From 909e522cf70a1950a841d56df24a2d5ee1efb507 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 9 Sep 2021 00:38:43 +0200 Subject: [PATCH] LibWeb: Schedule HTML::EventLoop processing when there are queued tasks Since we can't simply give HTML::EventLoop control of the whole program, we have to integrate with Core::EventLoop. We do this by having a single-shot 0ms Core::Timer that we start when a task is added to the queue, and restart after processing the queue and there are still tasks in the queue. --- Userland/Libraries/LibWeb/Forward.h | 1 + .../LibWeb/HTML/EventLoop/EventLoop.cpp | 21 +++++++++++++++++++ .../LibWeb/HTML/EventLoop/EventLoop.h | 6 ++++++ .../LibWeb/HTML/EventLoop/TaskQueue.cpp | 5 ++++- .../LibWeb/HTML/EventLoop/TaskQueue.h | 4 +++- 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 6dda41271f..488bb38ab4 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -65,6 +65,7 @@ class CanvasRenderingContext2D; class CloseEvent; class DOMParser; struct EventHandler; +class EventLoop; class HTMLAnchorElement; class HTMLAreaElement; class HTMLAudioElement; diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp index ed74909e97..a0cd1234fe 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -11,6 +12,7 @@ namespace Web::HTML { EventLoop::EventLoop() + : m_task_queue(*this) { } @@ -18,6 +20,18 @@ EventLoop::~EventLoop() { } +void EventLoop::schedule() +{ + if (!m_system_event_loop_timer) { + m_system_event_loop_timer = Core::Timer::create_single_shot(0, [this] { + process(); + }); + } + + if (!m_system_event_loop_timer->is_active()) + m_system_event_loop_timer->restart(); +} + void EventLoop::set_vm(JS::VM& vm) { VERIFY(!m_vm); @@ -66,6 +80,9 @@ void EventLoop::process() // 2. Let oldestTask be the first runnable task in taskQueue, and remove it from taskQueue. auto oldest_task = task_queue.take_first_runnable(); + // FIXME: Figure out if we need to be here when there's no task. + VERIFY(oldest_task); + // 3. Set the event loop's currently running task to oldestTask. m_currently_running_task = oldest_task.ptr(); @@ -145,6 +162,10 @@ void EventLoop::process() // FIXME: 3. Update the rendering of that dedicated worker to reflect the current state. // FIXME: 2. If there are no tasks in the event loop's task queues and the WorkerGlobalScope object's closing flag is true, then destroy the event loop, aborting these steps, resuming the run a worker steps described in the Web workers section below. + + // If there are tasks in the queue, schedule a new round of processing. :^) + if (!m_task_queue.is_empty()) + schedule(); } } diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h index 26ee3ebdd7..ab5d01074c 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h @@ -7,6 +7,8 @@ #pragma once #include +#include +#include #include namespace Web::HTML { @@ -40,6 +42,8 @@ public: void set_vm(JS::VM&); + void schedule(); + private: Type m_type { Type::Window }; @@ -49,6 +53,8 @@ private: Task* m_currently_running_task { nullptr }; JS::VM* m_vm { nullptr }; + + RefPtr m_system_event_loop_timer; }; EventLoop& main_thread_event_loop(); diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.cpp b/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.cpp index e076a97431..50c8598d67 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.cpp +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.cpp @@ -4,11 +4,13 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include namespace Web::HTML { -TaskQueue::TaskQueue() +TaskQueue::TaskQueue(HTML::EventLoop& event_loop) + : m_event_loop(event_loop) { } @@ -19,6 +21,7 @@ TaskQueue::~TaskQueue() void TaskQueue::add(NonnullOwnPtr task) { m_tasks.enqueue(move(task)); + m_event_loop.schedule(); } } diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.h b/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.h index 0bc8e11eb5..49a8e1c061 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.h +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.h @@ -13,7 +13,7 @@ namespace Web::HTML { class TaskQueue { public: - TaskQueue(); + explicit TaskQueue(HTML::EventLoop&); ~TaskQueue(); bool is_empty() const { return m_tasks.is_empty(); } @@ -22,6 +22,8 @@ public: OwnPtr take_first_runnable() { return m_tasks.dequeue(); } private: + HTML::EventLoop& m_event_loop; + Queue> m_tasks; };