pub(crate) struct StatelessWorkletThreadPool {
primary_sender: Sender<WorkletData>,
hot_backup_sender: Sender<WorkletData>,
cold_backup_sender: Sender<WorkletData>,
control_sender_0: Sender<WorkletControl>,
control_sender_1: Sender<WorkletControl>,
control_sender_2: Sender<WorkletControl>,
}Expand description
The StatelessWorkletThreadPool executes the associated
WorkletTasks in a dedicated thread pool with the assumption that
the tasks are idempotent. This is useful for the paint worklet, for
example.
The goal is to ensure that there is a primary worklet thread, which is able to responsively execute worklet code. In particular, worklet execution should not be delayed by GC, or by script loading.
To achieve this, we implement a three-thread pool, with the threads cycling between three thread roles:
-
The primary worklet thread is the one available to execute worklet code.
-
The hot backup thread may peform GC, but otherwise is expected to take over the primary role.
-
The cold backup thread may peform script loading and other long-running tasks.
In the implementation, we use two kinds of messages:
-
Data messages are expected to be processed quickly, and include the worklet tasks to be performed by the primary thread, as well as requests to change role or quit execution.
-
Control messages are expected to be processed more slowly, and include script loading.
Data messages are targeted at a role, for example, task execution is expected to be performed by whichever thread is currently primary. Control messages are targeted at a thread, for example adding a module is performed in every thread, even if they change roles in the middle of module loading.
The thread pool lives in the script thread, and is initialized when a worklet adds a module. It is dropped when the script thread is dropped, and asks each of the worklet threads to quit.
Layout can end up blocking on the primary worklet thread (e.g. when invoking a paint callback), so it is important to avoid deadlock by making sure the primary worklet thread doesn’t end up blocking waiting on layout. In particular, since the constellation can block waiting on layout, this means the primary worklet thread can’t block waiting on the constellation. In general, the primary worklet thread shouldn’t perform any blocking operations. If a worklet thread needs to do anything blocking, it should send a control message, to make sure that the blocking operation is performed by a backup thread, not by the primary thread.
Fields§
§primary_sender: Sender<WorkletData>§hot_backup_sender: Sender<WorkletData>§cold_backup_sender: Sender<WorkletData>§control_sender_0: Sender<WorkletControl>§control_sender_1: Sender<WorkletControl>§control_sender_2: Sender<WorkletControl>Implementations§
Source§impl StatelessWorkletThreadPool
impl StatelessWorkletThreadPool
Sourcepub(crate) fn spawn(
global_init: WorkletGlobalScopeInit,
) -> StatelessWorkletThreadPool
pub(crate) fn spawn( global_init: WorkletGlobalScopeInit, ) -> StatelessWorkletThreadPool
Create a new thread pool and spawn the threads. When the thread pool is dropped, the threads will be asked to quit.
Trait Implementations§
Source§impl Clone for StatelessWorkletThreadPool
impl Clone for StatelessWorkletThreadPool
Source§fn clone(&self) -> StatelessWorkletThreadPool
fn clone(&self) -> StatelessWorkletThreadPool
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Drop for StatelessWorkletThreadPool
impl Drop for StatelessWorkletThreadPool
Source§impl WorkletThreadPool for StatelessWorkletThreadPool
impl WorkletThreadPool for StatelessWorkletThreadPool
Source§fn perform_a_worklet_task(
&self,
worklet_id: WorkletId,
worklet_task: Box<dyn FnOnce(&mut JSContext, &WorkletGlobalScope) + Send>,
)
fn perform_a_worklet_task( &self, worklet_id: WorkletId, worklet_task: Box<dyn FnOnce(&mut JSContext, &WorkletGlobalScope) + Send>, )
Queue the WorkletTask for execution on the primary thread.
Source§fn fetch_and_invoke_a_worklet_script(
&self,
pipeline_id: PipelineId,
worklet_id: WorkletId,
global_type: WorkletGlobalScopeType,
origin: ImmutableOrigin,
base_url: ServoUrl,
script_url: ServoUrl,
policy_container: PolicyContainer,
credentials: RequestCredentials,
pending_tasks_struct: PendingTasksStruct,
promise: &Rc<Promise>,
inherited_secure_context: Option<bool>,
)
fn fetch_and_invoke_a_worklet_script( &self, pipeline_id: PipelineId, worklet_id: WorkletId, global_type: WorkletGlobalScopeType, origin: ImmutableOrigin, base_url: ServoUrl, script_url: ServoUrl, policy_container: PolicyContainer, credentials: RequestCredentials, pending_tasks_struct: PendingTasksStruct, promise: &Rc<Promise>, inherited_secure_context: Option<bool>, )
Source§fn exit_worklet(&self, worklet_id: WorkletId)
fn exit_worklet(&self, worklet_id: WorkletId)
WorkletGlobalScope associated with the WorkletId
be removed from all the threads in the thread pool.Source§fn wake_threads(&self)
fn wake_threads(&self)
Auto Trait Implementations§
impl Freeze for StatelessWorkletThreadPool
impl RefUnwindSafe for StatelessWorkletThreadPool
impl Send for StatelessWorkletThreadPool
impl Sync for StatelessWorkletThreadPool
impl Unpin for StatelessWorkletThreadPool
impl UnsafeUnpin for StatelessWorkletThreadPool
impl UnwindSafe for StatelessWorkletThreadPool
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more