From 2cd93e6b585d64b37b51992b754ad321f756fab7 Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Thu, 18 Jan 2024 13:02:24 -0700 Subject: [PATCH] LibWeb: Pump the task queue when spinning until a goal condition This prevents goal conditions that rely on tasks that are currently in flight on the task queue (or were just submitted) from blocking the event loop until an IPC event fires to kick the native event loop. --- .../LibWeb/HTML/EventLoop/EventLoop.cpp | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp index cfe60dfc01..dcb5ff2736 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp @@ -5,6 +5,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -53,29 +54,38 @@ EventLoop& main_thread_event_loop() // https://html.spec.whatwg.org/multipage/webappapis.html#spin-the-event-loop void EventLoop::spin_until(JS::SafeFunction goal_condition) { - // FIXME: 1. Let task be the event loop's currently running task. - - // FIXME: 2. Let task source be task's source. + // FIXME: The spec wants us to do the rest of the enclosing algorithm (i.e. the caller) + // in the context of the currently running task on entry. That's not possible with this implementation. + // 1. Let task be the event loop's currently running task. + // 2. Let task source be task's source. // 3. Let old stack be a copy of the JavaScript execution context stack. // 4. Empty the JavaScript execution context stack. - auto& vm = Bindings::main_thread_vm(); - vm.save_execution_context_stack(); + m_vm->save_execution_context_stack(); + m_vm->clear_execution_context_stack(); // 5. Perform a microtask checkpoint. perform_a_microtask_checkpoint(); // 6. In parallel: - // NOTE: We do these in reverse order here, but it shouldn't matter. - + // 1. Wait until the condition goal is met. // 2. Queue a task on task source to: // 1. Replace the JavaScript execution context stack with old stack. - vm.restore_execution_context_stack(); // 2. Perform any steps that appear after this spin the event loop instance in the original algorithm. // NOTE: This is achieved by returning from the function. - // 1. Wait until the condition goal is met. - Platform::EventLoopPlugin::the().spin_until(move(goal_condition)); + Platform::EventLoopPlugin::the().spin_until([&] { + if (goal_condition()) + return true; + if (m_task_queue.has_runnable_tasks()) { + schedule(); + // FIXME: Remove the platform event loop plugin so that this doesn't look out of place + Core::EventLoop::current().wake(); + } + return goal_condition(); + }); + + m_vm->restore_execution_context_stack(); // 7. Stop task, allowing whatever algorithm that invoked it to resume. // NOTE: This is achieved by returning from the function.