Skip to content

Commit

Permalink
Prevent the constellation from panicking if there is a deserializatio…
Browse files Browse the repository at this point in the history
…n error.
  • Loading branch information
Alan Jeffrey committed Feb 20, 2017
1 parent ddaa679 commit aee1291
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 13 deletions.
52 changes: 39 additions & 13 deletions components/constellation/constellation.rs
Expand Up @@ -78,8 +78,8 @@ use event_loop::EventLoop;
use frame::{Frame, FrameChange, FrameState, FrameTreeIterator, FullFrameTreeIterator};
use gfx::font_cache_thread::FontCacheThread;
use gfx_traits::Epoch;
use ipc_channel::Error;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::{Error as IpcError};
use ipc_channel::ipc::{self, IpcSender, IpcReceiver};
use ipc_channel::router::ROUTER;
use layout_traits::LayoutThreadFactory;
use log::{Log, LogLevel, LogLevelFilter, LogMetadata, LogRecord};
Expand All @@ -103,6 +103,7 @@ use script_traits::{LogEntry, ServiceWorkerMsg, webdriver_msg};
use script_traits::{MozBrowserErrorType, MozBrowserEvent, WebDriverCommandMsg, WindowSizeData};
use script_traits::{SWManagerMsg, ScopeThings, WindowSizeType};
use script_traits::WebVREventMsg;
use serde::{Deserialize, Serialize};
use servo_config::opts;
use servo_config::prefs::PREFS;
use servo_rand::{Rng, SeedableRng, ServoRng, random};
Expand Down Expand Up @@ -145,15 +146,15 @@ pub struct Constellation<Message, LTF, STF> {

/// A channel for the constellation to receive messages from script threads.
/// This is the constellation's view of `script_sender`.
script_receiver: Receiver<FromScriptMsg>,
script_receiver: Receiver<Result<FromScriptMsg, IpcError>>,

/// An IPC channel for layout threads to send messages to the constellation.
/// This is the layout threads' view of `layout_receiver`.
layout_sender: IpcSender<FromLayoutMsg>,

/// A channel for the constellation to receive messages from layout threads.
/// This is the constellation's view of `layout_sender`.
layout_receiver: Receiver<FromLayoutMsg>,
layout_receiver: Receiver<Result<FromLayoutMsg, IpcError>>,

/// A channel for the constellation to receive messages from the compositor thread.
compositor_receiver: Receiver<FromCompositorMsg>,
Expand Down Expand Up @@ -206,7 +207,7 @@ pub struct Constellation<Message, LTF, STF> {
/// A channel for the constellation to receive messages from the
/// Service Worker Manager thread. This is the constellation's view of
/// `swmanager_sender`.
swmanager_receiver: Receiver<SWManagerMsg>,
swmanager_receiver: Receiver<Result<SWManagerMsg, IpcError>>,

/// A channel for the constellation to send messages to the
/// time profiler thread.
Expand Down Expand Up @@ -468,6 +469,20 @@ fn log_entry(record: &LogRecord) -> Option<LogEntry> {
/// The number of warnings to include in each crash report.
const WARNINGS_BUFFER_SIZE: usize = 32;

/// Route an ipc receiver to an mpsc receiver, preserving any errors.
/// This is the same as `route_ipc_receiver_to_new_mpsc_receiver`,
/// but does not panic on deserializtion errors.
fn route_ipc_receiver_to_new_mpsc_receiver_preserving_errors<T>(ipc_receiver: IpcReceiver<T>)
-> Receiver<Result<T, IpcError>>
where T: Deserialize + Serialize + Send + 'static
{
let (mpsc_sender, mpsc_receiver) = channel();
ROUTER.add_route(ipc_receiver.to_opaque(), Box::new(move |message| {
drop(mpsc_sender.send(message.to::<T>()))
}));
mpsc_receiver
}

impl<Message, LTF, STF> Constellation<Message, LTF, STF>
where LTF: LayoutThreadFactory<Message=Message>,
STF: ScriptThreadFactory<Message=Message>
Expand All @@ -482,12 +497,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>

thread::Builder::new().name("Constellation".to_owned()).spawn(move || {
let (ipc_script_sender, ipc_script_receiver) = ipc::channel().expect("ipc channel failure");
let script_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_script_receiver);
let script_receiver = route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(ipc_script_receiver);

let (ipc_layout_sender, ipc_layout_receiver) = ipc::channel().expect("ipc channel failure");
let layout_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_layout_receiver);
let layout_receiver = route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(ipc_layout_receiver);

let swmanager_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(swmanager_receiver);
let swmanager_receiver = route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(swmanager_receiver);

PipelineNamespace::install(PipelineNamespaceId(0));

Expand Down Expand Up @@ -776,13 +791,24 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let receiver_from_swmanager = &self.swmanager_receiver;
select! {
msg = receiver_from_script.recv() =>
Request::Script(msg.expect("Unexpected script channel panic in constellation")),
msg.expect("Unexpected script channel panic in constellation").map(Request::Script),
msg = receiver_from_compositor.recv() =>
Request::Compositor(msg.expect("Unexpected compositor channel panic in constellation")),
Ok(Request::Compositor(msg.expect("Unexpected compositor channel panic in constellation"))),
msg = receiver_from_layout.recv() =>
Request::Layout(msg.expect("Unexpected layout channel panic in constellation")),
msg.expect("Unexpected layout channel panic in constellation").map(Request::Layout),
msg = receiver_from_swmanager.recv() =>
Request::FromSWManager(msg.expect("Unexpected panic channel panic in constellation"))
msg.expect("Unexpected panic channel panic in constellation").map(Request::FromSWManager)
}
};

let request = match request {
Ok(request) => request,
Err(err) => {
// Treat deserialization error the same as receiving a panic message
debug!("Deserialization failed ({:?}).", err);
let reason = format!("Deserialization failed ({})", err);
let root_frame_id = self.root_frame_id;
return self.handle_panic(root_frame_id, reason, None);
}
};

Expand Down Expand Up @@ -1228,7 +1254,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.pipelines.remove(&pipeline_id);
}

fn handle_send_error(&mut self, pipeline_id: PipelineId, err: Error) {
fn handle_send_error(&mut self, pipeline_id: PipelineId, err: IpcError) {
// Treat send error the same as receiving a panic message
debug!("Pipeline {:?} send error ({}).", pipeline_id, err);
let top_level_frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
Expand Down
1 change: 1 addition & 0 deletions components/constellation/lib.rs
Expand Up @@ -31,6 +31,7 @@ extern crate net_traits;
extern crate offscreen_gl_context;
extern crate profile_traits;
extern crate script_traits;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate servo_config;
Expand Down

0 comments on commit aee1291

Please sign in to comment.