LibCore: Add a thread-safe weak link for EventLoop

Since the event loop has a very specifically scoped lifetime, we can't
ensure that it outlives threads that hold a reference to it without
blocking the thread that owns it. In order to make threads use the
event loop safely, we now have an atomically ref-counted
WeakEventLoopReference class that can be passed off to threads to
safely post events/callbacks to it.

Another possibility was to use an RWLock per event loop that each
thread holds a read lock on, while ~EventLoop() uses a write lock to
block and prevent it being destroyed until all its threads exit.
However, media data providers don't receive a signal to exit due to the
GC heap being intentionally leaked, so the process never actually
exits. It would be possible to specifically drop the reference to
PlaybackManager in HTMLMediaElement in order to make those data
providers die on their own, but that doesn't help prevent this problem
in other cases where it may arise.
This commit is contained in:
Zaggy1024
2025-12-05 13:48:48 -06:00
committed by Gregory Bertilson
parent 8289b24a7e
commit 2a5a9d2103
Notes: github-actions[bot] 2025-12-09 22:14:13 +00:00
3 changed files with 100 additions and 0 deletions

View File

@@ -8,6 +8,7 @@
#pragma once
#include <AK/AtomicRefCounted.h>
#include <AK/Forward.h>
#include <AK/Function.h>
#include <AK/Noncopyable.h>
@@ -16,11 +17,13 @@
#include <AK/Time.h>
#include <LibCore/Event.h>
#include <LibCore/Forward.h>
#include <LibThreading/RWLock.h>
namespace Core {
class EventLoopImplementation;
class ThreadEventQueue;
class WeakEventLoopReference;
// The event loop enables asynchronous (not parallel or multi-threaded) computing by efficiently handling events from various sources.
// Event loops are most important for GUI programs, where the various GUI updates and action callbacks run on the EventLoop,
@@ -89,13 +92,50 @@ public:
static bool is_running();
static EventLoop& current();
static NonnullRefPtr<WeakEventLoopReference> current_weak();
EventLoopImplementation& impl() { return *m_impl; }
private:
NonnullOwnPtr<EventLoopImplementation> m_impl;
RefPtr<WeakEventLoopReference> m_weak;
} SWIFT_UNSAFE_REFERENCE;
class StrongEventLoopReference;
class WeakEventLoopReference : public AtomicRefCounted<WeakEventLoopReference> {
public:
StrongEventLoopReference take();
private:
friend class EventLoop;
friend class StrongEventLoopReference;
WeakEventLoopReference(EventLoop&);
void revoke();
EventLoop* m_event_loop;
Threading::RWLock m_lock;
};
class StrongEventLoopReference {
public:
~StrongEventLoopReference();
bool is_alive() const;
operator bool() const;
EventLoop* operator*() const;
EventLoop* operator->() const;
private:
friend class WeakEventLoopReference;
StrongEventLoopReference(WeakEventLoopReference&);
WeakEventLoopReference* m_event_loop_weak;
};
void deferred_invoke(ESCAPING Function<void()>);
}