mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
net: Use a thread for each AsyncResponseTarget
to avoid having to send
trait objects across process boundaries.
This commit is contained in:
parent
9c9d7dc93b
commit
44d13f7fd4
10 changed files with 78 additions and 31 deletions
|
@ -14,6 +14,7 @@ use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::mpsc::{channel, Sender, Receiver, Select};
|
use std::sync::mpsc::{channel, Sender, Receiver, Select};
|
||||||
|
use std::thread;
|
||||||
use util::resource_files::resources_dir_path;
|
use util::resource_files::resources_dir_path;
|
||||||
use util::task::spawn_named;
|
use util::task::spawn_named;
|
||||||
use util::taskpool::TaskPool;
|
use util::taskpool::TaskPool;
|
||||||
|
@ -100,14 +101,17 @@ struct ResourceLoadInfo {
|
||||||
struct ResourceListener {
|
struct ResourceListener {
|
||||||
url: Url,
|
url: Url,
|
||||||
sender: Sender<ResourceLoadInfo>,
|
sender: Sender<ResourceLoadInfo>,
|
||||||
|
receiver: Receiver<ResponseAction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncResponseTarget for ResourceListener {
|
impl ResourceListener {
|
||||||
fn invoke_with_listener(&self, action: ResponseAction) {
|
fn run(&self) {
|
||||||
self.sender.send(ResourceLoadInfo {
|
while let Ok(action) = self.receiver.recv() {
|
||||||
action: action,
|
self.sender.send(ResourceLoadInfo {
|
||||||
url: self.url.clone(),
|
action: action,
|
||||||
}).unwrap();
|
url: self.url.clone(),
|
||||||
|
}).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,11 +334,17 @@ impl ImageCache {
|
||||||
e.insert(pending_load);
|
e.insert(pending_load);
|
||||||
|
|
||||||
let load_data = LoadData::new(url.clone(), None);
|
let load_data = LoadData::new(url.clone(), None);
|
||||||
|
let (action_sender, action_receiver) = channel();
|
||||||
let listener = box ResourceListener {
|
let listener = box ResourceListener {
|
||||||
url: url,
|
url: url,
|
||||||
sender: self.progress_sender.clone(),
|
sender: self.progress_sender.clone(),
|
||||||
|
receiver: action_receiver,
|
||||||
};
|
};
|
||||||
let msg = ControlMsg::Load(load_data, LoadConsumer::Listener(listener));
|
let msg = ControlMsg::Load(load_data,
|
||||||
|
LoadConsumer::Listener(AsyncResponseTarget {
|
||||||
|
sender: action_sender,
|
||||||
|
}));
|
||||||
|
thread::spawn(move || listener.run());
|
||||||
self.resource_task.send(msg).unwrap();
|
self.resource_task.send(msg).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ pub fn global_init() {
|
||||||
|
|
||||||
pub enum ProgressSender {
|
pub enum ProgressSender {
|
||||||
Channel(Sender<ProgressMsg>),
|
Channel(Sender<ProgressMsg>),
|
||||||
Listener(Box<AsyncResponseTarget>),
|
Listener(AsyncResponseTarget),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProgressSender {
|
impl ProgressSender {
|
||||||
|
|
|
@ -114,14 +114,20 @@ impl ResponseAction {
|
||||||
|
|
||||||
/// A target for async networking events. Commonly used to dispatch a runnable event to another
|
/// A target for async networking events. Commonly used to dispatch a runnable event to another
|
||||||
/// thread storing the wrapped closure for later execution.
|
/// thread storing the wrapped closure for later execution.
|
||||||
pub trait AsyncResponseTarget {
|
pub struct AsyncResponseTarget {
|
||||||
fn invoke_with_listener(&self, action: ResponseAction);
|
pub sender: Sender<ResponseAction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncResponseTarget {
|
||||||
|
pub fn invoke_with_listener(&self, action: ResponseAction) {
|
||||||
|
self.sender.send(action).unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper for a network load that can either be channel or event-based.
|
/// A wrapper for a network load that can either be channel or event-based.
|
||||||
pub enum LoadConsumer {
|
pub enum LoadConsumer {
|
||||||
Channel(Sender<LoadResponse>),
|
Channel(Sender<LoadResponse>),
|
||||||
Listener(Box<AsyncResponseTarget + Send>),
|
Listener(AsyncResponseTarget),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle to a resource task
|
/// Handle to a resource task
|
||||||
|
@ -195,7 +201,7 @@ impl PendingAsyncLoad {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initiate the network request associated with this pending load, using the provided target.
|
/// Initiate the network request associated with this pending load, using the provided target.
|
||||||
pub fn load_async(mut self, listener: Box<AsyncResponseTarget + Send>) {
|
pub fn load_async(mut self, listener: AsyncResponseTarget) {
|
||||||
self.guard.neuter();
|
self.guard.neuter();
|
||||||
let load_data = LoadData::new(self.url, self.pipeline);
|
let load_data = LoadData::new(self.url, self.pipeline);
|
||||||
let consumer = LoadConsumer::Listener(listener);
|
let consumer = LoadConsumer::Listener(listener);
|
||||||
|
|
|
@ -17,6 +17,7 @@ use net_traits::{SerializableStringResult};
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::sync::mpsc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use time;
|
use time;
|
||||||
use time::{now, Timespec};
|
use time::{now, Timespec};
|
||||||
|
@ -132,9 +133,14 @@ impl CORSRequest {
|
||||||
listener: listener,
|
listener: listener,
|
||||||
response: RefCell::new(None),
|
response: RefCell::new(None),
|
||||||
};
|
};
|
||||||
|
let (action_sender, action_receiver) = mpsc::channel();
|
||||||
let listener = NetworkListener {
|
let listener = NetworkListener {
|
||||||
context: Arc::new(Mutex::new(context)),
|
context: Arc::new(Mutex::new(context)),
|
||||||
script_chan: script_chan,
|
script_chan: script_chan,
|
||||||
|
receiver: action_receiver,
|
||||||
|
};
|
||||||
|
let response_target = AsyncResponseTarget {
|
||||||
|
sender: action_sender,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: this exists only to make preflight check non-blocking
|
// TODO: this exists only to make preflight check non-blocking
|
||||||
|
@ -145,7 +151,7 @@ impl CORSRequest {
|
||||||
let mut context = listener.context.lock();
|
let mut context = listener.context.lock();
|
||||||
let context = context.as_mut().unwrap();
|
let context = context.as_mut().unwrap();
|
||||||
*context.response.borrow_mut() = Some(response);
|
*context.response.borrow_mut() = Some(response);
|
||||||
listener.invoke_with_listener(ResponseAction::ResponseComplete(
|
response_target.invoke_with_listener(ResponseAction::ResponseComplete(
|
||||||
SerializableStringResult(Ok(()))));
|
SerializableStringResult(Ok(()))));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ impl DocumentLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create and initiate a new network request.
|
/// Create and initiate a new network request.
|
||||||
pub fn load_async(&mut self, load: LoadType, listener: Box<AsyncResponseTarget + Send>) {
|
pub fn load_async(&mut self, load: LoadType, listener: AsyncResponseTarget) {
|
||||||
let pending = self.prepare_async_load(load);
|
let pending = self.prepare_async_load(load);
|
||||||
pending.load_async(listener)
|
pending.load_async(listener)
|
||||||
}
|
}
|
||||||
|
|
|
@ -283,7 +283,7 @@ pub trait DocumentHelpers<'a> {
|
||||||
/// https://w3c.github.io/animation-timing/#dfn-invoke-callbacks-algorithm
|
/// https://w3c.github.io/animation-timing/#dfn-invoke-callbacks-algorithm
|
||||||
fn invoke_animation_callbacks(self);
|
fn invoke_animation_callbacks(self);
|
||||||
fn prepare_async_load(self, load: LoadType) -> PendingAsyncLoad;
|
fn prepare_async_load(self, load: LoadType) -> PendingAsyncLoad;
|
||||||
fn load_async(self, load: LoadType, listener: Box<AsyncResponseTarget + Send>);
|
fn load_async(self, load: LoadType, listener: AsyncResponseTarget);
|
||||||
fn load_sync(self, load: LoadType) -> Result<(Metadata, Vec<u8>), String>;
|
fn load_sync(self, load: LoadType) -> Result<(Metadata, Vec<u8>), String>;
|
||||||
fn finish_load(self, load: LoadType);
|
fn finish_load(self, load: LoadType);
|
||||||
fn set_current_parser(self, script: Option<&ServoHTMLParser>);
|
fn set_current_parser(self, script: Option<&ServoHTMLParser>);
|
||||||
|
@ -968,7 +968,7 @@ impl<'a> DocumentHelpers<'a> for &'a Document {
|
||||||
loader.prepare_async_load(load)
|
loader.prepare_async_load(load)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_async(self, load: LoadType, listener: Box<AsyncResponseTarget + Send>) {
|
fn load_async(self, load: LoadType, listener: AsyncResponseTarget) {
|
||||||
let mut loader = self.loader.borrow_mut();
|
let mut loader = self.loader.borrow_mut();
|
||||||
loader.load_async(load, listener)
|
loader.load_async(load, listener)
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,12 +40,14 @@ use js::jsval::UndefinedValue;
|
||||||
use encoding::all::UTF_8;
|
use encoding::all::UTF_8;
|
||||||
use encoding::label::encoding_from_whatwg_label;
|
use encoding::label::encoding_from_whatwg_label;
|
||||||
use encoding::types::{Encoding, EncodingRef, DecoderTrap};
|
use encoding::types::{Encoding, EncodingRef, DecoderTrap};
|
||||||
use net_traits::{Metadata, AsyncResponseListener};
|
use net_traits::{Metadata, AsyncResponseListener, AsyncResponseTarget};
|
||||||
use util::str::{DOMString, HTML_SPACE_CHARACTERS, StaticStringVec};
|
use util::str::{DOMString, HTML_SPACE_CHARACTERS, StaticStringVec};
|
||||||
use html5ever::tree_builder::NextParserState;
|
use html5ever::tree_builder::NextParserState;
|
||||||
use std::cell::{RefCell, Cell};
|
use std::cell::{RefCell, Cell};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::sync::mpsc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::thread;
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use url::{Url, UrlParser};
|
use url::{Url, UrlParser};
|
||||||
|
|
||||||
|
@ -330,12 +332,18 @@ impl<'a> HTMLScriptElementHelpers for &'a HTMLScriptElement {
|
||||||
url: url.clone(),
|
url: url.clone(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
let (action_sender, action_receiver) = mpsc::channel();
|
||||||
let listener = box NetworkListener {
|
let listener = box NetworkListener {
|
||||||
context: context,
|
context: context,
|
||||||
script_chan: script_chan,
|
script_chan: script_chan,
|
||||||
|
receiver: action_receiver,
|
||||||
};
|
};
|
||||||
|
let response_target = AsyncResponseTarget {
|
||||||
|
sender: action_sender,
|
||||||
|
};
|
||||||
|
thread::spawn(move || listener.run());
|
||||||
|
|
||||||
doc.r().load_async(LoadType::Script(url), listener);
|
doc.r().load_async(LoadType::Script(url), response_target);
|
||||||
|
|
||||||
if self.parser_inserted.get() {
|
if self.parser_inserted.get() {
|
||||||
doc.r().get_current_parser().unwrap().r().suspend();
|
doc.r().get_current_parser().unwrap().r().suspend();
|
||||||
|
|
|
@ -46,8 +46,8 @@ use js::jsval::{JSVal, NullValue, UndefinedValue};
|
||||||
|
|
||||||
use net_traits::ControlMsg::Load;
|
use net_traits::ControlMsg::Load;
|
||||||
use net_traits::{ResourceTask, ResourceCORSData, LoadData, LoadConsumer};
|
use net_traits::{ResourceTask, ResourceCORSData, LoadData, LoadConsumer};
|
||||||
use net_traits::{AsyncResponseListener, Metadata, SerializableHeaders, SerializableMethod};
|
use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata, SerializableHeaders};
|
||||||
use net_traits::{SerializableUrl};
|
use net_traits::{SerializableMethod, SerializableUrl};
|
||||||
use cors::{allow_cross_origin_request, CORSRequest, RequestMode, AsyncCORSResponseListener};
|
use cors::{allow_cross_origin_request, CORSRequest, RequestMode, AsyncCORSResponseListener};
|
||||||
use cors::CORSResponse;
|
use cors::CORSResponse;
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
|
@ -59,7 +59,7 @@ use std::cell::{RefCell, Cell};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::sync::{Mutex, Arc};
|
use std::sync::{Mutex, Arc};
|
||||||
use std::sync::mpsc::{channel, Sender, TryRecvError};
|
use std::sync::mpsc::{channel, Sender, TryRecvError};
|
||||||
use std::thread::sleep_ms;
|
use std::thread::{self, sleep_ms};
|
||||||
use time;
|
use time;
|
||||||
use url::{Url, UrlParser};
|
use url::{Url, UrlParser};
|
||||||
|
|
||||||
|
@ -271,11 +271,17 @@ impl XMLHttpRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (action_sender, action_receiver) = channel();
|
||||||
let listener = box NetworkListener {
|
let listener = box NetworkListener {
|
||||||
context: context,
|
context: context,
|
||||||
script_chan: script_chan,
|
script_chan: script_chan,
|
||||||
|
receiver: action_receiver,
|
||||||
};
|
};
|
||||||
resource_task.send(Load(load_data, LoadConsumer::Listener(listener))).unwrap();
|
let response_target = AsyncResponseTarget {
|
||||||
|
sender: action_sender,
|
||||||
|
};
|
||||||
|
thread::spawn(move || listener.run());
|
||||||
|
resource_task.send(Load(load_data, LoadConsumer::Listener(response_target))).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use script_task::{ScriptChan, ScriptMsg, Runnable};
|
use script_task::{ScriptChan, ScriptMsg, Runnable};
|
||||||
use net_traits::{AsyncResponseTarget, AsyncResponseListener, ResponseAction};
|
use net_traits::{AsyncResponseListener, ResponseAction};
|
||||||
|
use std::sync::mpsc::Receiver;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
/// An off-thread sink for async network event runnables. All such events are forwarded to
|
/// An off-thread sink for async network event runnables. All such events are forwarded to
|
||||||
|
@ -11,14 +12,17 @@ use std::sync::{Arc, Mutex};
|
||||||
pub struct NetworkListener<T: AsyncResponseListener + PreInvoke + Send + 'static> {
|
pub struct NetworkListener<T: AsyncResponseListener + PreInvoke + Send + 'static> {
|
||||||
pub context: Arc<Mutex<T>>,
|
pub context: Arc<Mutex<T>>,
|
||||||
pub script_chan: Box<ScriptChan+Send>,
|
pub script_chan: Box<ScriptChan+Send>,
|
||||||
|
pub receiver: Receiver<ResponseAction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: AsyncResponseListener + PreInvoke + Send + 'static> AsyncResponseTarget for NetworkListener<T> {
|
impl<T: AsyncResponseListener + PreInvoke + Send + 'static> NetworkListener<T> {
|
||||||
fn invoke_with_listener(&self, action: ResponseAction) {
|
pub fn run(&self) {
|
||||||
self.script_chan.send(ScriptMsg::RunnableMsg(box ListenerRunnable {
|
while let Ok(action) = self.receiver.recv() {
|
||||||
context: self.context.clone(),
|
self.script_chan.send(ScriptMsg::RunnableMsg(box ListenerRunnable {
|
||||||
action: action,
|
context: self.context.clone(),
|
||||||
})).unwrap();
|
action: action,
|
||||||
|
})).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ use msg::constellation_msg::{Failure, WindowSizeData, PipelineExitType};
|
||||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||||
use msg::webdriver_msg::WebDriverScriptCommand;
|
use msg::webdriver_msg::WebDriverScriptCommand;
|
||||||
use net_traits::LoadData as NetLoadData;
|
use net_traits::LoadData as NetLoadData;
|
||||||
use net_traits::{ResourceTask, LoadConsumer, ControlMsg, Metadata};
|
use net_traits::{AsyncResponseTarget, ResourceTask, LoadConsumer, ControlMsg, Metadata};
|
||||||
use net_traits::{SerializableContentType, SerializableHeaders, SerializableMethod};
|
use net_traits::{SerializableContentType, SerializableHeaders, SerializableMethod};
|
||||||
use net_traits::{SerializableUrl};
|
use net_traits::{SerializableUrl};
|
||||||
use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageCacheResult};
|
use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageCacheResult};
|
||||||
|
@ -105,6 +105,7 @@ use std::rc::Rc;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::sync::mpsc::{channel, Sender, Receiver, Select};
|
use std::sync::mpsc::{channel, Sender, Receiver, Select};
|
||||||
|
use std::thread;
|
||||||
use time::Tm;
|
use time::Tm;
|
||||||
|
|
||||||
use hyper::header::{ContentType, HttpDate};
|
use hyper::header::{ContentType, HttpDate};
|
||||||
|
@ -1686,9 +1687,15 @@ impl ScriptTask {
|
||||||
|
|
||||||
let context = Arc::new(Mutex::new(ParserContext::new(id, subpage, script_chan.clone(),
|
let context = Arc::new(Mutex::new(ParserContext::new(id, subpage, script_chan.clone(),
|
||||||
load_data.url.clone())));
|
load_data.url.clone())));
|
||||||
|
let (action_sender, action_receiver) = channel();
|
||||||
let listener = box NetworkListener {
|
let listener = box NetworkListener {
|
||||||
context: context,
|
context: context,
|
||||||
script_chan: script_chan.clone(),
|
script_chan: script_chan.clone(),
|
||||||
|
receiver: action_receiver,
|
||||||
|
};
|
||||||
|
thread::spawn(move || listener.run());
|
||||||
|
let response_target = AsyncResponseTarget {
|
||||||
|
sender: action_sender,
|
||||||
};
|
};
|
||||||
|
|
||||||
if load_data.url.scheme == "javascript" {
|
if load_data.url.scheme == "javascript" {
|
||||||
|
@ -1703,7 +1710,7 @@ impl ScriptTask {
|
||||||
data: load_data.data,
|
data: load_data.data,
|
||||||
cors: None,
|
cors: None,
|
||||||
pipeline_id: Some(id),
|
pipeline_id: Some(id),
|
||||||
}, LoadConsumer::Listener(listener))).unwrap();
|
}, LoadConsumer::Listener(response_target))).unwrap();
|
||||||
|
|
||||||
self.incomplete_loads.borrow_mut().push(incomplete);
|
self.incomplete_loads.borrow_mut().push(incomplete);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue