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.
This commit is contained in:
Andreas Kling 2021-09-09 00:38:43 +02:00
parent e0c7f8dafa
commit 909e522cf7
Notes: sideshowbarker 2024-07-18 04:24:27 +09:00
5 changed files with 35 additions and 2 deletions

View File

@ -65,6 +65,7 @@ class CanvasRenderingContext2D;
class CloseEvent;
class DOMParser;
struct EventHandler;
class EventLoop;
class HTMLAnchorElement;
class HTMLAreaElement;
class HTMLAudioElement;

View File

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibCore/Timer.h>
#include <LibJS/Runtime/VM.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/HTML/EventLoop/EventLoop.h>
@ -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();
}
}

View File

@ -7,6 +7,8 @@
#pragma once
#include <AK/Function.h>
#include <LibCore/Forward.h>
#include <LibJS/Forward.h>
#include <LibWeb/HTML/EventLoop/TaskQueue.h>
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<Core::Timer> m_system_event_loop_timer;
};
EventLoop& main_thread_event_loop();

View File

@ -4,11 +4,13 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/HTML/EventLoop/EventLoop.h>
#include <LibWeb/HTML/EventLoop/TaskQueue.h>
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> task)
{
m_tasks.enqueue(move(task));
m_event_loop.schedule();
}
}

View File

@ -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<HTML::Task> take_first_runnable() { return m_tasks.dequeue(); }
private:
HTML::EventLoop& m_event_loop;
Queue<NonnullOwnPtr<HTML::Task>> m_tasks;
};