script: Use enums for event loop senders and receivers (#34896)

Previously, senders and receivers to different kinds of event loops (the
main `ScriptThread`, different types of workers) used a rust `trait`
mechanism to implement dynamic behavior. This led to having many unused
implementations of this `trait`. This change moves to using an `enum`
based approach for these senders and receivers and removes all of the
dead code.

In addition, to allowing for use of rust's dead code detection, it
simplifies the code a great deal. All of these generic senders and
receivers are moved to the `messaging.rs` file and given proper
documentation.

Finally, empty an `JSTraceable` implementation is made for all
crossbeam `Sender<...>`s to avoid having to manually skip them everytime
they are included in structs. The pre-existing empty `MallocSizeOf`
implementation is used more thoroughly.

Other unecessary wrappers around these senders and receivers are removed
as well.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2025-01-08 22:33:29 +01:00 committed by GitHub
parent 82ac8d41d0
commit 77bc7f415d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 217 additions and 325 deletions

View file

@ -7,7 +7,7 @@ use servo_url::ImmutableOrigin;
use crate::dom::bindings::refcounted::Trusted; use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::reflector::DomObject;
use crate::script_runtime::CommonScriptMsg; use crate::messaging::CommonScriptMsg;
/// Messages used to control the worker event loops /// Messages used to control the worker event loops
pub enum WorkerScriptMsg { pub enum WorkerScriptMsg {

View file

@ -2,88 +2,19 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crossbeam_channel::{select, Receiver, Sender}; use crossbeam_channel::{select, Receiver};
use devtools_traits::DevtoolScriptControlMsg; use devtools_traits::DevtoolScriptControlMsg;
use crate::dom::abstractworker::WorkerScriptMsg;
use crate::dom::bindings::conversions::DerivedFrom; use crate::dom::bindings::conversions::DerivedFrom;
use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::reflector::DomObject;
use crate::dom::dedicatedworkerglobalscope::{AutoWorkerReset, DedicatedWorkerScriptMsg}; use crate::dom::dedicatedworkerglobalscope::AutoWorkerReset;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::worker::TrustedWorkerAddress; use crate::dom::worker::TrustedWorkerAddress;
use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::realms::enter_realm; use crate::realms::enter_realm;
use crate::script_runtime::{CanGc, CommonScriptMsg, ScriptChan, ScriptPort}; use crate::script_runtime::CanGc;
use crate::task_queue::{QueuedTaskConversion, TaskQueue}; use crate::task_queue::{QueuedTaskConversion, TaskQueue};
/// A ScriptChan that can be cloned freely and will silently send a TrustedWorkerAddress with
/// common event loop messages. While this SendableWorkerScriptChan is alive, the associated
/// Worker object will remain alive.
#[derive(Clone, JSTraceable)]
pub struct SendableWorkerScriptChan {
#[no_trace]
pub sender: Sender<DedicatedWorkerScriptMsg>,
pub worker: TrustedWorkerAddress,
}
impl ScriptChan for SendableWorkerScriptChan {
fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
let msg = DedicatedWorkerScriptMsg::CommonWorker(
self.worker.clone(),
WorkerScriptMsg::Common(msg),
);
self.sender.send(msg).map_err(|_| ())
}
fn as_boxed(&self) -> Box<dyn ScriptChan> {
Box::new(SendableWorkerScriptChan {
sender: self.sender.clone(),
worker: self.worker.clone(),
})
}
}
/// A ScriptChan that can be cloned freely and will silently send a TrustedWorkerAddress with
/// worker event loop messages. While this SendableWorkerScriptChan is alive, the associated
/// Worker object will remain alive.
#[derive(Clone, JSTraceable)]
pub struct WorkerThreadWorkerChan {
#[no_trace]
pub sender: Sender<DedicatedWorkerScriptMsg>,
pub worker: TrustedWorkerAddress,
}
impl ScriptChan for WorkerThreadWorkerChan {
fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
let msg = DedicatedWorkerScriptMsg::CommonWorker(
self.worker.clone(),
WorkerScriptMsg::Common(msg),
);
self.sender.send(msg).map_err(|_| ())
}
fn as_boxed(&self) -> Box<dyn ScriptChan> {
Box::new(WorkerThreadWorkerChan {
sender: self.sender.clone(),
worker: self.worker.clone(),
})
}
}
impl ScriptPort for Receiver<DedicatedWorkerScriptMsg> {
fn recv(&self) -> Result<CommonScriptMsg, ()> {
let common_msg = match self.recv() {
Ok(DedicatedWorkerScriptMsg::CommonWorker(_worker, common_msg)) => common_msg,
Err(_) => return Err(()),
Ok(DedicatedWorkerScriptMsg::WakeUp) => panic!("unexpected worker event message!"),
};
match common_msg {
WorkerScriptMsg::Common(script_msg) => Ok(script_msg),
WorkerScriptMsg::DOMMessage { .. } => panic!("unexpected worker event message!"),
}
}
}
pub trait WorkerEventLoopMethods { pub trait WorkerEventLoopMethods {
type WorkerMsg: QueuedTaskConversion + Send; type WorkerMsg: QueuedTaskConversion + Send;
type ControlMsg; type ControlMsg;

View file

@ -53,7 +53,10 @@ mod dummy {
pub use self::dummy::LIVE_REFERENCES; pub use self::dummy::LIVE_REFERENCES;
/// A pointer to a Rust DOM object that needs to be destroyed. /// A pointer to a Rust DOM object that needs to be destroyed.
struct TrustedReference(*const libc::c_void); #[derive(MallocSizeOf)]
struct TrustedReference(
#[ignore_malloc_size_of = "This is a shared reference."] *const libc::c_void,
);
unsafe impl Send for TrustedReference {} unsafe impl Send for TrustedReference {}
impl TrustedReference { impl TrustedReference {
@ -158,10 +161,13 @@ impl TrustedPromise {
/// DOM object is guaranteed to live at least as long as the last outstanding /// DOM object is guaranteed to live at least as long as the last outstanding
/// `Trusted<T>` instance. /// `Trusted<T>` instance.
#[crown::unrooted_must_root_lint::allow_unrooted_interior] #[crown::unrooted_must_root_lint::allow_unrooted_interior]
#[derive(MallocSizeOf)]
pub struct Trusted<T: DomObject> { pub struct Trusted<T: DomObject> {
/// A pointer to the Rust DOM object of type T, but void to allow /// A pointer to the Rust DOM object of type T, but void to allow
/// sending `Trusted<T>` between threads, regardless of T's sendability. /// sending `Trusted<T>` between threads, regardless of T's sendability.
#[conditional_malloc_size_of]
refcount: Arc<TrustedReference>, refcount: Arc<TrustedReference>,
#[ignore_malloc_size_of = "These are shared by all `Trusted` types."]
owner_thread: *const LiveDOMReferences, owner_thread: *const LiveDOMReferences,
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }

View file

@ -37,6 +37,7 @@ use std::hash::{BuildHasher, Hash};
use std::mem; use std::mem;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use crossbeam_channel::Sender;
use indexmap::IndexMap; use indexmap::IndexMap;
/// A trait to allow tracing (only) DOM objects. /// A trait to allow tracing (only) DOM objects.
pub use js::gc::Traceable as JSTraceable; pub use js::gc::Traceable as JSTraceable;
@ -107,6 +108,10 @@ unsafe impl<T: JSTraceable> CustomTraceable for OnceCell<T> {
} }
} }
unsafe impl<T> CustomTraceable for Sender<T> {
unsafe fn trace(&self, _: *mut JSTracer) {}
}
/// Wrapper type for nop traceble /// Wrapper type for nop traceble
/// ///
/// SAFETY: Inner type must not impl JSTraceable /// SAFETY: Inner type must not impl JSTraceable

View file

@ -27,9 +27,7 @@ use style::thread_state::{self, ThreadState};
use crate::devtools; use crate::devtools;
use crate::dom::abstractworker::{SimpleWorkerErrorHandler, WorkerScriptMsg}; use crate::dom::abstractworker::{SimpleWorkerErrorHandler, WorkerScriptMsg};
use crate::dom::abstractworkerglobalscope::{ use crate::dom::abstractworkerglobalscope::{run_worker_event_loop, WorkerEventLoopMethods};
run_worker_event_loop, SendableWorkerScriptChan, WorkerEventLoopMethods, WorkerThreadWorkerChan,
};
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding; use crate::dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding;
use crate::dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding::DedicatedWorkerGlobalScopeMethods; use crate::dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding::DedicatedWorkerGlobalScopeMethods;
@ -41,7 +39,7 @@ use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::{DomRoot, RootCollection, ThreadLocalStackRoots}; use crate::dom::bindings::root::{DomRoot, RootCollection, ThreadLocalStackRoots};
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::structuredclone; use crate::dom::bindings::structuredclone;
use crate::dom::bindings::trace::RootedTraceableBox; use crate::dom::bindings::trace::{CustomTraceable, RootedTraceableBox};
use crate::dom::errorevent::ErrorEvent; use crate::dom::errorevent::ErrorEvent;
use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus}; use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus};
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
@ -52,12 +50,10 @@ use crate::dom::webgpu::identityhub::IdentityHub;
use crate::dom::worker::{TrustedWorkerAddress, Worker}; use crate::dom::worker::{TrustedWorkerAddress, Worker};
use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::fetch::load_whole_resource; use crate::fetch::load_whole_resource;
use crate::messaging::{CommonScriptMsg, ScriptEventLoopReceiver, ScriptEventLoopSender};
use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::realms::{enter_realm, AlreadyInRealm, InRealm};
use crate::script_runtime::ScriptThreadEventCategory::WorkerEvent; use crate::script_runtime::ScriptThreadEventCategory::WorkerEvent;
use crate::script_runtime::{ use crate::script_runtime::{CanGc, JSContext as SafeJSContext, Runtime, ThreadSafeJSContext};
CanGc, CommonScriptMsg, JSContext as SafeJSContext, Runtime, ScriptChan, ScriptPort,
ThreadSafeJSContext,
};
use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue}; use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
use crate::task_source::{SendableTaskSource, TaskSourceName}; use crate::task_source::{SendableTaskSource, TaskSourceName};
@ -182,14 +178,12 @@ pub struct DedicatedWorkerGlobalScope {
workerglobalscope: WorkerGlobalScope, workerglobalscope: WorkerGlobalScope,
#[ignore_malloc_size_of = "Defined in std"] #[ignore_malloc_size_of = "Defined in std"]
task_queue: TaskQueue<DedicatedWorkerScriptMsg>, task_queue: TaskQueue<DedicatedWorkerScriptMsg>,
#[ignore_malloc_size_of = "Defined in std"]
#[no_trace]
own_sender: Sender<DedicatedWorkerScriptMsg>, own_sender: Sender<DedicatedWorkerScriptMsg>,
#[ignore_malloc_size_of = "Trusted<T> has unclear ownership like Dom<T>"] #[ignore_malloc_size_of = "Trusted<T> has unclear ownership like Dom<T>"]
worker: DomRefCell<Option<TrustedWorkerAddress>>, worker: DomRefCell<Option<TrustedWorkerAddress>>,
#[ignore_malloc_size_of = "Can't measure trait objects"] #[ignore_malloc_size_of = "Can't measure trait objects"]
/// Sender to the parent thread. /// Sender to the parent thread.
parent_sender: Box<dyn ScriptChan>, parent_event_loop_sender: ScriptEventLoopSender,
#[ignore_malloc_size_of = "Arc"] #[ignore_malloc_size_of = "Arc"]
#[no_trace] #[no_trace]
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
@ -250,7 +244,7 @@ impl DedicatedWorkerGlobalScope {
worker_url: ServoUrl, worker_url: ServoUrl,
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
runtime: Runtime, runtime: Runtime,
parent_sender: Box<dyn ScriptChan + Send>, parent_event_loop_sender: ScriptEventLoopSender,
own_sender: Sender<DedicatedWorkerScriptMsg>, own_sender: Sender<DedicatedWorkerScriptMsg>,
receiver: Receiver<DedicatedWorkerScriptMsg>, receiver: Receiver<DedicatedWorkerScriptMsg>,
closing: Arc<AtomicBool>, closing: Arc<AtomicBool>,
@ -273,7 +267,7 @@ impl DedicatedWorkerGlobalScope {
), ),
task_queue: TaskQueue::new(receiver, own_sender.clone()), task_queue: TaskQueue::new(receiver, own_sender.clone()),
own_sender, own_sender,
parent_sender, parent_event_loop_sender,
worker: DomRefCell::new(None), worker: DomRefCell::new(None),
image_cache, image_cache,
browsing_context, browsing_context,
@ -282,14 +276,14 @@ impl DedicatedWorkerGlobalScope {
} }
#[allow(unsafe_code, clippy::too_many_arguments)] #[allow(unsafe_code, clippy::too_many_arguments)]
pub fn new( pub(crate) fn new(
init: WorkerGlobalScopeInit, init: WorkerGlobalScopeInit,
worker_name: DOMString, worker_name: DOMString,
worker_type: WorkerType, worker_type: WorkerType,
worker_url: ServoUrl, worker_url: ServoUrl,
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
runtime: Runtime, runtime: Runtime,
parent_sender: Box<dyn ScriptChan + Send>, parent_event_loop_sender: ScriptEventLoopSender,
own_sender: Sender<DedicatedWorkerScriptMsg>, own_sender: Sender<DedicatedWorkerScriptMsg>,
receiver: Receiver<DedicatedWorkerScriptMsg>, receiver: Receiver<DedicatedWorkerScriptMsg>,
closing: Arc<AtomicBool>, closing: Arc<AtomicBool>,
@ -306,7 +300,7 @@ impl DedicatedWorkerGlobalScope {
worker_url, worker_url,
from_devtools_receiver, from_devtools_receiver,
runtime, runtime,
parent_sender, parent_event_loop_sender,
own_sender, own_sender,
receiver, receiver,
closing, closing,
@ -321,12 +315,12 @@ impl DedicatedWorkerGlobalScope {
/// <https://html.spec.whatwg.org/multipage/#run-a-worker> /// <https://html.spec.whatwg.org/multipage/#run-a-worker>
#[allow(unsafe_code, clippy::too_many_arguments)] #[allow(unsafe_code, clippy::too_many_arguments)]
pub fn run_worker_scope( pub(crate) fn run_worker_scope(
mut init: WorkerGlobalScopeInit, mut init: WorkerGlobalScopeInit,
worker_url: ServoUrl, worker_url: ServoUrl,
from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>, from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>,
worker: TrustedWorkerAddress, worker: TrustedWorkerAddress,
parent_sender: Box<dyn ScriptChan + Send>, parent_event_loop_sender: ScriptEventLoopSender,
own_sender: Sender<DedicatedWorkerScriptMsg>, own_sender: Sender<DedicatedWorkerScriptMsg>,
receiver: Receiver<DedicatedWorkerScriptMsg>, receiver: Receiver<DedicatedWorkerScriptMsg>,
worker_load_origin: WorkerScriptLoadOrigin, worker_load_origin: WorkerScriptLoadOrigin,
@ -379,10 +373,10 @@ impl DedicatedWorkerGlobalScope {
let runtime = unsafe { let runtime = unsafe {
let task_source = SendableTaskSource { let task_source = SendableTaskSource {
sender: Box::new(WorkerThreadWorkerChan { sender: ScriptEventLoopSender::DedicatedWorker {
sender: own_sender.clone(), sender: own_sender.clone(),
worker: worker.clone(), main_thread_worker: worker.clone(),
}), },
pipeline_id, pipeline_id,
name: TaskSourceName::Networking, name: TaskSourceName::Networking,
canceller: Default::default(), canceller: Default::default(),
@ -417,7 +411,7 @@ impl DedicatedWorkerGlobalScope {
worker_url, worker_url,
devtools_mpsc_port, devtools_mpsc_port,
runtime, runtime,
parent_sender.as_boxed(), parent_event_loop_sender.clone(),
own_sender, own_sender,
receiver, receiver,
closing, closing,
@ -442,7 +436,7 @@ impl DedicatedWorkerGlobalScope {
) { ) {
Err(_) => { Err(_) => {
println!("error loading script {}", serialized_worker_url); println!("error loading script {}", serialized_worker_url);
parent_sender parent_event_loop_sender
.send(CommonScriptMsg::Task( .send(CommonScriptMsg::Task(
WorkerEvent, WorkerEvent,
Box::new(SimpleWorkerErrorHandler::new(worker)), Box::new(SimpleWorkerErrorHandler::new(worker)),
@ -491,7 +485,7 @@ impl DedicatedWorkerGlobalScope {
} }
}, },
reporter_name, reporter_name,
parent_sender, parent_event_loop_sender,
CommonScriptMsg::CollectReports, CommonScriptMsg::CollectReports,
); );
@ -526,21 +520,23 @@ impl DedicatedWorkerGlobalScope {
self.image_cache.clone() self.image_cache.clone()
} }
pub(crate) fn event_loop_sender(&self) -> Option<Box<dyn ScriptChan + Send>> { pub(crate) fn event_loop_sender(&self) -> Option<ScriptEventLoopSender> {
let worker = self.worker.borrow().clone()?; Some(ScriptEventLoopSender::DedicatedWorker {
Some(Box::new(WorkerThreadWorkerChan {
sender: self.own_sender.clone(), sender: self.own_sender.clone(),
worker, main_thread_worker: self.worker.borrow().clone()?,
})) })
} }
pub fn new_script_pair(&self) -> (Box<dyn ScriptChan + Send>, Box<dyn ScriptPort + Send>) { pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
let (tx, rx) = unbounded(); let (sender, receiver) = unbounded();
let chan = Box::new(SendableWorkerScriptChan { let main_thread_worker = self.worker.borrow().as_ref().unwrap().clone();
sender: tx, (
worker: self.worker.borrow().as_ref().unwrap().clone(), ScriptEventLoopSender::DedicatedWorker {
}); sender,
(chan, Box::new(rx)) main_thread_worker,
},
ScriptEventLoopReceiver::DedicatedWorker(receiver),
)
} }
fn handle_script_event(&self, msg: WorkerScriptMsg, can_gc: CanGc) { fn handle_script_event(&self, msg: WorkerScriptMsg, can_gc: CanGc) {
@ -626,7 +622,7 @@ impl DedicatedWorkerGlobalScope {
global.report_an_error(error_info, HandleValue::null(), CanGc::note()); global.report_an_error(error_info, HandleValue::null(), CanGc::note());
} }
})); }));
self.parent_sender self.parent_event_loop_sender
.send(CommonScriptMsg::Task( .send(CommonScriptMsg::Task(
WorkerEvent, WorkerEvent,
task, task,
@ -650,7 +646,7 @@ impl DedicatedWorkerGlobalScope {
let task = Box::new(task!(post_worker_message: move || { let task = Box::new(task!(post_worker_message: move || {
Worker::handle_message(worker, data, CanGc::note()); Worker::handle_message(worker, data, CanGc::note());
})); }));
self.parent_sender self.parent_event_loop_sender
.send(CommonScriptMsg::Task( .send(CommonScriptMsg::Task(
WorkerEvent, WorkerEvent,
task, task,

View file

@ -184,10 +184,10 @@ use crate::dom::windowproxy::WindowProxy;
use crate::dom::xpathevaluator::XPathEvaluator; use crate::dom::xpathevaluator::XPathEvaluator;
use crate::fetch::FetchCanceller; use crate::fetch::FetchCanceller;
use crate::iframe_collection::IFrameCollection; use crate::iframe_collection::IFrameCollection;
use crate::messaging::MainThreadScriptMsg; use crate::messaging::{CommonScriptMsg, MainThreadScriptMsg};
use crate::network_listener::{NetworkListener, PreInvoke}; use crate::network_listener::{NetworkListener, PreInvoke};
use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::realms::{enter_realm, AlreadyInRealm, InRealm};
use crate::script_runtime::{CanGc, CommonScriptMsg, ScriptThreadEventCategory}; use crate::script_runtime::{CanGc, ScriptThreadEventCategory};
use crate::script_thread::{with_script_thread, ScriptThread}; use crate::script_thread::{with_script_thread, ScriptThread};
use crate::stylesheet_set::StylesheetSetRef; use crate::stylesheet_set::StylesheetSetRef;
use crate::task::TaskBox; use crate::task::TaskBox;

View file

@ -128,13 +128,12 @@ use crate::dom::webgpu::identityhub::IdentityHub;
use crate::dom::window::Window; use crate::dom::window::Window;
use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::dom::workletglobalscope::WorkletGlobalScope; use crate::dom::workletglobalscope::WorkletGlobalScope;
use crate::messaging::{CommonScriptMsg, ScriptEventLoopReceiver, ScriptEventLoopSender};
use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask}; use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask};
use crate::network_listener::{NetworkListener, PreInvoke}; use crate::network_listener::{NetworkListener, PreInvoke};
use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::realms::{enter_realm, AlreadyInRealm, InRealm};
use crate::script_module::{DynamicModuleList, ModuleScript, ModuleTree, ScriptFetchOptions}; use crate::script_module::{DynamicModuleList, ModuleScript, ModuleTree, ScriptFetchOptions};
use crate::script_runtime::{ use crate::script_runtime::{CanGc, JSContext as SafeJSContext, ThreadSafeJSContext};
CanGc, CommonScriptMsg, JSContext as SafeJSContext, ScriptChan, ScriptPort, ThreadSafeJSContext,
};
use crate::script_thread::{with_script_thread, ScriptThread}; use crate::script_thread::{with_script_thread, ScriptThread};
use crate::security_manager::CSPViolationReporter; use crate::security_manager::CSPViolationReporter;
use crate::task_manager::TaskManager; use crate::task_manager::TaskManager;
@ -2480,7 +2479,7 @@ impl GlobalScope {
/// A sender to the event loop of this global scope. This either sends to the Worker event loop /// A sender to the event loop of this global scope. This either sends to the Worker event loop
/// or the ScriptThread event loop in the case of a `Window`. This can be `None` for dedicated /// or the ScriptThread event loop in the case of a `Window`. This can be `None` for dedicated
/// workers that are not currently handling a message. /// workers that are not currently handling a message.
pub(crate) fn event_loop_sender(&self) -> Option<Box<dyn ScriptChan + Send>> { pub(crate) fn event_loop_sender(&self) -> Option<ScriptEventLoopSender> {
if let Some(window) = self.downcast::<Window>() { if let Some(window) = self.downcast::<Window>() {
Some(window.event_loop_sender()) Some(window.event_loop_sender())
} else if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() { } else if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() {
@ -2825,7 +2824,7 @@ impl GlobalScope {
/// Create a new sender/receiver pair that can be used to implement an on-demand /// Create a new sender/receiver pair that can be used to implement an on-demand
/// event loop. Used for implementing web APIs that require blocking semantics /// event loop. Used for implementing web APIs that require blocking semantics
/// without resorting to nested event loops. /// without resorting to nested event loops.
pub fn new_script_pair(&self) -> (Box<dyn ScriptChan + Send>, Box<dyn ScriptPort + Send>) { pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
if let Some(window) = self.downcast::<Window>() { if let Some(window) = self.downcast::<Window>() {
return window.new_script_pair(); return window.new_script_pair();
} }

View file

@ -33,6 +33,7 @@ use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::root::{DomRoot, RootCollection, ThreadLocalStackRoots}; use crate::dom::bindings::root::{DomRoot, RootCollection, ThreadLocalStackRoots};
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::structuredclone; use crate::dom::bindings::structuredclone;
use crate::dom::bindings::trace::CustomTraceable;
use crate::dom::dedicatedworkerglobalscope::AutoWorkerReset; use crate::dom::dedicatedworkerglobalscope::AutoWorkerReset;
use crate::dom::event::Event; use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
@ -44,10 +45,9 @@ use crate::dom::webgpu::identityhub::IdentityHub;
use crate::dom::worker::TrustedWorkerAddress; use crate::dom::worker::TrustedWorkerAddress;
use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::fetch::load_whole_resource; use crate::fetch::load_whole_resource;
use crate::messaging::{CommonScriptMsg, ScriptEventLoopSender};
use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::realms::{enter_realm, AlreadyInRealm, InRealm};
use crate::script_runtime::{ use crate::script_runtime::{CanGc, JSContext as SafeJSContext, Runtime, ThreadSafeJSContext};
CanGc, CommonScriptMsg, JSContext as SafeJSContext, Runtime, ScriptChan, ThreadSafeJSContext,
};
use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue}; use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
use crate::task_source::TaskSourceName; use crate::task_source::TaskSourceName;
@ -128,28 +128,6 @@ pub enum MixedMessage {
Timer, Timer,
} }
#[derive(Clone, JSTraceable)]
pub struct ServiceWorkerChan {
#[no_trace]
pub sender: Sender<ServiceWorkerScriptMsg>,
}
impl ScriptChan for ServiceWorkerChan {
fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
self.sender
.send(ServiceWorkerScriptMsg::CommonWorker(
WorkerScriptMsg::Common(msg),
))
.map_err(|_| ())
}
fn as_boxed(&self) -> Box<dyn ScriptChan> {
Box::new(ServiceWorkerChan {
sender: self.sender.clone(),
})
}
}
#[dom_struct] #[dom_struct]
pub struct ServiceWorkerGlobalScope { pub struct ServiceWorkerGlobalScope {
workerglobalscope: WorkerGlobalScope, workerglobalscope: WorkerGlobalScope,
@ -158,8 +136,6 @@ pub struct ServiceWorkerGlobalScope {
#[no_trace] #[no_trace]
task_queue: TaskQueue<ServiceWorkerScriptMsg>, task_queue: TaskQueue<ServiceWorkerScriptMsg>,
#[ignore_malloc_size_of = "Defined in std"]
#[no_trace]
own_sender: Sender<ServiceWorkerScriptMsg>, own_sender: Sender<ServiceWorkerScriptMsg>,
/// A port on which a single "time-out" message can be received, /// A port on which a single "time-out" message can be received,
@ -485,10 +461,8 @@ impl ServiceWorkerGlobalScope {
} }
} }
pub(crate) fn event_loop_sender(&self) -> Box<dyn ScriptChan + Send> { pub(crate) fn event_loop_sender(&self) -> ScriptEventLoopSender {
Box::new(ServiceWorkerChan { ScriptEventLoopSender::ServiceWorker(self.own_sender.clone())
sender: self.own_sender.clone(),
})
} }
fn dispatch_activate(&self, can_gc: CanGc) { fn dispatch_activate(&self, can_gc: CanGc) {

View file

@ -112,7 +112,7 @@ use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::bindings::structuredclone; use crate::dom::bindings::structuredclone;
use crate::dom::bindings::trace::{JSTraceable, RootedTraceableBox}; use crate::dom::bindings::trace::{CustomTraceable, JSTraceable, RootedTraceableBox};
use crate::dom::bindings::utils::GlobalStaticData; use crate::dom::bindings::utils::GlobalStaticData;
use crate::dom::bindings::weakref::DOMTracker; use crate::dom::bindings::weakref::DOMTracker;
use crate::dom::bluetooth::BluetoothExtraPermissionData; use crate::dom::bluetooth::BluetoothExtraPermissionData;
@ -149,11 +149,11 @@ use crate::dom::worklet::Worklet;
use crate::dom::workletglobalscope::WorkletGlobalScopeType; use crate::dom::workletglobalscope::WorkletGlobalScopeType;
use crate::layout_image::fetch_image_for_layout; use crate::layout_image::fetch_image_for_layout;
use crate::messaging::{ use crate::messaging::{
ImageCacheMsg, MainThreadScriptChan, MainThreadScriptMsg, SendableMainThreadScriptChan, ImageCacheMsg, MainThreadScriptMsg, ScriptEventLoopReceiver, ScriptEventLoopSender,
}; };
use crate::microtask::MicrotaskQueue; use crate::microtask::MicrotaskQueue;
use crate::realms::{enter_realm, InRealm}; use crate::realms::{enter_realm, InRealm};
use crate::script_runtime::{CanGc, JSContext, Runtime, ScriptChan, ScriptPort}; use crate::script_runtime::{CanGc, JSContext, Runtime};
use crate::script_thread::ScriptThread; use crate::script_thread::ScriptThread;
use crate::timers::{IsInterval, TimerCallback}; use crate::timers::{IsInterval, TimerCallback};
use crate::unminify::unminified_path; use crate::unminify::unminified_path;
@ -202,8 +202,7 @@ impl LayoutBlocker {
#[dom_struct] #[dom_struct]
pub struct Window { pub struct Window {
globalscope: GlobalScope, globalscope: GlobalScope,
#[ignore_malloc_size_of = "trait objects are hard"] script_chan: Sender<MainThreadScriptMsg>,
script_chan: MainThreadScriptChan,
#[no_trace] #[no_trace]
#[ignore_malloc_size_of = "TODO: Add MallocSizeOf support to layout"] #[ignore_malloc_size_of = "TODO: Add MallocSizeOf support to layout"]
layout: RefCell<Box<dyn Layout>>, layout: RefCell<Box<dyn Layout>>,
@ -216,7 +215,6 @@ pub struct Window {
#[ignore_malloc_size_of = "Arc"] #[ignore_malloc_size_of = "Arc"]
#[no_trace] #[no_trace]
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
#[ignore_malloc_size_of = "channels are hard"]
#[no_trace] #[no_trace]
image_cache_chan: Sender<ImageCacheMsg>, image_cache_chan: Sender<ImageCacheMsg>,
window_proxy: MutNullableDom<WindowProxy>, window_proxy: MutNullableDom<WindowProxy>,
@ -452,16 +450,23 @@ impl Window {
} }
pub(crate) fn main_thread_script_chan(&self) -> &Sender<MainThreadScriptMsg> { pub(crate) fn main_thread_script_chan(&self) -> &Sender<MainThreadScriptMsg> {
&self.script_chan.0 &self.script_chan
} }
pub fn parent_info(&self) -> Option<PipelineId> { pub fn parent_info(&self) -> Option<PipelineId> {
self.parent_info self.parent_info
} }
pub fn new_script_pair(&self) -> (Box<dyn ScriptChan + Send>, Box<dyn ScriptPort + Send>) { pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
let (tx, rx) = unbounded(); let (sender, receiver) = unbounded();
(Box::new(SendableMainThreadScriptChan(tx)), Box::new(rx)) (
ScriptEventLoopSender::MainThread(sender),
ScriptEventLoopReceiver::MainThread(receiver),
)
}
pub(crate) fn event_loop_sender(&self) -> ScriptEventLoopSender {
ScriptEventLoopSender::MainThread(self.script_chan.clone())
} }
pub fn image_cache(&self) -> Arc<dyn ImageCache> { pub fn image_cache(&self) -> Arc<dyn ImageCache> {
@ -2677,7 +2682,7 @@ impl Window {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub(crate) fn new( pub(crate) fn new(
runtime: Rc<Runtime>, runtime: Rc<Runtime>,
script_chan: MainThreadScriptChan, script_chan: Sender<MainThreadScriptMsg>,
layout: Box<dyn Layout>, layout: Box<dyn Layout>,
font_context: Arc<FontContext>, font_context: Arc<FontContext>,
image_cache_chan: Sender<ImageCacheMsg>, image_cache_chan: Sender<ImageCacheMsg>,
@ -2803,10 +2808,6 @@ impl Window {
unsafe { WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), win) } unsafe { WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), win) }
} }
pub(crate) fn event_loop_sender(&self) -> Box<dyn ScriptChan + Send> {
Box::new(self.script_chan.clone())
}
pub(crate) fn pipeline_id(&self) -> PipelineId { pub(crate) fn pipeline_id(&self) -> PipelineId {
self.as_global_scope().pipeline_id() self.as_global_scope().pipeline_id()
} }

View file

@ -28,7 +28,7 @@ use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomObject};
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::bindings::structuredclone; use crate::dom::bindings::structuredclone;
use crate::dom::bindings::trace::RootedTraceableBox; use crate::dom::bindings::trace::{CustomTraceable, RootedTraceableBox};
use crate::dom::dedicatedworkerglobalscope::{ use crate::dom::dedicatedworkerglobalscope::{
DedicatedWorkerGlobalScope, DedicatedWorkerScriptMsg, DedicatedWorkerGlobalScope, DedicatedWorkerScriptMsg,
}; };
@ -47,8 +47,6 @@ pub type TrustedWorkerAddress = Trusted<Worker>;
#[dom_struct] #[dom_struct]
pub struct Worker { pub struct Worker {
eventtarget: EventTarget, eventtarget: EventTarget,
#[ignore_malloc_size_of = "Defined in std"]
#[no_trace]
/// Sender to the Receiver associated with the DedicatedWorkerGlobalScope /// Sender to the Receiver associated with the DedicatedWorkerGlobalScope
/// this Worker created. /// this Worker created.
sender: Sender<DedicatedWorkerScriptMsg>, sender: Sender<DedicatedWorkerScriptMsg>,

View file

@ -56,8 +56,9 @@ use crate::dom::window::{base64_atob, base64_btoa};
use crate::dom::workerlocation::WorkerLocation; use crate::dom::workerlocation::WorkerLocation;
use crate::dom::workernavigator::WorkerNavigator; use crate::dom::workernavigator::WorkerNavigator;
use crate::fetch; use crate::fetch;
use crate::messaging::{CommonScriptMsg, ScriptEventLoopReceiver, ScriptEventLoopSender};
use crate::realms::{enter_realm, InRealm}; use crate::realms::{enter_realm, InRealm};
use crate::script_runtime::{CanGc, CommonScriptMsg, JSContext, Runtime, ScriptChan, ScriptPort}; use crate::script_runtime::{CanGc, JSContext, Runtime};
use crate::task::TaskCanceller; use crate::task::TaskCanceller;
use crate::timers::{IsInterval, TimerCallback}; use crate::timers::{IsInterval, TimerCallback};
@ -491,7 +492,7 @@ impl WorkerGlobalScope {
} }
} }
pub fn new_script_pair(&self) -> (Box<dyn ScriptChan + Send>, Box<dyn ScriptPort + Send>) { pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
let dedicated = self.downcast::<DedicatedWorkerGlobalScope>(); let dedicated = self.downcast::<DedicatedWorkerGlobalScope>();
if let Some(dedicated) = dedicated { if let Some(dedicated) = dedicated {
dedicated.new_script_pair() dedicated.new_script_pair()

View file

@ -49,9 +49,9 @@ use crate::dom::workletglobalscope::{
WorkletGlobalScope, WorkletGlobalScopeInit, WorkletGlobalScopeType, WorkletTask, WorkletGlobalScope, WorkletGlobalScopeInit, WorkletGlobalScopeType, WorkletTask,
}; };
use crate::fetch::load_whole_resource; use crate::fetch::load_whole_resource;
use crate::messaging::MainThreadScriptMsg; use crate::messaging::{CommonScriptMsg, MainThreadScriptMsg};
use crate::realms::InRealm; use crate::realms::InRealm;
use crate::script_runtime::{CanGc, CommonScriptMsg, Runtime, ScriptThreadEventCategory}; use crate::script_runtime::{CanGc, Runtime, ScriptThreadEventCategory};
use crate::script_thread::ScriptThread; use crate::script_thread::ScriptThread;
use crate::task::TaskBox; use crate::task::TaskBox;
use crate::task_source::TaskSourceName; use crate::task_source::TaskSourceName;
@ -768,7 +768,6 @@ impl WorkletThread {
#[derive(Clone, JSTraceable, MallocSizeOf)] #[derive(Clone, JSTraceable, MallocSizeOf)]
pub struct WorkletExecutor { pub struct WorkletExecutor {
worklet_id: WorkletId, worklet_id: WorkletId,
#[ignore_malloc_size_of = "channels are hard"]
#[no_trace] #[no_trace]
primary_sender: Sender<WorkletData>, primary_sender: Sender<WorkletData>,
} }

View file

@ -21,6 +21,7 @@ use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::trace::CustomTraceable;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::paintworkletglobalscope::{PaintWorkletGlobalScope, PaintWorkletTask}; use crate::dom::paintworkletglobalscope::{PaintWorkletGlobalScope, PaintWorkletTask};
use crate::dom::testworkletglobalscope::{TestWorkletGlobalScope, TestWorkletTask}; use crate::dom::testworkletglobalscope::{TestWorkletGlobalScope, TestWorkletTask};
@ -40,8 +41,6 @@ pub struct WorkletGlobalScope {
#[no_trace] #[no_trace]
base_url: ServoUrl, base_url: ServoUrl,
/// Sender back to the script thread /// Sender back to the script thread
#[ignore_malloc_size_of = "channels are hard"]
#[no_trace]
to_script_thread_sender: Sender<MainThreadScriptMsg>, to_script_thread_sender: Sender<MainThreadScriptMsg>,
/// Worklet task executor /// Worklet task executor
executor: WorkletExecutor, executor: WorkletExecutor,

View file

@ -2,17 +2,18 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use core::fmt;
use std::cell::RefCell; use std::cell::RefCell;
use std::option::Option; use std::option::Option;
use std::result::Result; use std::result::Result;
use base::id::PipelineId; use base::id::PipelineId;
use bluetooth_traits::BluetoothRequest; use bluetooth_traits::BluetoothRequest;
use crossbeam_channel::{select, Receiver, Sender}; use crossbeam_channel::{select, Receiver, SendError, Sender};
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg}; use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg};
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use net_traits::image_cache::PendingImageResponse; use net_traits::image_cache::PendingImageResponse;
use profile_traits::mem::{self as profile_mem, OpaqueSender}; use profile_traits::mem::{self as profile_mem, OpaqueSender, ReportsChan};
use profile_traits::time::{self as profile_time}; use profile_traits::time::{self as profile_time};
use script_traits::{ConstellationControlMsg, LayoutMsg, Painter, ScriptMsg}; use script_traits::{ConstellationControlMsg, LayoutMsg, Painter, ScriptMsg};
use servo_atoms::Atom; use servo_atoms::Atom;
@ -20,9 +21,13 @@ use timers::TimerScheduler;
#[cfg(feature = "webgpu")] #[cfg(feature = "webgpu")]
use webgpu::WebGPUMsg; use webgpu::WebGPUMsg;
use crate::dom::serviceworker::TrustedServiceWorkerAddress; use crate::dom::abstractworker::WorkerScriptMsg;
use crate::dom::bindings::trace::CustomTraceable;
use crate::dom::dedicatedworkerglobalscope::DedicatedWorkerScriptMsg;
use crate::dom::serviceworkerglobalscope::ServiceWorkerScriptMsg;
use crate::dom::worker::TrustedWorkerAddress; use crate::dom::worker::TrustedWorkerAddress;
use crate::script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort}; use crate::script_runtime::ScriptThreadEventCategory;
use crate::task::TaskBox;
use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue}; use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
use crate::task_source::TaskSourceName; use crate::task_source::TaskSourceName;
@ -124,6 +129,106 @@ pub(crate) enum MainThreadScriptMsg {
WakeUp, WakeUp,
} }
/// Common messages used to control the event loops in both the script and the worker
pub enum CommonScriptMsg {
/// Requests that the script thread measure its memory usage. The results are sent back via the
/// supplied channel.
CollectReports(ReportsChan),
/// Generic message that encapsulates event handling.
Task(
ScriptThreadEventCategory,
Box<dyn TaskBox>,
Option<PipelineId>,
TaskSourceName,
),
}
impl fmt::Debug for CommonScriptMsg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
CommonScriptMsg::CollectReports(_) => write!(f, "CollectReports(...)"),
CommonScriptMsg::Task(ref category, ref task, _, _) => {
f.debug_tuple("Task").field(category).field(task).finish()
},
}
}
}
/// A wrapper around various types of `Sender`s that send messages back to the event loop
/// of a script context event loop. This will either target the main `ScriptThread` event
/// loop or that of a worker.
#[derive(Clone, JSTraceable, MallocSizeOf)]
pub(crate) enum ScriptEventLoopSender {
/// A sender that sends to the main `ScriptThread` event loop.
MainThread(Sender<MainThreadScriptMsg>),
/// A sender that sends to a `ServiceWorker` event loop.
ServiceWorker(Sender<ServiceWorkerScriptMsg>),
/// A sender that sends to a dedicated worker (such as a generic Web Worker) event loop.
/// Note that this sender keeps the main thread Worker DOM object alive as long as it or
/// or any message it sends is not dropped.
DedicatedWorker {
sender: Sender<DedicatedWorkerScriptMsg>,
main_thread_worker: TrustedWorkerAddress,
},
}
impl ScriptEventLoopSender {
/// Send a message to the event loop, which might be a main thread event loop or a worker event loop.
pub(crate) fn send(&self, message: CommonScriptMsg) -> Result<(), SendError<()>> {
match self {
Self::MainThread(sender) => sender
.send(MainThreadScriptMsg::Common(message))
.map_err(|_| SendError(())),
Self::ServiceWorker(sender) => sender
.send(ServiceWorkerScriptMsg::CommonWorker(
WorkerScriptMsg::Common(message),
))
.map_err(|_| SendError(())),
Self::DedicatedWorker {
sender,
main_thread_worker,
} => {
let common_message = WorkerScriptMsg::Common(message);
sender
.send(DedicatedWorkerScriptMsg::CommonWorker(
main_thread_worker.clone(),
common_message,
))
.map_err(|_| SendError(()))
},
}
}
}
/// A wrapper around various types of `Receiver`s that receive event loop messages. Used for
/// synchronous DOM APIs that need to abstract over multiple kinds of event loops (worker/main
/// thread) with different Receiver interfaces.
pub(crate) enum ScriptEventLoopReceiver {
/// A receiver that receives messages to the main `ScriptThread` event loop.
MainThread(Receiver<MainThreadScriptMsg>),
/// A receiver that receives messages to dedicated workers (such as a generic Web Worker) event loop.
DedicatedWorker(Receiver<DedicatedWorkerScriptMsg>),
}
impl ScriptEventLoopReceiver {
pub(crate) fn recv(&self) -> Result<CommonScriptMsg, ()> {
match self {
Self::MainThread(receiver) => match receiver.recv() {
Ok(MainThreadScriptMsg::Common(script_msg)) => Ok(script_msg),
Ok(_) => panic!("unexpected main thread event message!"),
Err(_) => Err(()),
},
Self::DedicatedWorker(receiver) => match receiver.recv() {
Ok(DedicatedWorkerScriptMsg::CommonWorker(_, WorkerScriptMsg::Common(message))) => {
Ok(message)
},
Ok(_) => panic!("unexpected worker event message!"),
Err(_) => Err(()),
},
}
}
}
impl QueuedTaskConversion for MainThreadScriptMsg { impl QueuedTaskConversion for MainThreadScriptMsg {
fn task_source_name(&self) -> Option<&TaskSourceName> { fn task_source_name(&self) -> Option<&TaskSourceName> {
let script_msg = match self { let script_msg = match self {
@ -182,83 +287,9 @@ impl QueuedTaskConversion for MainThreadScriptMsg {
} }
} }
impl OpaqueSender<CommonScriptMsg> for Box<dyn ScriptChan + Send> { impl OpaqueSender<CommonScriptMsg> for ScriptEventLoopSender {
fn send(&self, msg: CommonScriptMsg) { fn send(&self, message: CommonScriptMsg) {
ScriptChan::send(&**self, msg).unwrap(); self.send(message).unwrap()
}
}
impl ScriptPort for Receiver<CommonScriptMsg> {
fn recv(&self) -> Result<CommonScriptMsg, ()> {
self.recv().map_err(|_| ())
}
}
impl ScriptPort for Receiver<MainThreadScriptMsg> {
fn recv(&self) -> Result<CommonScriptMsg, ()> {
match self.recv() {
Ok(MainThreadScriptMsg::Common(script_msg)) => Ok(script_msg),
Ok(_) => panic!("unexpected main thread event message!"),
Err(_) => Err(()),
}
}
}
impl ScriptPort for Receiver<(TrustedWorkerAddress, CommonScriptMsg)> {
fn recv(&self) -> Result<CommonScriptMsg, ()> {
self.recv().map(|(_, msg)| msg).map_err(|_| ())
}
}
impl ScriptPort for Receiver<(TrustedWorkerAddress, MainThreadScriptMsg)> {
fn recv(&self) -> Result<CommonScriptMsg, ()> {
match self.recv().map(|(_, msg)| msg) {
Ok(MainThreadScriptMsg::Common(script_msg)) => Ok(script_msg),
Ok(_) => panic!("unexpected main thread event message!"),
Err(_) => Err(()),
}
}
}
impl ScriptPort for Receiver<(TrustedServiceWorkerAddress, CommonScriptMsg)> {
fn recv(&self) -> Result<CommonScriptMsg, ()> {
self.recv().map(|(_, msg)| msg).map_err(|_| ())
}
}
/// Encapsulates internal communication of shared messages within the script thread.
#[derive(Clone, JSTraceable)]
pub(crate) struct SendableMainThreadScriptChan(#[no_trace] pub Sender<CommonScriptMsg>);
impl ScriptChan for SendableMainThreadScriptChan {
fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
self.0.send(msg).map_err(|_| ())
}
fn as_boxed(&self) -> Box<dyn ScriptChan> {
Box::new(SendableMainThreadScriptChan((self.0).clone()))
}
}
/// Encapsulates internal communication of main thread messages within the script thread.
#[derive(Clone, JSTraceable)]
pub(crate) struct MainThreadScriptChan(#[no_trace] pub Sender<MainThreadScriptMsg>);
impl ScriptChan for MainThreadScriptChan {
fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
self.0
.send(MainThreadScriptMsg::Common(msg))
.map_err(|_| ())
}
fn as_boxed(&self) -> Box<dyn ScriptChan> {
Box::new(MainThreadScriptChan((self.0).clone()))
}
}
impl OpaqueSender<CommonScriptMsg> for Sender<MainThreadScriptMsg> {
fn send(&self, msg: CommonScriptMsg) {
self.send(MainThreadScriptMsg::Common(msg)).unwrap()
} }
} }
@ -266,7 +297,7 @@ impl OpaqueSender<CommonScriptMsg> for Sender<MainThreadScriptMsg> {
pub(crate) struct ScriptThreadSenders { pub(crate) struct ScriptThreadSenders {
/// A channel to hand out to script thread-based entities that need to be able to enqueue /// A channel to hand out to script thread-based entities that need to be able to enqueue
/// events in the event queue. /// events in the event queue.
pub self_sender: MainThreadScriptChan, pub self_sender: Sender<MainThreadScriptMsg>,
/// A handle to the bluetooth thread. /// A handle to the bluetooth thread.
#[no_trace] #[no_trace]

View file

@ -16,10 +16,9 @@ use std::os::raw::c_void;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Mutex; use std::sync::Mutex;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use std::{fmt, os, ptr, thread}; use std::{os, ptr, thread};
use background_hang_monitor_api::ScriptHangAnnotation; use background_hang_monitor_api::ScriptHangAnnotation;
use base::id::PipelineId;
use content_security_policy::{CheckResult, PolicyDisposition}; use content_security_policy::{CheckResult, PolicyDisposition};
use js::conversions::jsstr_to_string; use js::conversions::jsstr_to_string;
use js::glue::{ use js::glue::{
@ -50,7 +49,7 @@ use js::rust::{
}; };
use malloc_size_of::MallocSizeOfOps; use malloc_size_of::MallocSizeOfOps;
use malloc_size_of_derive::MallocSizeOf; use malloc_size_of_derive::MallocSizeOf;
use profile_traits::mem::{Report, ReportKind, ReportsChan}; use profile_traits::mem::{Report, ReportKind};
use profile_traits::path; use profile_traits::path;
use profile_traits::time::ProfilerCategory; use profile_traits::time::ProfilerCategory;
use servo_config::{opts, pref}; use servo_config::{opts, pref};
@ -70,7 +69,6 @@ use crate::dom::bindings::refcounted::{
}; };
use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::trace_roots; use crate::dom::bindings::root::trace_roots;
use crate::dom::bindings::trace::JSTraceable;
use crate::dom::bindings::utils::DOM_CALLBACKS; use crate::dom::bindings::utils::DOM_CALLBACKS;
use crate::dom::bindings::{principals, settings_stack}; use crate::dom::bindings::{principals, settings_stack};
use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus}; use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus};
@ -84,8 +82,7 @@ use crate::realms::{AlreadyInRealm, InRealm};
use crate::script_module::EnsureModuleHooksInitialized; use crate::script_module::EnsureModuleHooksInitialized;
use crate::script_thread::trace_thread; use crate::script_thread::trace_thread;
use crate::security_manager::CSPViolationReporter; use crate::security_manager::CSPViolationReporter;
use crate::task::TaskBox; use crate::task_source::SendableTaskSource;
use crate::task_source::{SendableTaskSource, TaskSourceName};
static JOB_QUEUE_TRAPS: JobQueueTraps = JobQueueTraps { static JOB_QUEUE_TRAPS: JobQueueTraps = JobQueueTraps {
getIncumbentGlobal: Some(get_incumbent_global), getIncumbentGlobal: Some(get_incumbent_global),
@ -98,40 +95,6 @@ static SECURITY_CALLBACKS: JSSecurityCallbacks = JSSecurityCallbacks {
subsumes: Some(principals::subsumes), subsumes: Some(principals::subsumes),
}; };
/// Common messages used to control the event loops in both the script and the worker
pub enum CommonScriptMsg {
/// Requests that the script thread measure its memory usage. The results are sent back via the
/// supplied channel.
CollectReports(ReportsChan),
/// Generic message that encapsulates event handling.
Task(
ScriptThreadEventCategory,
Box<dyn TaskBox>,
Option<PipelineId>,
TaskSourceName,
),
}
impl fmt::Debug for CommonScriptMsg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
CommonScriptMsg::CollectReports(_) => write!(f, "CollectReports(...)"),
CommonScriptMsg::Task(ref category, ref task, _, _) => {
f.debug_tuple("Task").field(category).field(task).finish()
},
}
}
}
/// A cloneable interface for communicating with an event loop.
pub trait ScriptChan: JSTraceable + Send {
/// Send a message to the associated event loop.
#[allow(clippy::result_unit_err)]
fn send(&self, msg: CommonScriptMsg) -> Result<(), ()>;
/// Return a cloned version of this sender in a [`Box`].
fn as_boxed(&self) -> Box<dyn ScriptChan>;
}
#[derive(Clone, Copy, Debug, Eq, Hash, JSTraceable, MallocSizeOf, PartialEq)] #[derive(Clone, Copy, Debug, Eq, Hash, JSTraceable, MallocSizeOf, PartialEq)]
pub enum ScriptThreadEventCategory { pub enum ScriptThreadEventCategory {
AttachLayout, AttachLayout,
@ -253,14 +216,6 @@ impl From<ScriptThreadEventCategory> for ScriptHangAnnotation {
} }
} }
/// An interface for receiving ScriptMsg values in an event loop. Used for synchronous DOM
/// APIs that need to abstract over multiple kinds of event loops (worker/main thread) with
/// different Receiver interfaces.
pub trait ScriptPort {
#[allow(clippy::result_unit_err)]
fn recv(&self) -> Result<CommonScriptMsg, ()>;
}
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe extern "C" fn get_incumbent_global(_: *const c_void, _: *mut RawJSContext) -> *mut JSObject { unsafe extern "C" fn get_incumbent_global(_: *const c_void, _: *mut RawJSContext) -> *mut JSObject {
let mut result = ptr::null_mut(); let mut result = ptr::null_mut();

View file

@ -142,15 +142,14 @@ use crate::dom::worklet::WorkletThreadPool;
use crate::dom::workletglobalscope::WorkletGlobalScopeInit; use crate::dom::workletglobalscope::WorkletGlobalScopeInit;
use crate::fetch::FetchCanceller; use crate::fetch::FetchCanceller;
use crate::messaging::{ use crate::messaging::{
MainThreadScriptChan, MainThreadScriptMsg, MixedMessage, ScriptThreadReceivers, CommonScriptMsg, MainThreadScriptMsg, MixedMessage, ScriptEventLoopSender,
ScriptThreadSenders, ScriptThreadReceivers, ScriptThreadSenders,
}; };
use crate::microtask::{Microtask, MicrotaskQueue}; use crate::microtask::{Microtask, MicrotaskQueue};
use crate::realms::enter_realm; use crate::realms::enter_realm;
use crate::script_module::ScriptFetchOptions; use crate::script_module::ScriptFetchOptions;
use crate::script_runtime::{ use crate::script_runtime::{
CanGc, CommonScriptMsg, JSContext, Runtime, ScriptChan, ScriptThreadEventCategory, CanGc, JSContext, Runtime, ScriptThreadEventCategory, ThreadSafeJSContext,
ThreadSafeJSContext,
}; };
use crate::task_queue::TaskQueue; use crate::task_queue::TaskQueue;
use crate::task_source::{SendableTaskSource, TaskSourceName}; use crate::task_source::{SendableTaskSource, TaskSourceName};
@ -531,7 +530,7 @@ impl ScriptThreadFactory for ScriptThread {
.send(()); .send(());
}, },
reporter_name, reporter_name,
script_thread.senders.self_sender.0.clone(), ScriptEventLoopSender::MainThread(script_thread.senders.self_sender.clone()),
CommonScriptMsg::CollectReports, CommonScriptMsg::CollectReports,
); );
@ -795,7 +794,7 @@ impl ScriptThread {
.borrow_mut() .borrow_mut()
.get_or_insert_with(|| { .get_or_insert_with(|| {
let init = WorkletGlobalScopeInit { let init = WorkletGlobalScopeInit {
to_script_thread_sender: script_thread.senders.self_sender.0.clone(), to_script_thread_sender: script_thread.senders.self_sender.clone(),
resource_threads: script_thread.resource_threads.clone(), resource_threads: script_thread.resource_threads.clone(),
mem_profiler_chan: script_thread.senders.memory_profiler_sender.clone(), mem_profiler_chan: script_thread.senders.memory_profiler_sender.clone(),
time_profiler_chan: script_thread.senders.time_profiler_sender.clone(), time_profiler_chan: script_thread.senders.time_profiler_sender.clone(),
@ -900,9 +899,8 @@ impl ScriptThread {
opts.output_file.is_some() || opts.exit_after_load || opts.webdriver_port.is_some(); opts.output_file.is_some() || opts.exit_after_load || opts.webdriver_port.is_some();
let (self_sender, self_receiver) = unbounded(); let (self_sender, self_receiver) = unbounded();
let self_sender = MainThreadScriptChan(self_sender.clone());
let runtime = Runtime::new(Some(SendableTaskSource { let runtime = Runtime::new(Some(SendableTaskSource {
sender: self_sender.as_boxed(), sender: ScriptEventLoopSender::MainThread(self_sender.clone()),
pipeline_id: state.id, pipeline_id: state.id,
name: TaskSourceName::Networking, name: TaskSourceName::Networking,
canceller: Default::default(), canceller: Default::default(),
@ -927,7 +925,7 @@ impl ScriptThread {
.unwrap_or_else(crossbeam_channel::never); .unwrap_or_else(crossbeam_channel::never);
let (image_cache_sender, image_cache_receiver) = unbounded(); let (image_cache_sender, image_cache_receiver) = unbounded();
let task_queue = TaskQueue::new(self_receiver, self_sender.0.clone()); let task_queue = TaskQueue::new(self_receiver, self_sender.clone());
let closing = Arc::new(AtomicBool::new(false)); let closing = Arc::new(AtomicBool::new(false));
let background_hang_monitor_exit_signal = BHMExitSignal { let background_hang_monitor_exit_signal = BHMExitSignal {

View file

@ -9,7 +9,7 @@ use std::collections::HashMap;
use base::id::PipelineId; use base::id::PipelineId;
use crate::script_runtime::ScriptChan; use crate::messaging::ScriptEventLoopSender;
use crate::task::TaskCanceller; use crate::task::TaskCanceller;
use crate::task_source::{TaskSource, TaskSourceName}; use crate::task_source::{TaskSource, TaskSourceName};
@ -75,8 +75,7 @@ macro_rules! task_source_functions {
#[derive(JSTraceable, MallocSizeOf)] #[derive(JSTraceable, MallocSizeOf)]
pub(crate) struct TaskManager { pub(crate) struct TaskManager {
#[ignore_malloc_size_of = "We need to push the measurement of this down into the ScriptChan trait"] sender: RefCell<Option<ScriptEventLoopSender>>,
sender: RefCell<Option<Box<dyn ScriptChan + Send>>>,
#[no_trace] #[no_trace]
pipeline_id: PipelineId, pipeline_id: PipelineId,
cancellers: TaskCancellers, cancellers: TaskCancellers,
@ -84,7 +83,7 @@ pub(crate) struct TaskManager {
impl TaskManager { impl TaskManager {
pub(crate) fn new( pub(crate) fn new(
sender: Option<Box<dyn ScriptChan + Send>>, sender: Option<ScriptEventLoopSender>,
pipeline_id: PipelineId, pipeline_id: PipelineId,
shared_canceller: Option<TaskCanceller>, shared_canceller: Option<TaskCanceller>,
) -> Self { ) -> Self {
@ -105,7 +104,7 @@ impl TaskManager {
self.pipeline_id self.pipeline_id
} }
pub(crate) fn sender(&self) -> Ref<Option<Box<dyn ScriptChan + Send + 'static>>> { pub(crate) fn sender(&self) -> Ref<Option<ScriptEventLoopSender>> {
self.sender.borrow() self.sender.borrow()
} }
@ -116,7 +115,7 @@ impl TaskManager {
/// Update the sender for this [`TaskSource`]. This is used by dedicated workers, which only have a /// Update the sender for this [`TaskSource`]. This is used by dedicated workers, which only have a
/// sender while handling messages (as their sender prevents the main thread Worker object from being /// sender while handling messages (as their sender prevents the main thread Worker object from being
/// garbage collected). /// garbage collected).
pub(crate) fn set_sender(&self, sender: Option<Box<dyn ScriptChan + Send>>) { pub(crate) fn set_sender(&self, sender: Option<ScriptEventLoopSender>) {
*self.sender.borrow_mut() = sender; *self.sender.borrow_mut() = sender;
} }

View file

@ -11,7 +11,8 @@ use servo_atoms::Atom;
use crate::dom::bindings::refcounted::Trusted; use crate::dom::bindings::refcounted::Trusted;
use crate::dom::event::{EventBubbles, EventCancelable, EventTask, SimpleEventTask}; use crate::dom::event::{EventBubbles, EventCancelable, EventTask, SimpleEventTask};
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
use crate::script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory}; use crate::messaging::{CommonScriptMsg, ScriptEventLoopSender};
use crate::script_runtime::ScriptThreadEventCategory;
use crate::task::{TaskCanceller, TaskOnce}; use crate::task::{TaskCanceller, TaskOnce};
use crate::task_manager::TaskManager; use crate::task_manager::TaskManager;
@ -141,7 +142,7 @@ impl TaskSource<'_> {
let sender = sender let sender = sender
.as_ref() .as_ref()
.expect("Tried to enqueue task for DedicatedWorker while not handling a message.") .expect("Tried to enqueue task for DedicatedWorker while not handling a message.")
.as_boxed(); .clone();
SendableTaskSource { SendableTaskSource {
sender, sender,
pipeline_id: self.task_manager.pipeline_id(), pipeline_id: self.task_manager.pipeline_id(),
@ -159,8 +160,7 @@ impl<'task_manager> From<TaskSource<'task_manager>> for SendableTaskSource {
#[derive(JSTraceable, MallocSizeOf)] #[derive(JSTraceable, MallocSizeOf)]
pub(crate) struct SendableTaskSource { pub(crate) struct SendableTaskSource {
#[ignore_malloc_size_of = "Need to push MallocSizeOf down into the ScriptChan trait implementations"] pub sender: ScriptEventLoopSender,
pub sender: Box<dyn ScriptChan + Send + 'static>,
#[no_trace] #[no_trace]
pub pipeline_id: PipelineId, pub pipeline_id: PipelineId,
pub name: TaskSourceName, pub name: TaskSourceName,
@ -197,7 +197,7 @@ impl SendableTaskSource {
impl Clone for SendableTaskSource { impl Clone for SendableTaskSource {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
sender: self.sender.as_boxed(), sender: self.sender.clone(),
pipeline_id: self.pipeline_id, pipeline_id: self.pipeline_id,
name: self.name, name: self.name,
canceller: self.canceller.clone(), canceller: self.canceller.clone(),