mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-05-01 03:57:15 +02:00
LibCore: Add thread-safe weak deferred_invoke()
Add a thread-safe deferred_invoke() API on WeakEventLoopReference that queues work onto the owning thread's event queue and wakes that thread via EventLoopManager hooks. This avoids calling wake() from foreign threads during teardown. Implement current_thread_handle()/wake_thread() in each backend and track per-thread data so handles are validated before waking: - Unix: wake via per-thread wake pipe - Windows: wake via thread wake event - macOS: wake via stored CFRunLoopRef - Qt: wake via event target or QEventLoop::wakeUp() - Android: wake via stored ALooper
This commit is contained in:
committed by
Andreas Kling
parent
367296fce6
commit
96ce468b60
Notes:
github-actions[bot]
2026-02-06 11:08:22 +00:00
Author: https://github.com/awesomekling Commit: https://github.com/LadybirdBrowser/ladybird/commit/96ce468b601 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/7582
@@ -10,6 +10,7 @@
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/Diagnostics.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/HashTable.h>
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <AK/Windows.h>
|
||||
#include <LibCore/EventLoopImplementationWindows.h>
|
||||
@@ -17,6 +18,7 @@
|
||||
#include <LibCore/ThreadEventQueue.h>
|
||||
#include <LibCore/Timer.h>
|
||||
#include <LibThreading/Mutex.h>
|
||||
#include <LibThreading/RWLock.h>
|
||||
|
||||
struct OwnHandle {
|
||||
HANDLE handle = NULL;
|
||||
@@ -62,6 +64,10 @@ constexpr bool IsHashCompatible<HANDLE, OwnHandle> = true;
|
||||
|
||||
namespace Core {
|
||||
|
||||
struct ThreadData;
|
||||
static HashTable<ThreadData*> s_thread_data_by_ptr;
|
||||
static Threading::RWLock s_thread_data_lock;
|
||||
|
||||
enum class CompletionType : u8 {
|
||||
Wake,
|
||||
Timer,
|
||||
@@ -110,9 +116,23 @@ struct ThreadData {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static ThreadData* for_handle(EventLoopThreadHandle handle)
|
||||
{
|
||||
if (handle == 0)
|
||||
return nullptr;
|
||||
auto* ptr = reinterpret_cast<ThreadData*>(handle);
|
||||
Threading::RWLockLocker<Threading::LockMode::Read> locker(s_thread_data_lock);
|
||||
if (!s_thread_data_by_ptr.contains(ptr))
|
||||
return nullptr;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
ThreadData()
|
||||
: wake_data(make<EventLoopWake>())
|
||||
{
|
||||
Threading::RWLockLocker<Threading::LockMode::Write> locker(s_thread_data_lock);
|
||||
s_thread_data_by_ptr.set(this);
|
||||
|
||||
wake_data->type = CompletionType::Wake;
|
||||
wake_data->wait_event.handle = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
@@ -129,6 +149,8 @@ struct ThreadData {
|
||||
{
|
||||
NTSTATUS status = g_system.NtCancelWaitCompletionPacket(wake_data->wait_packet.handle, TRUE);
|
||||
VERIFY(NT_SUCCESS(status));
|
||||
Threading::RWLockLocker<Threading::LockMode::Write> locker(s_thread_data_lock);
|
||||
s_thread_data_by_ptr.remove(this);
|
||||
}
|
||||
|
||||
OwnHandle iocp;
|
||||
@@ -355,6 +377,20 @@ void EventLoopManagerWindows::did_post_event()
|
||||
{
|
||||
}
|
||||
|
||||
EventLoopThreadHandle EventLoopManagerWindows::current_thread_handle()
|
||||
{
|
||||
auto* thread_data = ThreadData::the();
|
||||
return reinterpret_cast<EventLoopThreadHandle>(thread_data);
|
||||
}
|
||||
|
||||
void EventLoopManagerWindows::wake_thread(EventLoopThreadHandle handle)
|
||||
{
|
||||
auto* thread_data = ThreadData::for_handle(handle);
|
||||
if (!thread_data)
|
||||
return;
|
||||
SetEvent(thread_data->wake_data->wait_event.handle);
|
||||
}
|
||||
|
||||
NonnullOwnPtr<EventLoopImplementation> EventLoopManagerWindows::make_implementation()
|
||||
{
|
||||
return make<EventLoopImplementationWindows>();
|
||||
|
||||
Reference in New Issue
Block a user