mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-08 01:00:05 +00:00
LibIPC: Wait until socket is writable when transferring IPC messages
This commit is contained in:
parent
41e37f0079
commit
21897c8ed0
Notes:
github-actions[bot]
2024-09-18 08:07:44 +00:00
Author: https://github.com/tcl3
Commit: 21897c8ed0
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1416
Reviewed-by: https://github.com/awesomekling
1 changed files with 14 additions and 13 deletions
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <AK/Checked.h>
|
#include <AK/Checked.h>
|
||||||
#include <LibCore/Socket.h>
|
#include <LibCore/Socket.h>
|
||||||
|
#include <LibCore/System.h>
|
||||||
#include <LibIPC/Message.h>
|
#include <LibIPC/Message.h>
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
|
|
||||||
|
@ -58,7 +59,6 @@ ErrorOr<void> MessageBuffer::transfer_message(Core::LocalSocket& socket)
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadonlyBytes bytes_to_write { m_data.span() };
|
ReadonlyBytes bytes_to_write { m_data.span() };
|
||||||
size_t writes_done = 0;
|
|
||||||
|
|
||||||
while (!bytes_to_write.is_empty()) {
|
while (!bytes_to_write.is_empty()) {
|
||||||
ErrorOr<ssize_t> maybe_nwritten = 0;
|
ErrorOr<ssize_t> maybe_nwritten = 0;
|
||||||
|
@ -69,22 +69,27 @@ ErrorOr<void> MessageBuffer::transfer_message(Core::LocalSocket& socket)
|
||||||
} else {
|
} else {
|
||||||
maybe_nwritten = socket.write_some(bytes_to_write);
|
maybe_nwritten = socket.write_some(bytes_to_write);
|
||||||
}
|
}
|
||||||
++writes_done;
|
|
||||||
|
|
||||||
if (maybe_nwritten.is_error()) {
|
if (maybe_nwritten.is_error()) {
|
||||||
if (auto error = maybe_nwritten.release_error(); error.is_errno()) {
|
if (auto error = maybe_nwritten.release_error(); error.is_errno() && (error.code() == EAGAIN || error.code() == EWOULDBLOCK)) {
|
||||||
// FIXME: This is a hacky way to at least not crash on large messages
|
Vector<struct pollfd, 1> pollfds;
|
||||||
// The limit of 100 writes is arbitrary, and there to prevent indefinite spinning on the EventLoop
|
if (pollfds.is_empty())
|
||||||
if (error.code() == EAGAIN && writes_done < 100) {
|
pollfds.append({ .fd = socket.fd().value(), .events = POLLOUT, .revents = 0 });
|
||||||
sched_yield();
|
|
||||||
|
ErrorOr<int> result { 0 };
|
||||||
|
do {
|
||||||
|
constexpr u32 POLL_TIMEOUT_MS = 100;
|
||||||
|
result = Core::System::poll(pollfds, POLL_TIMEOUT_MS);
|
||||||
|
} while (result.is_error() && result.error().code() == EINTR);
|
||||||
|
|
||||||
|
if (!result.is_error() && result.value() != 0)
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
switch (error.code()) {
|
switch (error.code()) {
|
||||||
case EPIPE:
|
case EPIPE:
|
||||||
return Error::from_string_literal("IPC::transfer_message: Disconnected from peer");
|
return Error::from_string_literal("IPC::transfer_message: Disconnected from peer");
|
||||||
case EAGAIN:
|
case EAGAIN:
|
||||||
return Error::from_string_literal("IPC::transfer_message: Peer buffer overflowed");
|
return Error::from_string_literal("IPC::transfer_message: Timed out waiting for socket to become writable");
|
||||||
default:
|
default:
|
||||||
return Error::from_syscall("IPC::transfer_message write"sv, -error.code());
|
return Error::from_syscall("IPC::transfer_message write"sv, -error.code());
|
||||||
}
|
}
|
||||||
|
@ -96,10 +101,6 @@ ErrorOr<void> MessageBuffer::transfer_message(Core::LocalSocket& socket)
|
||||||
bytes_to_write = bytes_to_write.slice(maybe_nwritten.value());
|
bytes_to_write = bytes_to_write.slice(maybe_nwritten.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (writes_done > 1) {
|
|
||||||
dbgln("LibIPC::transfer_message FIXME Warning, needed {} writes needed to send message of size {}B, this is pretty bad, as it spins on the EventLoop", writes_done, m_data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue