From 2dc9c23d07864f9d544ac778d732ebd81d44c404 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Mon, 9 Jan 2017 14:56:06 +0100 Subject: [PATCH] fix deadlock in queue drop (#4095) Former-commit-id: 923fc16078834f0c63e245dcb01ee95210bfc7f7 --- ethcore/src/verification/queue/mod.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index d2f96ea80..007c5de92 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -97,7 +97,6 @@ pub struct VerificationQueue { engine: Arc, more_to_verify: Arc, verification: Arc>, - verifiers: Vec>, deleting: Arc, ready_signal: Arc, empty: Arc, @@ -105,6 +104,7 @@ pub struct VerificationQueue { max_queue_size: usize, max_mem_use: usize, total_difficulty: RwLock, + verifier_handles: Vec>, } struct QueueSignal { @@ -186,7 +186,7 @@ impl VerificationQueue { let empty = Arc::new(SCondvar::new()); let panic_handler = PanicHandler::new_in_arc(); - let mut verifiers: Vec> = Vec::new(); + let mut verifier_handles: Vec> = Vec::new(); let thread_count = max(::num_cpus::get(), 3) - 2; for i in 0..thread_count { let verification = verification.clone(); @@ -196,7 +196,7 @@ impl VerificationQueue { let empty = empty.clone(); let deleting = deleting.clone(); let panic_handler = panic_handler.clone(); - verifiers.push( + verifier_handles.push( thread::Builder::new() .name(format!("Verifier #{}", i)) .spawn(move || { @@ -213,13 +213,13 @@ impl VerificationQueue { ready_signal: ready_signal.clone(), more_to_verify: more_to_verify.clone(), verification: verification.clone(), - verifiers: verifiers, deleting: deleting.clone(), processing: RwLock::new(HashMap::new()), empty: empty.clone(), max_queue_size: max(config.max_queue_size, MIN_QUEUE_LIMIT), max_mem_use: max(config.max_mem_use, MIN_MEM_LIMIT), total_difficulty: RwLock::new(0.into()), + verifier_handles: verifier_handles, } } @@ -531,8 +531,15 @@ impl Drop for VerificationQueue { trace!(target: "shutdown", "[VerificationQueue] Closing..."); self.clear(); self.deleting.store(true, AtomicOrdering::Release); - self.more_to_verify.notify_all(); - for t in self.verifiers.drain(..) { + + // acquire this lock to force threads to reach the waiting point + // if they're in-between the exit check and the more_to_verify wait. + { + let _more = self.verification.more_to_verify.lock().unwrap(); + self.more_to_verify.notify_all(); + } + + for t in self.verifier_handles.drain(..) { t.join().unwrap(); } trace!(target: "shutdown", "[VerificationQueue] Closed.");