diff --git a/Cargo.toml b/Cargo.toml index b1d8c6699..7faaac2c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,6 +95,9 @@ secretstore = ["ethcore-secretstore"] path = "parity/main.rs" name = "parity" +[profile.debug] +panic = "abort" + [profile.release] debug = false lto = false diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 4cf1530ea..a42b5723e 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -141,7 +141,6 @@ pub struct Client { block_queue: BlockQueue, report: RwLock, import_lock: Mutex<()>, - panic_handler: Arc, verifier: Box, miner: Arc, sleep_state: Mutex, @@ -213,8 +212,6 @@ impl Client { let engine = spec.engine.clone(); let block_queue = BlockQueue::new(config.queue.clone(), engine.clone(), message_channel.clone(), config.verifier_type.verifying_seal()); - let panic_handler = PanicHandler::new_in_arc(); - panic_handler.forward_from(&block_queue); let awake = match config.mode { Mode::Dark(..) | Mode::Off => false, _ => true }; @@ -234,7 +231,6 @@ impl Client { block_queue: block_queue, report: RwLock::new(Default::default()), import_lock: Mutex::new(()), - panic_handler: panic_handler, miner: miner, io_channel: Mutex::new(message_channel), notify: RwLock::new(Vec::new()), @@ -1723,12 +1719,6 @@ impl EngineClient for Client { } } -impl MayPanic for Client { - fn on_panic(&self, closure: F) where F: OnPanicListener { - self.panic_handler.on_panic(closure); - } -} - impl ProvingBlockChainClient for Client { fn prove_storage(&self, key1: H256, key2: H256, id: BlockId) -> Option<(Vec, H256)> { self.state_at(id) diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index b48fb9445..e4c3d7519 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -56,7 +56,6 @@ pub struct ClientService { io_service: Arc>, client: Arc, snapshot: Arc, - panic_handler: Arc, database: Arc, _stop_guard: ::devtools::StopGuard, } @@ -72,9 +71,7 @@ impl ClientService { miner: Arc, ) -> Result { - let panic_handler = PanicHandler::new_in_arc(); let io_service = IoService::::start()?; - panic_handler.forward_from(&io_service); info!("Configured for {} using {} engine", Colour::White.bold().paint(spec.name.clone()), Colour::Yellow.bold().paint(spec.engine.name())); @@ -109,7 +106,6 @@ impl ClientService { }; let snapshot = Arc::new(SnapshotService::new(snapshot_params)?); - panic_handler.forward_from(&*client); let client_io = Arc::new(ClientIoHandler { client: client.clone(), snapshot: snapshot.clone(), @@ -125,7 +121,6 @@ impl ClientService { io_service: Arc::new(io_service), client: client, snapshot: snapshot, - panic_handler: panic_handler, database: db, _stop_guard: stop_guard, }) @@ -160,12 +155,6 @@ impl ClientService { pub fn db(&self) -> Arc { self.database.clone() } } -impl MayPanic for ClientService { - fn on_panic(&self, closure: F) where F: OnPanicListener { - self.panic_handler.on_panic(closure); - } -} - /// IO interface for the Client handler struct ClientIoHandler { client: Arc, diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index 9d43cf635..fa090a0cf 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -125,7 +125,6 @@ struct Sizes { /// A queue of items to be verified. Sits between network or other I/O and the `BlockChain`. /// Keeps them in the same order as inserted, minus invalid items. pub struct VerificationQueue { - panic_handler: Arc, engine: Arc, more_to_verify: Arc, verification: Arc>, @@ -221,7 +220,6 @@ impl VerificationQueue { message_channel: Mutex::new(message_channel), }); let empty = Arc::new(SCondvar::new()); - let panic_handler = PanicHandler::new_in_arc(); let scale_verifiers = config.verifier_settings.scale_verifiers; let num_cpus = ::num_cpus::get(); @@ -236,7 +234,6 @@ impl VerificationQueue { for i in 0..max_verifiers { debug!(target: "verification", "Adding verification thread #{}", i); - let panic_handler = panic_handler.clone(); let verification = verification.clone(); let engine = engine.clone(); let wait = more_to_verify.clone(); @@ -247,17 +244,15 @@ impl VerificationQueue { let handle = thread::Builder::new() .name(format!("Verifier #{}", i)) .spawn(move || { - panic_handler.catch_panic(move || { - VerificationQueue::verify( - verification, - engine, - wait, - ready, - empty, - state, - i, - ) - }).unwrap() + VerificationQueue::verify( + verification, + engine, + wait, + ready, + empty, + state, + i, + ) }) .expect("Failed to create verifier thread."); verifier_handles.push(handle); @@ -265,7 +260,6 @@ impl VerificationQueue { VerificationQueue { engine: engine, - panic_handler: panic_handler, ready_signal: ready_signal, more_to_verify: more_to_verify, verification: verification, @@ -692,12 +686,6 @@ impl VerificationQueue { } } -impl MayPanic for VerificationQueue { - fn on_panic(&self, closure: F) where F: OnPanicListener { - self.panic_handler.on_panic(closure); - } -} - impl Drop for VerificationQueue { fn drop(&mut self) { trace!(target: "shutdown", "[VerificationQueue] Closing..."); diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 84af882ca..fe34fa56c 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -21,7 +21,6 @@ use std::time::{Instant, Duration}; use std::thread::sleep; use std::sync::Arc; use rustc_serialize::hex::FromHex; -use io::{PanicHandler, ForwardPanic}; use util::{ToPretty, U256, H256, Address, Hashable}; use rlp::PayloadInfo; use ethcore::service::ClientService; @@ -148,9 +147,6 @@ pub fn execute(cmd: BlockchainCmd) -> Result<(), String> { fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { let timer = Instant::now(); - // Setup panic handler - let panic_handler = PanicHandler::new_in_arc(); - // load spec file let spec = cmd.spec.spec()?; @@ -219,7 +215,6 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { // free up the spec in memory. drop(spec); - panic_handler.forward_from(&service); let client = service.client(); let mut instream: Box = match cmd.file_path { @@ -390,7 +385,6 @@ fn start_client( } fn execute_export(cmd: ExportBlockchain) -> Result<(), String> { - // Setup panic handler let service = start_client( cmd.dirs, cmd.spec, @@ -403,10 +397,8 @@ fn execute_export(cmd: ExportBlockchain) -> Result<(), String> { cmd.wal, cmd.cache_config )?; - let panic_handler = PanicHandler::new_in_arc(); let format = cmd.format.unwrap_or_default(); - panic_handler.forward_from(&service); let client = service.client(); let mut out: Box = match cmd.file_path { @@ -433,7 +425,6 @@ fn execute_export(cmd: ExportBlockchain) -> Result<(), String> { } fn execute_export_state(cmd: ExportState) -> Result<(), String> { - // Setup panic handler let service = start_client( cmd.dirs, cmd.spec, @@ -447,9 +438,6 @@ fn execute_export_state(cmd: ExportState) -> Result<(), String> { cmd.cache_config )?; - let panic_handler = PanicHandler::new_in_arc(); - - panic_handler.forward_from(&service); let client = service.client(); let mut out: Box = match cmd.file_path { diff --git a/parity/run.rs b/parity/run.rs index fcbeb5f1f..4368a6376 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -21,7 +21,6 @@ use fdlimit::raise_fd_limit; use parity_rpc::{NetworkSettings, informant, is_major_importing}; use ethsync::NetworkConfiguration; use util::{Colour, version, Mutex, Condvar}; -use io::{MayPanic, ForwardPanic, PanicHandler}; use ethcore_logger::{Config as LogConfig, RotatingLogger}; use ethcore::miner::{StratumOptions, Stratum}; use ethcore::client::{Client, Mode, DatabaseCompactionProfile, VMType, BlockChainClient}; @@ -168,8 +167,6 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc) -> use ethsync::{LightSyncParams, LightSync, ManageNetwork}; use util::RwLock; - let panic_handler = PanicHandler::new_in_arc(); - // load spec let spec = cmd.spec.spec()?; @@ -332,7 +329,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc) -> }); // wait for ctrl-c. - Ok(wait_for_exit(panic_handler, None, None, can_restart)) + Ok(wait_for_exit(None, None, can_restart)) } pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc) -> Result<(bool, Option), String> { @@ -352,9 +349,6 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc) -> R return execute_light(cmd, can_restart, logger); } - // set up panic handler - let panic_handler = PanicHandler::new_in_arc(); - // load spec let spec = cmd.spec.spec()?; @@ -517,9 +511,6 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc) -> R // drop the spec to free up genesis state. drop(spec); - // forward panics from service - panic_handler.forward_from(&service); - // take handle to client let client = service.client(); let snapshot_service = service.snapshot_service(); @@ -731,7 +722,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc) -> R } // Handle exit - let restart = wait_for_exit(panic_handler, Some(updater), Some(client), can_restart); + let restart = wait_for_exit(Some(updater), Some(client), can_restart); info!("Finishing work, please wait..."); @@ -836,7 +827,6 @@ fn build_create_account_hint(spec: &SpecType, keys: &str) -> String { } fn wait_for_exit( - panic_handler: Arc, updater: Option>, client: Option>, can_restart: bool @@ -847,10 +837,6 @@ fn wait_for_exit( let e = exit.clone(); CtrlC::set_handler(move || { e.1.notify_all(); }); - // Handle panics - let e = exit.clone(); - panic_handler.on_panic(move |_reason| { e.1.notify_all(); }); - if can_restart { if let Some(updater) = updater { // Handle updater wanting to restart us diff --git a/parity/snapshot.rs b/parity/snapshot.rs index af39bffb0..0c4569901 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -35,8 +35,6 @@ use dir::Directories; use user_defaults::UserDefaults; use fdlimit; -use io::PanicHandler; - /// Kinds of snapshot commands. #[derive(Debug, PartialEq, Clone, Copy)] pub enum Kind { @@ -133,10 +131,7 @@ fn restore_using(snapshot: Arc, reader: &R, impl SnapshotCommand { // shared portion of snapshot commands: start the client service - fn start_service(self) -> Result<(ClientService, Arc), String> { - // Setup panic handler - let panic_handler = PanicHandler::new_in_arc(); - + fn start_service(self) -> Result { // load spec file let spec = self.spec.spec()?; @@ -196,12 +191,12 @@ impl SnapshotCommand { Arc::new(Miner::with_spec(&spec)) ).map_err(|e| format!("Client service error: {:?}", e))?; - Ok((service, panic_handler)) + Ok(service) } /// restore from a snapshot pub fn restore(self) -> Result<(), String> { let file = self.file_path.clone(); - let (service, _panic_handler) = self.start_service()?; + let service = self.start_service()?; warn!("Snapshot restoration is experimental and the format may be subject to change."); warn!("On encountering an unexpected error, please ensure that you have a recent snapshot."); @@ -236,7 +231,7 @@ impl SnapshotCommand { let file_path = self.file_path.clone().ok_or("No file path provided.".to_owned())?; let file_path: PathBuf = file_path.into(); let block_at = self.block_at; - let (service, _panic_handler) = self.start_service()?; + let service = self.start_service()?; warn!("Snapshots are currently experimental. File formats may be subject to change."); diff --git a/util/io/src/lib.rs b/util/io/src/lib.rs index 486ec4790..cc3597fb4 100644 --- a/util/io/src/lib.rs +++ b/util/io/src/lib.rs @@ -66,7 +66,6 @@ extern crate parking_lot; mod service; mod worker; -mod panics; use mio::{Token}; use mio::deprecated::{EventLoop, NotifyError}; @@ -137,7 +136,6 @@ pub use service::IoService; pub use service::IoChannel; pub use service::IoManager; pub use service::TOKENS_PER_HANDLER; -pub use panics::{PanicHandler, MayPanic, OnPanicListener, ForwardPanic}; #[cfg(test)] mod tests { @@ -171,5 +169,4 @@ mod tests { let service = IoService::::start().expect("Error creating network service"); service.register_handler(Arc::new(MyHandler)).unwrap(); } - } diff --git a/util/io/src/panics.rs b/util/io/src/panics.rs deleted file mode 100644 index c245abcd4..000000000 --- a/util/io/src/panics.rs +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Panic utilities - -use std::thread; -use std::sync::Arc; -use std::default::Default; - -use parking_lot::Mutex; - -/// Thread-safe closure for handling possible panics -pub trait OnPanicListener: Send + Sync + 'static { - /// Invoke listener - fn call(&mut self, arg: &str); -} - -/// Forwards panics from child -pub trait ForwardPanic { - /// Attach `on_panic` listener to `child` and rethrow all panics - fn forward_from(&self, child: &S) where S : MayPanic; -} - -/// Trait indicating that the structure catches some of the panics (most probably from spawned threads) -/// and it's possbile to be notified when one of the threads panics. -pub trait MayPanic { - /// `closure` will be invoked whenever panic in thread is caught - fn on_panic(&self, closure: F) where F: OnPanicListener; -} - -struct PanicGuard<'a> { - handler: &'a PanicHandler, -} - -impl<'a> Drop for PanicGuard<'a> { - fn drop(&mut self) { - if thread::panicking() { - self.handler.notify_all("Panic!".to_owned()); - } - } -} - -/// Structure that allows to catch panics and notify listeners -pub struct PanicHandler { - listeners: Mutex>> -} - -impl Default for PanicHandler { - fn default() -> Self { - PanicHandler::new() - } -} - -impl PanicHandler { - /// Creates new `PanicHandler` wrapped in `Arc` - pub fn new_in_arc() -> Arc { - Arc::new(Self::new()) - } - - /// Creates new `PanicHandler` - pub fn new() -> Self { - PanicHandler { - listeners: Mutex::new(vec![]) - } - } - - /// Invoke closure and catch any possible panics. - /// In case of panic notifies all listeners about it. - #[cfg_attr(feature="dev", allow(deprecated))] - pub fn catch_panic(&self, g: G) -> thread::Result where G: FnOnce() -> R + Send + 'static { - let _guard = PanicGuard { handler: self }; - let result = g(); - Ok(result) - } - - /// Notifies all listeners in case there is a panic. - /// You should use `catch_panic` instead of calling this method explicitly. - pub fn notify_all(&self, r: String) { - let mut listeners = self.listeners.lock(); - for mut listener in &mut **listeners { - listener.call(&r); - } - } -} - -impl MayPanic for PanicHandler { - fn on_panic(&self, closure: F) where F: OnPanicListener { - self.listeners.lock().push(Box::new(closure)); - } -} - -impl ForwardPanic for Arc { - fn forward_from(&self, child: &S) where S : MayPanic { - let p = self.clone(); - child.on_panic(move |t| p.notify_all(t)); - } -} - -impl OnPanicListener for F - where F: FnMut(String) + Send + Sync + 'static { - fn call(&mut self, arg: &str) { - self(arg.to_owned()) - } -} - -#[test] -#[ignore] // panic forwarding doesnt work on the same thread in beta -fn should_notify_listeners_about_panic () { - use parking_lot::RwLock; - // given - let invocations = Arc::new(RwLock::new(vec![])); - let i = invocations.clone(); - let p = PanicHandler::new(); - p.on_panic(move |t| i.write().push(t)); - - // when - p.catch_panic(|| panic!("Panic!")).unwrap_err(); - - // then - assert!(invocations.read()[0] == "Panic!"); -} - -#[test] -#[ignore] // panic forwarding doesnt work on the same thread in beta -fn should_notify_listeners_about_panic_when_string_is_dynamic () { - use parking_lot::RwLock; - // given - let invocations = Arc::new(RwLock::new(vec![])); - let i = invocations.clone(); - let p = PanicHandler::new(); - p.on_panic(move |t| i.write().push(t)); - - // when - p.catch_panic(|| panic!("Panic: {}", 1)).unwrap_err(); - - // then - assert!(invocations.read()[0] == "Panic: 1"); -} - -#[test] -fn should_notify_listeners_about_panic_in_other_thread () { - use std::thread; - use parking_lot::RwLock; - // given - let invocations = Arc::new(RwLock::new(vec![])); - let i = invocations.clone(); - let p = PanicHandler::new(); - p.on_panic(move |t| i.write().push(t)); - - // when - let t = thread::spawn(move || - p.catch_panic(|| panic!("Panic!")).unwrap() - ); - t.join().unwrap_err(); - - // then - assert!(invocations.read()[0] == "Panic!"); -} - -#[test] -#[ignore] // panic forwarding doesnt work on the same thread in beta -fn should_forward_panics () { - use parking_lot::RwLock; - // given - let invocations = Arc::new(RwLock::new(vec![])); - let i = invocations.clone(); - let p = PanicHandler::new_in_arc(); - p.on_panic(move |t| i.write().push(t)); - - let p2 = PanicHandler::new(); - p.forward_from(&p2); - - // when - p2.catch_panic(|| panic!("Panic!")).unwrap_err(); - - // then - assert!(invocations.read()[0] == "Panic!"); -} diff --git a/util/io/src/service.rs b/util/io/src/service.rs index 0cb4ead5f..baa279cab 100644 --- a/util/io/src/service.rs +++ b/util/io/src/service.rs @@ -24,7 +24,6 @@ use crossbeam::sync::chase_lev; use slab::Slab; use {IoError, IoHandler}; use worker::{Worker, Work, WorkType}; -use panics::*; use parking_lot::{RwLock, Mutex}; use std::sync::{Condvar as SCondvar, Mutex as SMutex}; use std::time::Duration; @@ -191,7 +190,6 @@ pub struct IoManager where Message: Send + Sync { impl IoManager where Message: Send + Sync + Clone + 'static { /// Creates a new instance and registers it with the event loop. pub fn start( - panic_handler: Arc, event_loop: &mut EventLoop>, handlers: Arc>, HandlerId>>> ) -> Result<(), IoError> { @@ -206,7 +204,6 @@ impl IoManager where Message: Send + Sync + Clone + 'static { IoChannel::new(event_loop.channel(), Arc::downgrade(&handlers)), work_ready.clone(), work_ready_mutex.clone(), - panic_handler.clone(), ) ).collect(); @@ -417,37 +414,24 @@ impl IoChannel where Message: Send + Clone + Sync + 'static { /// General IO Service. Starts an event loop and dispatches IO requests. /// 'Message' is a notification message type pub struct IoService where Message: Send + Sync + Clone + 'static { - panic_handler: Arc, thread: Mutex>>, host_channel: Mutex>>, handlers: Arc>, HandlerId>>>, } -impl MayPanic for IoService where Message: Send + Sync + Clone + 'static { - fn on_panic(&self, closure: F) where F: OnPanicListener { - self.panic_handler.on_panic(closure); - } -} - impl IoService where Message: Send + Sync + Clone + 'static { /// Starts IO event loop pub fn start() -> Result, IoError> { - let panic_handler = PanicHandler::new_in_arc(); let mut config = EventLoopBuilder::new(); config.messages_per_tick(1024); let mut event_loop = config.build().expect("Error creating event loop"); let channel = event_loop.channel(); - let panic = panic_handler.clone(); let handlers = Arc::new(RwLock::new(Slab::new(MAX_HANDLERS))); let h = handlers.clone(); let thread = thread::spawn(move || { - let p = panic.clone(); - panic.catch_panic(move || { - IoManager::::start(p, &mut event_loop, h).expect("Error starting IO service"); - }).expect("Error starting panic handler") + IoManager::::start(&mut event_loop, h).expect("Error starting IO service"); }); Ok(IoService { - panic_handler: panic_handler, thread: Mutex::new(Some(thread)), host_channel: Mutex::new(channel), handlers: handlers, diff --git a/util/io/src/worker.rs b/util/io/src/worker.rs index 86e6078f0..79570d361 100644 --- a/util/io/src/worker.rs +++ b/util/io/src/worker.rs @@ -20,7 +20,6 @@ use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use crossbeam::sync::chase_lev; use service::{HandlerId, IoChannel, IoContext}; use IoHandler; -use panics::*; use std::cell::Cell; use std::sync::{Condvar as SCondvar, Mutex as SMutex}; @@ -65,7 +64,6 @@ impl Worker { channel: IoChannel, wait: Arc, wait_mutex: Arc>, - panic_handler: Arc ) -> Worker where Message: Send + Sync + Clone + 'static { let deleting = Arc::new(AtomicBool::new(false)); @@ -78,9 +76,7 @@ impl Worker { worker.thread = Some(thread::Builder::new().stack_size(STACK_SIZE).name(format!("IO Worker #{}", index)).spawn( move || { LOCAL_STACK_SIZE.with(|val| val.set(STACK_SIZE)); - panic_handler.catch_panic(move || { - Worker::work_loop(stealer, channel.clone(), wait, wait_mutex.clone(), deleting) - }).expect("Error starting panic handler") + Worker::work_loop(stealer, channel.clone(), wait, wait_mutex.clone(), deleting) }) .expect("Error creating worker thread")); worker diff --git a/util/network/src/service.rs b/util/network/src/service.rs index 76e21c7f8..d31edadb5 100644 --- a/util/network/src/service.rs +++ b/util/network/src/service.rs @@ -46,7 +46,6 @@ pub struct NetworkService { host_info: String, host: RwLock>>, stats: Arc, - panic_handler: Arc, host_handler: Arc, config: NetworkConfiguration, } @@ -55,9 +54,7 @@ impl NetworkService { /// Starts IO event loop pub fn new(config: NetworkConfiguration) -> Result { let host_handler = Arc::new(HostHandler { public_url: RwLock::new(None) }); - let panic_handler = PanicHandler::new_in_arc(); let io_service = IoService::::start()?; - panic_handler.forward_from(&io_service); let stats = Arc::new(NetworkStats::new()); let host_info = Host::client_version(); @@ -65,7 +62,6 @@ impl NetworkService { io_service: io_service, host_info: host_info, stats: stats, - panic_handler: panic_handler, host: RwLock::new(None), config: config, host_handler: host_handler, @@ -192,9 +188,3 @@ impl NetworkService { host.as_ref().map(|ref host| host.with_context_eval(protocol, &io, action)) } } - -impl MayPanic for NetworkService { - fn on_panic(&self, closure: F) where F: OnPanicListener { - self.panic_handler.on_panic(closure); - } -}