diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 958d163fec4..dba9902fd1b 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -2631,10 +2631,10 @@ where } debug!("Exiting storage resource threads."); - if let Err(e) = self - .public_resource_threads - .send(StorageThreadMsg::Exit(storage_ipc_sender)) - { + if let Err(e) = generic_channel::GenericSend::send( + &self.public_resource_threads, + StorageThreadMsg::Exit(storage_ipc_sender), + ) { warn!("Exit storage thread failed ({})", e); } diff --git a/components/fonts/tests/font_context.rs b/components/fonts/tests/font_context.rs index e551b8aed38..a9e3a3f9b25 100644 --- a/components/fonts/tests/font_context.rs +++ b/components/fonts/tests/font_context.rs @@ -14,6 +14,7 @@ mod font_context { use std::thread; use app_units::Au; + use base::generic_channel; use compositing_traits::CrossProcessCompositorApi; use fonts::platform::font::PlatformFont; use fonts::{ @@ -48,7 +49,7 @@ mod font_context { fn new() -> TestContext { let (system_font_service, system_font_service_proxy) = MockSystemFontService::spawn(); let (core_sender, _) = ipc::channel().unwrap(); - let (storage_sender, _) = ipc::channel().unwrap(); + let (storage_sender, _) = generic_channel::channel().unwrap(); let (indexeddb_sender, _) = ipc::channel().unwrap(); let mock_resource_threads = ResourceThreads::new(core_sender, storage_sender, indexeddb_sender); diff --git a/components/net/resource_thread.rs b/components/net/resource_thread.rs index 5ff2a1fb5ae..b244ae7d87e 100644 --- a/components/net/resource_thread.rs +++ b/components/net/resource_thread.rs @@ -14,6 +14,7 @@ use std::sync::{Arc, Mutex, RwLock, Weak}; use std::thread; use std::time::Duration; +use base::generic_channel::GenericSender; use base::id::CookieStoreId; use cookie::Cookie; use crossbeam_channel::Sender; @@ -112,7 +113,7 @@ pub fn new_resource_threads( protocols, ); let idb: IpcSender = IndexedDBThreadFactory::new(config_dir.clone()); - let storage: IpcSender = + let storage: GenericSender = StorageThreadFactory::new(config_dir, mem_profiler_chan); ( ResourceThreads::new(public_core, storage.clone(), idb.clone()), diff --git a/components/net/storage_thread.rs b/components/net/storage_thread.rs index da8740f11be..d094205e966 100644 --- a/components/net/storage_thread.rs +++ b/components/net/storage_thread.rs @@ -7,8 +7,9 @@ use std::collections::{BTreeMap, HashMap}; use std::path::PathBuf; use std::thread; +use base::generic_channel::{self, GenericReceiver, GenericSender}; use base::id::WebViewId; -use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; +use ipc_channel::ipc::IpcSender; use malloc_size_of::MallocSizeOf; use net_traits::storage_thread::{StorageThreadMsg, StorageType}; use profile_traits::mem::{ @@ -25,13 +26,13 @@ pub trait StorageThreadFactory { fn new(config_dir: Option, mem_profiler_chan: MemProfilerChan) -> Self; } -impl StorageThreadFactory for IpcSender { +impl StorageThreadFactory for GenericSender { /// Create a storage thread fn new( config_dir: Option, mem_profiler_chan: MemProfilerChan, - ) -> IpcSender { - let (chan, port) = ipc::channel().unwrap(); + ) -> GenericSender { + let (chan, port) = generic_channel::channel().unwrap(); let chan2 = chan.clone(); thread::Builder::new() .name("StorageManager".to_owned()) @@ -51,14 +52,14 @@ impl StorageThreadFactory for IpcSender { type OriginEntry = (usize, BTreeMap); struct StorageManager { - port: IpcReceiver, + port: GenericReceiver, session_data: HashMap>, local_data: HashMap, config_dir: Option, } impl StorageManager { - fn new(port: IpcReceiver, config_dir: Option) -> StorageManager { + fn new(port: GenericReceiver, config_dir: Option) -> StorageManager { let mut local_data = HashMap::new(); if let Some(ref config_dir) = config_dir { resource_thread::read_json_from_file(&mut local_data, config_dir, "local_data.json"); @@ -224,7 +225,7 @@ impl StorageManager { fn keys( &self, - sender: IpcSender>, + sender: GenericSender>, storage_type: StorageType, webview_id: WebViewId, url: ServoUrl, diff --git a/components/script/dom/storage.rs b/components/script/dom/storage.rs index 377a83187e1..a1a9e960ea1 100644 --- a/components/script/dom/storage.rs +++ b/components/script/dom/storage.rs @@ -1,13 +1,12 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * 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/. */ - +use base::generic_channel::{GenericSend, SendResult}; use base::id::WebViewId; use constellation_traits::ScriptToConstellationMessage; use dom_struct::dom_struct; use net_traits::storage_thread::{StorageThreadMsg, StorageType}; -use net_traits::{IpcSend, IpcSendResult}; -use profile_traits::ipc; +use profile_traits::{generic_channel, ipc}; use servo_url::ServoUrl; use crate::dom::bindings::codegen::Bindings::StorageBinding::StorageMethods; @@ -57,8 +56,8 @@ impl Storage { self.global().get_url() } - fn send_storage_msg(&self, msg: StorageThreadMsg) -> IpcSendResult { - self.global().resource_threads().send(msg) + fn send_storage_msg(&self, msg: StorageThreadMsg) -> SendResult { + GenericSend::send(self.global().resource_threads(), msg) } } @@ -173,7 +172,8 @@ impl StorageMethods for Storage { // https://html.spec.whatwg.org/multipage/#the-storage-interface:supported-property-names fn SupportedPropertyNames(&self) -> Vec { - let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); + let time_profiler = self.global().time_profiler_chan().clone(); + let (sender, receiver) = generic_channel::channel(time_profiler).unwrap(); self.send_storage_msg(StorageThreadMsg::Keys( sender, diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs index e2d5a2154ca..40e6c4c29a7 100644 --- a/components/script/dom/windowproxy.rs +++ b/components/script/dom/windowproxy.rs @@ -5,6 +5,7 @@ use std::cell::Cell; use std::ptr; +use base::generic_channel::GenericSend; use base::id::{BrowsingContextId, PipelineId, WebViewId}; use constellation_traits::{ AuxiliaryWebViewCreationRequest, LoadData, LoadOrigin, NavigationHistoryBehavior, @@ -32,7 +33,6 @@ use js::jsval::{NullValue, PrivateValue, UndefinedValue}; use js::rust::wrappers::{JS_TransplantObject, NewWindowProxy, SetWindowProxy}; use js::rust::{Handle, MutableHandle, MutableHandleValue, get_object_class}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; -use net_traits::IpcSend; use net_traits::request::Referrer; use net_traits::storage_thread::StorageThreadMsg; use script_traits::NewLayoutInfo; @@ -356,7 +356,7 @@ impl WindowProxy { dest: response.new_webview_id, }; - document.global().resource_threads().send(msg).unwrap(); + GenericSend::send(document.global().resource_threads(), msg).unwrap(); receiver.recv().unwrap(); } Some(new_window_proxy) diff --git a/components/shared/base/generic_channel.rs b/components/shared/base/generic_channel.rs index ce336f0d174..37391d3787d 100644 --- a/components/shared/base/generic_channel.rs +++ b/components/shared/base/generic_channel.rs @@ -15,6 +15,18 @@ use serde::de::VariantAccess; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use servo_config::opts; +/// Abstraction of the ability to send a particular type of message cross-process. +/// This can be used to ease the use of GenericSender sub-fields. +pub trait GenericSend +where + T: serde::Serialize + for<'de> serde::Deserialize<'de>, +{ + /// send message T + fn send(&self, _: T) -> SendResult; + /// get underlying sender + fn sender(&self) -> GenericSender; +} + /// A GenericSender that sends messages to a [GenericReceiver]. /// /// The sender supports sending messages cross-process, if servo is run in multiprocess mode. diff --git a/components/shared/net/lib.rs b/components/shared/net/lib.rs index 6aa51b7037b..9ec386d16a2 100644 --- a/components/shared/net/lib.rs +++ b/components/shared/net/lib.rs @@ -10,6 +10,7 @@ use std::sync::{LazyLock, OnceLock}; use std::thread::{self, JoinHandle}; use base::cross_process_instant::CrossProcessInstant; +use base::generic_channel::{GenericSend, GenericSender, SendResult}; use base::id::{CookieStoreId, HistoryStateId}; use content_security_policy::{self as csp}; use cookie::Cookie; @@ -421,14 +422,14 @@ where #[derive(Clone, Debug, Deserialize, Serialize)] pub struct ResourceThreads { pub core_thread: CoreResourceThread, - storage_thread: IpcSender, + storage_thread: GenericSender, idb_thread: IpcSender, } impl ResourceThreads { pub fn new( c: CoreResourceThread, - s: IpcSender, + s: GenericSender, i: IpcSender, ) -> ResourceThreads { ResourceThreads { @@ -463,12 +464,12 @@ impl IpcSend for ResourceThreads { } } -impl IpcSend for ResourceThreads { - fn send(&self, msg: StorageThreadMsg) -> IpcSendResult { +impl GenericSend for ResourceThreads { + fn send(&self, msg: StorageThreadMsg) -> SendResult { self.storage_thread.send(msg) } - fn sender(&self) -> IpcSender { + fn sender(&self) -> GenericSender { self.storage_thread.clone() } } diff --git a/components/shared/net/storage_thread.rs b/components/shared/net/storage_thread.rs index 8b877678dce..ed4428851bd 100644 --- a/components/shared/net/storage_thread.rs +++ b/components/shared/net/storage_thread.rs @@ -2,6 +2,7 @@ * 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/. */ +use base::generic_channel::GenericSender; use base::id::WebViewId; use ipc_channel::ipc::IpcSender; use malloc_size_of_derive::MallocSizeOf; @@ -31,7 +32,7 @@ pub enum StorageThreadMsg { ), /// Gets the available keys in the associated storage data - Keys(IpcSender>, StorageType, WebViewId, ServoUrl), + Keys(GenericSender>, StorageType, WebViewId, ServoUrl), /// gets the value associated with the given key in the associated storage data GetItem( diff --git a/components/shared/profile/generic_channel.rs b/components/shared/profile/generic_channel.rs new file mode 100644 index 00000000000..5e293f569aa --- /dev/null +++ b/components/shared/profile/generic_channel.rs @@ -0,0 +1,53 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +use base::generic_channel; +use serde::{Deserialize, Serialize}; + +use crate::time::{ProfilerCategory, ProfilerChan}; +use crate::time_profile; + +pub struct GenericReceiver +where + T: for<'de> Deserialize<'de> + Serialize, +{ + receiver: generic_channel::GenericReceiver, + time_profile_chan: ProfilerChan, +} + +impl GenericReceiver +where + T: for<'de> Deserialize<'de> + Serialize, +{ + pub fn recv(&self) -> Result { + time_profile!( + ProfilerCategory::IpcReceiver, + None, + self.time_profile_chan.clone(), + move || self.receiver.recv(), + ) + } + + pub fn try_recv(&self) -> Result { + self.receiver.try_recv() + } + + pub fn into_inner(self) -> generic_channel::GenericReceiver { + self.receiver + } +} + +pub fn channel( + time_profile_chan: ProfilerChan, +) -> Option<(generic_channel::GenericSender, GenericReceiver)> +where + T: for<'de> Deserialize<'de> + Serialize, +{ + let (sender, receiver) = generic_channel::channel()?; + let profiled_receiver = GenericReceiver { + receiver, + time_profile_chan, + }; + Some((sender, profiled_receiver)) +} diff --git a/components/shared/profile/lib.rs b/components/shared/profile/lib.rs index 4e3aa1fc35d..acd3d0222f9 100644 --- a/components/shared/profile/lib.rs +++ b/components/shared/profile/lib.rs @@ -8,6 +8,7 @@ #![deny(unsafe_code)] +pub mod generic_channel; pub mod ipc; pub mod mem; pub mod time; diff --git a/components/shared/profile/mem.rs b/components/shared/profile/mem.rs index 57b442bd5cb..066a11059f3 100644 --- a/components/shared/profile/mem.rs +++ b/components/shared/profile/mem.rs @@ -11,6 +11,7 @@ use std::collections::HashSet; use std::ffi::c_void; use std::marker::Send; +use base::generic_channel::GenericSender; use crossbeam_channel::Sender; use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::router::ROUTER; @@ -49,6 +50,20 @@ where } } +impl OpaqueSender for GenericSender +where + T: serde::Serialize, +{ + fn send(&self, message: T) { + if let Err(e) = GenericSender::send(self, message) { + warn!( + "Error communicating with the target thread from the profiler: {}", + e + ); + } + } +} + /// Front-end representation of the profiler used to communicate with the /// profiler. #[derive(Clone, Debug, Deserialize, Serialize)]