ladybird/Libraries/LibWeb/HTML/EventLoop/TaskQueue.h
Jelle Raaijmakers a5000d07c0 LibWeb: Prevent running permanently unrunnable tasks in EventLoop
In `::spin_processing_tasks_with_source_until()`, we would first take a
set of tasks based on a filter, and then run them one by one. If there
was more than one task matched and put in that vector, they could
interfere with each other's runnability by making later tasks
permanently unrunnable.

The `::take_tasks_matching()` API is a footgun - remove it in favor of
an API that takes tasks one by one, performing the runnability check
just in time.
2026-03-26 18:48:27 +01:00

52 lines
1.2 KiB
C++

/*
* Copyright (c) 2021-2024, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Vector.h>
#include <LibJS/Heap/Cell.h>
#include <LibWeb/HTML/EventLoop/Task.h>
namespace Web::HTML {
class TaskQueue : public JS::Cell {
GC_CELL(TaskQueue, JS::Cell);
GC_DECLARE_ALLOCATOR(TaskQueue);
public:
explicit TaskQueue(HTML::EventLoop&);
virtual ~TaskQueue() override;
bool is_empty() const { return m_tasks.is_empty(); }
bool has_runnable_tasks() const;
bool has_rendering_tasks() const;
void add(GC::Ref<HTML::Task>);
GC::Ptr<HTML::Task> take_first_runnable();
void enqueue(GC::Ref<HTML::Task> task) { add(task); }
GC::Ptr<HTML::Task> dequeue()
{
if (m_tasks.is_empty())
return {};
return m_tasks.take_first();
}
void remove_tasks_matching(Function<bool(HTML::Task const&)>);
GC::Ptr<Task> take_first_runnable_matching(Function<bool(HTML::Task const&)>);
Task const* last_added_task() const;
private:
virtual void visit_edges(Visitor&) override;
GC::Ref<HTML::EventLoop> m_event_loop;
Vector<GC::Ref<HTML::Task>> m_tasks;
};
}