diff --git a/Cargo.lock b/Cargo.lock index a6fa12b3a..6597c44a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,7 +24,7 @@ dependencies = [ "ethcore-stratum 1.4.0", "ethcore-util 1.5.0", "ethsync 1.5.0", - "fdlimit 0.1.0", + "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", "isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -684,7 +684,8 @@ dependencies = [ [[package]] name = "fdlimit" -version = "0.1.0" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1270,7 +1271,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#7700411d2b0ba1372e0d6cf72a84ecf873a181f3" +source = "git+https://github.com/ethcore/js-precompiled.git#3cf6c68b7d08be71d12ff142e255a42043e50c75" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2027,6 +2028,7 @@ dependencies = [ "checksum env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aba65b63ffcc17ffacd6cf5aa843da7c5a25e3bd4bbe0b7def8b214e411250e5" "checksum eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)" = "" "checksum ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0c53453517f620847be51943db329276ae52f2e210cfc659e81182864be2f" +"checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "3eeb481e957304178d2e782f2da1257f1434dfecbae883bafb61ada2a9fea3bb" "checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" diff --git a/Cargo.toml b/Cargo.toml index e0e4df2e9..078d2916c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ serde = "0.8.0" serde_json = "0.8.0" hyper = { version = "0.9", default-features = false } ctrlc = { git = "https://github.com/ethcore/rust-ctrlc.git" } -fdlimit = { path = "util/fdlimit" } +fdlimit = "0.1" ethcore = { path = "ethcore" } ethcore-util = { path = "util" } ethsync = { path = "sync" } diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index 686a1d093..14df0819c 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -17,7 +17,7 @@ //! A queue of blocks. Sits between network or other I/O and the `BlockChain`. //! Sorts them ready for blockchain insertion. -use std::thread::{JoinHandle, self}; +use std::thread::{self, JoinHandle}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrdering}; use std::sync::{Condvar as SCondvar, Mutex as SMutex}; use util::*; @@ -64,35 +64,11 @@ impl Default for Config { } } -struct VerifierHandle { - deleting: Arc, - sleep: Arc, - thread: JoinHandle<()>, -} - -impl VerifierHandle { - // signal to the verifier thread that it should sleep. - fn sleep(&self) { - self.sleep.store(true, AtomicOrdering::SeqCst); - } - - // signal to the verifier thread that it should wake up. - fn wake_up(&self) { - self.sleep.store(false, AtomicOrdering::SeqCst); - self.thread.thread().unpark(); - } - - // signal to the verifier thread that it should conclude its - // operations. - fn conclude(&self) { - self.wake_up(); - self.deleting.store(true, AtomicOrdering::Release); - } - - // join the verifier thread. - fn join(self) { - self.thread.join().expect("Verifier thread panicked"); - } +// pool states +enum State { + // all threads with id < inner value are to work. + Work(usize), + Exit, } /// An item which is in the process of being verified. @@ -131,7 +107,6 @@ pub struct VerificationQueue { engine: Arc, more_to_verify: Arc, verification: Arc>, - verifiers: Mutex<(Vec, usize)>, deleting: Arc, ready_signal: Arc, empty: Arc, @@ -139,6 +114,8 @@ pub struct VerificationQueue { ticks_since_adjustment: AtomicUsize, max_queue_size: usize, max_mem_use: usize, + verifier_handles: Vec>, + state: Arc<(Mutex, Condvar)>, } struct QueueSignal { @@ -224,40 +201,39 @@ impl VerificationQueue { let max_verifiers = min(::num_cpus::get(), MAX_VERIFIERS); let default_amount = max(::num_cpus::get(), 3) - 2; - let mut verifiers = Vec::with_capacity(max_verifiers); + let state = Arc::new((Mutex::new(State::Work(default_amount)), Condvar::new())); + let mut verifier_handles = Vec::with_capacity(max_verifiers); debug!(target: "verification", "Allocating {} verifiers, {} initially active", max_verifiers, default_amount); for i in 0..max_verifiers { debug!(target: "verification", "Adding verification thread #{}", i); - let deleting = deleting.clone(); let panic_handler = panic_handler.clone(); let verification = verification.clone(); let engine = engine.clone(); let wait = more_to_verify.clone(); let ready = ready_signal.clone(); let empty = empty.clone(); + let state = state.clone(); - // enable only the first few verifiers. - let sleep = if i < default_amount { - Arc::new(AtomicBool::new(false)) - } else { - Arc::new(AtomicBool::new(true)) - }; - - verifiers.push(VerifierHandle { - deleting: deleting.clone(), - sleep: sleep.clone(), - thread: thread::Builder::new() - .name(format!("Verifier #{}", i)) - .spawn(move || { - panic_handler.catch_panic(move || { - VerificationQueue::verify(verification, engine, wait, ready, deleting, empty, sleep) - }).unwrap() - }) - .expect("Failed to create verifier thread.") - }); + 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() + }) + .expect("Failed to create verifier thread."); + verifier_handles.push(handle); } VerificationQueue { @@ -266,13 +242,14 @@ impl VerificationQueue { ready_signal: ready_signal, more_to_verify: more_to_verify, verification: verification, - verifiers: Mutex::new((verifiers, default_amount)), deleting: deleting, processing: RwLock::new(HashSet::new()), empty: empty, ticks_since_adjustment: AtomicUsize::new(0), max_queue_size: max(config.max_queue_size, MIN_QUEUE_LIMIT), max_mem_use: max(config.max_mem_use, MIN_MEM_LIMIT), + verifier_handles: verifier_handles, + state: state, } } @@ -281,23 +258,30 @@ impl VerificationQueue { engine: Arc, wait: Arc, ready: Arc, - deleting: Arc, empty: Arc, - sleep: Arc, + state: Arc<(Mutex, Condvar)>, + id: usize, ) { - while !deleting.load(AtomicOrdering::Acquire) { + loop { + // check current state. { - while sleep.load(AtomicOrdering::SeqCst) { - trace!(target: "verification", "Verifier sleeping"); - ::std::thread::park(); - trace!(target: "verification", "Verifier waking up"); + let mut cur_state = state.0.lock(); + while let State::Work(x) = *cur_state { + // sleep until this thread is required. + if id < x { break } - if deleting.load(AtomicOrdering::Acquire) { - return; - } + debug!(target: "verification", "verifier {} sleeping", id); + state.1.wait(&mut cur_state); + debug!(target: "verification", "verifier {} waking up", id); + } + + if let State::Exit = *cur_state { + debug!(target: "verification", "verifier {} exiting", id); + break; } } + // wait for work if empty. { let mut more_to_verify = verification.more_to_verify.lock().unwrap(); @@ -305,15 +289,22 @@ impl VerificationQueue { empty.notify_all(); } - while verification.unverified.lock().is_empty() && !deleting.load(AtomicOrdering::Acquire) { + while verification.unverified.lock().is_empty() { + if let State::Exit = *state.0.lock() { + debug!(target: "verification", "verifier {} exiting", id); + return; + } + more_to_verify = wait.wait(more_to_verify).unwrap(); } - if deleting.load(AtomicOrdering::Acquire) { + if let State::Exit = *state.0.lock() { + debug!(target: "verification", "verifier {} exiting", id); return; } } + // do work. let item = { // acquire these locks before getting the item to verify. let mut unverified = verification.unverified.lock(); @@ -568,6 +559,14 @@ impl VerificationQueue { } } + /// Get the current number of working verifiers. + pub fn num_verifiers(&self) -> usize { + match *self.state.0.lock() { + State::Work(x) => x, + State::Exit => panic!("state only set to exit on drop; queue live now; qed"), + } + } + /// Optimise memory footprint of the heap fields, and adjust the number of threads /// to better suit the workload. pub fn collect_garbage(&self) { @@ -604,7 +603,7 @@ impl VerificationQueue { return; } - let current = self.verifiers.lock().1; + let current = self.num_verifiers(); let diff = (v_len - u_len).abs(); let total = v_len + u_len; @@ -626,27 +625,14 @@ impl VerificationQueue { // possible, never going over the amount of initially allocated threads // or below 1. fn scale_verifiers(&self, target: usize) { - let mut verifiers = self.verifiers.lock(); - let &mut (ref mut verifiers, ref mut verifier_count) = &mut *verifiers; - - let target = min(verifiers.len(), target); + let current = self.num_verifiers(); + let target = min(self.verifier_handles.len(), target); let target = max(1, target); - debug!(target: "verification", "Scaling from {} to {} verifiers", verifier_count, target); + debug!(target: "verification", "Scaling from {} to {} verifiers", current, target); - // scaling up - for i in *verifier_count..target { - debug!(target: "verification", "Waking up verifier {}", i); - verifiers[i].wake_up(); - } - - // scaling down. - for i in target..*verifier_count { - debug!(target: "verification", "Putting verifier {} to sleep", i); - verifiers[i].sleep(); - } - - *verifier_count = target; + *self.state.0.lock() = State::Work(target); + self.state.1.notify_all(); } } @@ -660,22 +646,18 @@ impl Drop for VerificationQueue { fn drop(&mut self) { trace!(target: "shutdown", "[VerificationQueue] Closing..."); self.clear(); - self.deleting.store(true, AtomicOrdering::Release); + self.deleting.store(true, AtomicOrdering::SeqCst); - let mut verifiers = self.verifiers.get_mut(); - let mut verifiers = &mut verifiers.0; - - // first pass to signal conclusion. must be done before - // notify or deadlock possible. - for handle in verifiers.iter() { - handle.conclude(); - } + // set exit state; should be done before `more_to_verify` notification. + *self.state.0.lock() = State::Exit; + self.state.1.notify_all(); + // wake up all threads waiting for more work. self.more_to_verify.notify_all(); - // second pass to join. - for handle in verifiers.drain(..) { - handle.join(); + // wait for all verifier threads to join. + for thread in self.verifier_handles.drain(..) { + thread.join().expect("Propagating verifier thread panic on shutdown"); } trace!(target: "shutdown", "[VerificationQueue] Closed."); @@ -687,7 +669,7 @@ mod tests { use util::*; use io::*; use spec::*; - use super::{BlockQueue, Config}; + use super::{BlockQueue, Config, State}; use super::kind::blocks::Unverified; use tests::helpers::*; use error::*; @@ -784,11 +766,11 @@ mod tests { let queue = get_test_queue(); queue.scale_verifiers(MAX_VERIFIERS + 1); - assert!(queue.verifiers.lock().1 < MAX_VERIFIERS + 1); + assert!(queue.num_verifiers() < MAX_VERIFIERS + 1); queue.scale_verifiers(0); - assert!(queue.verifiers.lock().1 == 1); + assert!(queue.num_verifiers() == 1); } #[test] @@ -797,14 +779,7 @@ mod tests { // put all the verifiers to sleep to ensure // the test isn't timing sensitive. - let num_verifiers = { - let verifiers = queue.verifiers.lock(); - for i in 0..verifiers.1 { - verifiers.0[i].sleep(); - } - - verifiers.1 - }; + *queue.state.0.lock() = State::Work(0); for block in get_good_dummy_block_seq(5000) { queue.import(Unverified::new(block)).expect("Block good by definition; qed"); @@ -812,20 +787,12 @@ mod tests { // almost all unverified == bump verifier count. queue.collect_garbage(); - assert_eq!(queue.verifiers.lock().1, num_verifiers + 1); - - // wake them up again and verify everything. - { - let verifiers = queue.verifiers.lock(); - for i in 0..verifiers.1 { - verifiers.0[i].wake_up(); - } - } + assert_eq!(queue.num_verifiers(), 1); queue.flush(); // nothing to verify == use minimum number of verifiers. queue.collect_garbage(); - assert_eq!(queue.verifiers.lock().1, 1); + assert_eq!(queue.num_verifiers(), 1); } } diff --git a/js/package.json b/js/package.json index 5341cee31..42836bb7c 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "0.2.91", + "version": "0.2.92", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", diff --git a/js/src/ui/MethodDecoding/methodDecoding.js b/js/src/ui/MethodDecoding/methodDecoding.js index 70258f744..efb22b67b 100644 --- a/js/src/ui/MethodDecoding/methodDecoding.js +++ b/js/src/ui/MethodDecoding/methodDecoding.js @@ -457,6 +457,14 @@ class MethodDecoding extends Component { return; } + const { signature, paramdata } = api.util.decodeCallData(input); + this.setState({ methodSignature: signature, methodParams: paramdata }); + + if (!signature || signature === CONTRACT_CREATE || transaction.creates) { + this.setState({ isDeploy: true }); + return; + } + if (contractAddress === '0x') { return; } @@ -472,14 +480,6 @@ class MethodDecoding extends Component { return; } - const { signature, paramdata } = api.util.decodeCallData(input); - this.setState({ methodSignature: signature, methodParams: paramdata }); - - if (!signature || signature === CONTRACT_CREATE || transaction.creates) { - this.setState({ isDeploy: true }); - return; - } - return Contracts.get() .signatureReg .lookup(signature) diff --git a/util/fdlimit/Cargo.toml b/util/fdlimit/Cargo.toml deleted file mode 100644 index 42aa582fe..000000000 --- a/util/fdlimit/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -description = "Utility function to raise file descriptor limit on OS X" -homepage = "http://ethcore.io" -license = "GPL-3.0" -name = "fdlimit" -version = "0.1.0" -authors = ["Ethcore "] - -[dependencies] -libc = "0.2" diff --git a/util/fdlimit/src/lib.rs b/util/fdlimit/src/lib.rs deleted file mode 100644 index 92c403058..000000000 --- a/util/fdlimit/src/lib.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015, 2016 Ethcore (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 .extern crate libc; - -extern crate libc; -mod raise_fd_limit; -pub use raise_fd_limit::raise_fd_limit; diff --git a/util/fdlimit/src/raise_fd_limit.rs b/util/fdlimit/src/raise_fd_limit.rs deleted file mode 100644 index d0539fda9..000000000 --- a/util/fdlimit/src/raise_fd_limit.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// darwin_fd_limit exists to work around an issue where launchctl on Mac OS X -/// defaults the rlimit maxfiles to 256/unlimited. The default soft limit of 256 -/// ends up being far too low for our multithreaded scheduler testing, depending -/// on the number of cores available. -/// -#[cfg(any(target_os = "macos", target_os = "ios"))] -#[allow(non_camel_case_types)] -pub fn raise_fd_limit() { - use libc; - use std::cmp; - use std::io; - use std::mem::size_of_val; - use std::ptr::null_mut; - - unsafe { - static CTL_KERN: libc::c_int = 1; - static KERN_MAXFILESPERPROC: libc::c_int = 29; - - // The strategy here is to fetch the current resource limits, read the - // kern.maxfilesperproc sysctl value, and bump the soft resource limit for - // maxfiles up to the sysctl value. - - // Fetch the kern.maxfilesperproc value - let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC]; - let mut maxfiles: libc::c_int = 0; - let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t; - if libc::sysctl(&mut mib[0], 2, &mut maxfiles as *mut _ as *mut _, &mut size, - null_mut(), 0) != 0 { - let err = io::Error::last_os_error(); - panic!("raise_fd_limit: error calling sysctl: {}", err); - } - - // Fetch the current resource limits - let mut rlim = libc::rlimit{rlim_cur: 0, rlim_max: 0}; - if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 { - let err = io::Error::last_os_error(); - panic!("raise_fd_limit: error calling getrlimit: {}", err); - } - - // Bump the soft limit to the smaller of kern.maxfilesperproc and the hard - // limit - rlim.rlim_cur = cmp::min(maxfiles as libc::rlim_t, rlim.rlim_max); - - // Set our newly-increased resource limit - if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 { - let err = io::Error::last_os_error(); - panic!("raise_fd_limit: error calling setrlimit: {}", err); - } - } -} - -#[cfg(any(target_os = "linux"))] -#[allow(non_camel_case_types)] -pub fn raise_fd_limit() { - use libc; - use std::io; - - unsafe { - // Fetch the current resource limits - let mut rlim = libc::rlimit{rlim_cur: 0, rlim_max: 0}; - if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 { - let err = io::Error::last_os_error(); - panic!("raise_fd_limit: error calling getrlimit: {}", err); - } - - // Set soft limit to hard imit - rlim.rlim_cur = rlim.rlim_max; - - // Set our newly-increased resource limit - if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 { - let err = io::Error::last_os_error(); - panic!("raise_fd_limit: error calling setrlimit: {}", err); - } - } -} - -#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))] -pub fn raise_fd_limit() {}