mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
96 lines
2.9 KiB
C++
96 lines
2.9 KiB
C++
/*
|
|
* Copyright (c) 2026, The Ladybird developers
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/Atomic.h>
|
|
#include <AK/Function.h>
|
|
#include <AK/Time.h>
|
|
#include <LibCore/EventLoop.h>
|
|
#include <LibCore/Socket.h>
|
|
#include <LibCore/System.h>
|
|
#include <LibIPC/TransportSocket.h>
|
|
#include <LibTest/TestCase.h>
|
|
|
|
using namespace AK::TimeLiterals;
|
|
|
|
static void spin_until(Core::EventLoop& loop, Function<bool()> condition, AK::Duration timeout = 2000_ms)
|
|
{
|
|
i64 const timeout_ms = timeout.to_milliseconds();
|
|
for (i64 elapsed_ms = 0; elapsed_ms < timeout_ms; elapsed_ms += 5) {
|
|
(void)loop.pump(Core::EventLoop::WaitMode::PollForEvents);
|
|
if (condition())
|
|
return;
|
|
MUST(Core::System::sleep_ms(5));
|
|
}
|
|
|
|
FAIL("Timed out waiting for condition");
|
|
}
|
|
|
|
TEST_CASE(read_hook_is_notified_on_peer_hangup)
|
|
{
|
|
Core::EventLoop loop;
|
|
|
|
int fds[2] = {};
|
|
MUST(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, fds));
|
|
|
|
auto reader_socket = TRY_OR_FAIL(Core::LocalSocket::adopt_fd(fds[0]));
|
|
auto peer_socket = TRY_OR_FAIL(Core::LocalSocket::adopt_fd(fds[1]));
|
|
|
|
MUST(reader_socket->set_blocking(false));
|
|
MUST(peer_socket->set_blocking(false));
|
|
|
|
IPC::TransportSocket transport(move(reader_socket));
|
|
|
|
IGNORE_USE_IN_ESCAPING_LAMBDA Atomic<bool> observed_shutdown = false;
|
|
|
|
transport.set_up_read_hook([&] {
|
|
auto should_shutdown = transport.read_as_many_messages_as_possible_without_blocking([](auto&&) {
|
|
});
|
|
if (should_shutdown == IPC::TransportSocket::ShouldShutdown::Yes)
|
|
observed_shutdown.store(true, AK::MemoryOrder::memory_order_relaxed);
|
|
});
|
|
|
|
peer_socket->close();
|
|
|
|
spin_until(loop, [&] {
|
|
return observed_shutdown.load(AK::MemoryOrder::memory_order_relaxed);
|
|
});
|
|
|
|
EXPECT(observed_shutdown.load(AK::MemoryOrder::memory_order_relaxed));
|
|
}
|
|
|
|
TEST_CASE(read_hook_is_notified_when_io_thread_exits_on_close)
|
|
{
|
|
Core::EventLoop loop;
|
|
|
|
int fds[2] = {};
|
|
MUST(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, fds));
|
|
|
|
auto reader_socket = TRY_OR_FAIL(Core::LocalSocket::adopt_fd(fds[0]));
|
|
auto peer_socket = TRY_OR_FAIL(Core::LocalSocket::adopt_fd(fds[1]));
|
|
|
|
MUST(reader_socket->set_blocking(false));
|
|
MUST(peer_socket->set_blocking(false));
|
|
|
|
IPC::TransportSocket transport(move(reader_socket));
|
|
|
|
IGNORE_USE_IN_ESCAPING_LAMBDA Atomic<bool> observed_shutdown = false;
|
|
|
|
transport.set_up_read_hook([&] {
|
|
auto should_shutdown = transport.read_as_many_messages_as_possible_without_blocking([](auto&&) {
|
|
});
|
|
if (should_shutdown == IPC::TransportSocket::ShouldShutdown::Yes)
|
|
observed_shutdown.store(true, AK::MemoryOrder::memory_order_relaxed);
|
|
});
|
|
|
|
transport.close();
|
|
|
|
spin_until(loop, [&] {
|
|
return observed_shutdown.load(AK::MemoryOrder::memory_order_relaxed);
|
|
});
|
|
|
|
EXPECT(observed_shutdown.load(AK::MemoryOrder::memory_order_relaxed));
|
|
}
|