2023-04-23 17:45:12 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <AK/Vector.h>
|
|
|
|
#include <LibCore/DeferredInvocationContext.h>
|
2023-04-25 15:38:48 +00:00
|
|
|
#include <LibCore/EventLoopImplementation.h>
|
2023-08-06 16:09:39 +00:00
|
|
|
#include <LibCore/EventReceiver.h>
|
2023-04-23 17:45:12 +00:00
|
|
|
#include <LibCore/Promise.h>
|
|
|
|
#include <LibCore/ThreadEventQueue.h>
|
|
|
|
#include <LibThreading/Mutex.h>
|
2023-05-11 19:58:40 +00:00
|
|
|
#include <errno.h>
|
2023-04-23 17:45:12 +00:00
|
|
|
|
|
|
|
namespace Core {
|
|
|
|
|
|
|
|
struct ThreadEventQueue::Private {
|
|
|
|
struct QueuedEvent {
|
|
|
|
AK_MAKE_NONCOPYABLE(QueuedEvent);
|
2023-06-16 14:15:15 +00:00
|
|
|
AK_MAKE_DEFAULT_MOVABLE(QueuedEvent);
|
2023-04-23 17:45:12 +00:00
|
|
|
|
|
|
|
public:
|
2023-08-06 16:09:39 +00:00
|
|
|
QueuedEvent(EventReceiver& receiver, NonnullOwnPtr<Event> event)
|
2023-04-23 17:45:12 +00:00
|
|
|
: receiver(receiver)
|
|
|
|
, event(move(event))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
~QueuedEvent() = default;
|
|
|
|
|
2023-08-06 16:09:39 +00:00
|
|
|
WeakPtr<EventReceiver> receiver;
|
2023-04-23 17:45:12 +00:00
|
|
|
NonnullOwnPtr<Event> event;
|
|
|
|
};
|
|
|
|
|
|
|
|
Threading::Mutex mutex;
|
|
|
|
Vector<QueuedEvent, 128> queued_events;
|
2023-08-06 16:09:39 +00:00
|
|
|
Vector<NonnullRefPtr<Promise<NonnullRefPtr<EventReceiver>>>, 16> pending_promises;
|
2023-04-23 17:45:12 +00:00
|
|
|
bool warned_promise_count { false };
|
|
|
|
};
|
|
|
|
|
|
|
|
static thread_local ThreadEventQueue* s_current_thread_event_queue;
|
|
|
|
|
|
|
|
ThreadEventQueue& ThreadEventQueue::current()
|
|
|
|
{
|
|
|
|
if (!s_current_thread_event_queue) {
|
|
|
|
// FIXME: Don't leak these.
|
|
|
|
s_current_thread_event_queue = new ThreadEventQueue;
|
|
|
|
}
|
|
|
|
return *s_current_thread_event_queue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ThreadEventQueue::ThreadEventQueue()
|
|
|
|
: m_private(make<Private>())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ThreadEventQueue::~ThreadEventQueue() = default;
|
|
|
|
|
2023-08-06 16:09:39 +00:00
|
|
|
void ThreadEventQueue::post_event(Core::EventReceiver& receiver, NonnullOwnPtr<Core::Event> event)
|
2023-04-23 17:45:12 +00:00
|
|
|
{
|
2023-04-25 14:53:07 +00:00
|
|
|
{
|
|
|
|
Threading::MutexLocker lock(m_private->mutex);
|
|
|
|
m_private->queued_events.empend(receiver, move(event));
|
|
|
|
}
|
2023-04-25 15:38:48 +00:00
|
|
|
Core::EventLoopManager::the().did_post_event();
|
2023-04-23 17:45:12 +00:00
|
|
|
}
|
|
|
|
|
2023-08-06 16:09:39 +00:00
|
|
|
void ThreadEventQueue::add_job(NonnullRefPtr<Promise<NonnullRefPtr<EventReceiver>>> promise)
|
2023-04-23 17:45:12 +00:00
|
|
|
{
|
|
|
|
Threading::MutexLocker lock(m_private->mutex);
|
|
|
|
m_private->pending_promises.append(move(promise));
|
|
|
|
}
|
|
|
|
|
2023-05-11 19:58:40 +00:00
|
|
|
void ThreadEventQueue::cancel_all_pending_jobs()
|
|
|
|
{
|
|
|
|
Threading::MutexLocker lock(m_private->mutex);
|
|
|
|
for (auto const& promise : m_private->pending_promises)
|
2023-07-07 22:00:27 +00:00
|
|
|
promise->reject(Error::from_errno(ECANCELED));
|
2023-05-11 19:58:40 +00:00
|
|
|
|
|
|
|
m_private->pending_promises.clear();
|
|
|
|
}
|
|
|
|
|
2023-04-23 17:45:12 +00:00
|
|
|
size_t ThreadEventQueue::process()
|
|
|
|
{
|
|
|
|
decltype(m_private->queued_events) events;
|
|
|
|
{
|
|
|
|
Threading::MutexLocker locker(m_private->mutex);
|
|
|
|
events = move(m_private->queued_events);
|
2023-07-07 22:00:27 +00:00
|
|
|
m_private->pending_promises.remove_all_matching([](auto& job) { return job->is_resolved() || job->is_rejected(); });
|
2023-04-23 17:45:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t processed_events = 0;
|
|
|
|
for (size_t i = 0; i < events.size(); ++i) {
|
|
|
|
auto& queued_event = events.at(i);
|
|
|
|
auto receiver = queued_event.receiver.strong_ref();
|
|
|
|
auto& event = *queued_event.event;
|
|
|
|
|
|
|
|
if (!receiver) {
|
|
|
|
switch (event.type()) {
|
|
|
|
case Event::Quit:
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
default:
|
2023-04-24 10:25:14 +00:00
|
|
|
// Receiver disappeared, drop the event on the floor.
|
2023-04-23 17:45:12 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (event.type() == Event::Type::DeferredInvoke) {
|
|
|
|
static_cast<DeferredInvocationEvent&>(event).m_invokee();
|
|
|
|
} else {
|
2023-08-06 16:09:39 +00:00
|
|
|
NonnullRefPtr<EventReceiver> protector(*receiver);
|
2023-04-23 17:45:12 +00:00
|
|
|
receiver->dispatch_event(event);
|
|
|
|
}
|
|
|
|
++processed_events;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
Threading::MutexLocker locker(m_private->mutex);
|
|
|
|
if (m_private->pending_promises.size() > 30 && !m_private->warned_promise_count) {
|
|
|
|
m_private->warned_promise_count = true;
|
|
|
|
dbgln("ThreadEventQueue::process: Job queue wasn't designed for this load ({} promises)", m_private->pending_promises.size());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return processed_events;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ThreadEventQueue::has_pending_events() const
|
|
|
|
{
|
|
|
|
Threading::MutexLocker locker(m_private->mutex);
|
|
|
|
return !m_private->queued_events.is_empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|