Terminate backup threads when idle (#489)

This commit is contained in:
Stjepan Glavina
2018-07-30 20:48:53 -07:00
committed by Carl Lerche
parent e5b2681513
commit 9352249c3e
2 changed files with 36 additions and 34 deletions
+32 -26
View File
@@ -5,6 +5,7 @@ use std::cell::UnsafeCell;
use std::fmt;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::{self, Acquire, AcqRel, Relaxed};
use std::time::{Duration, Instant};
/// State associated with a thread in the thread pool.
///
@@ -155,7 +156,8 @@ impl Backup {
}
/// Wait for a worker handoff
pub fn wait_for_handoff(&self, sleep: bool) -> Handoff {
pub fn wait_for_handoff(&self, timeout: Option<Duration>) -> Handoff {
let sleep_until = timeout.map(|dur| Instant::now() + dur);
let mut state: State = self.state.load(Acquire).into();
// Run in a loop since there can be spurious wakeups
@@ -169,36 +171,40 @@ impl Backup {
(*self.handoff.get()).take()
.expect("no worker handoff")
};
return Handoff::Worker(worker_id);
}
if sleep {
// TODO: Park with a timeout
self.park.park_sync(None);
// Reload the state
state = self.state.load(Acquire).into();
debug_assert!(state.is_running());
} else {
debug_assert!(state.is_running());
// Transition out of running
let mut next = state;
next.unset_running();
let actual = self.state.compare_and_swap(
state.into(),
next.into(),
AcqRel).into();
if actual == state {
debug_assert!(!next.is_running());
return Handoff::Idle;
match sleep_until {
None => {
self.park.park_sync(None);
state = self.state.load(Acquire).into();
}
Some(when) => {
let now = Instant::now();
state = actual;
if now < when {
self.park.park_sync(Some(when - now));
state = self.state.load(Acquire).into();
} else {
debug_assert!(state.is_running());
// Transition out of running
let mut next = state;
next.unset_running();
let actual = self.state.compare_and_swap(
state.into(),
next.into(),
AcqRel).into();
if actual == state {
debug_assert!(!next.is_running());
return Handoff::Idle;
}
state = actual;
}
}
}
}
}
+4 -8
View File
@@ -417,6 +417,8 @@ impl Pool {
break;
}
debug_assert!(!inner.backup[backup_id.0].is_pushed());
// Push the thread back onto the backup stack. This makes it
// available for future handoffs.
//
@@ -437,20 +439,14 @@ impl Pool {
// Wait for a handoff
let handoff = inner.backup[backup_id.0]
.wait_for_handoff(true);
.wait_for_handoff(inner.config.keep_alive);
match handoff {
Handoff::Worker(id) => {
debug_assert!(inner.backup[backup_id.0].is_running());
worker_id = id;
}
Handoff::Idle => {
// Worker is idle
break;
}
Handoff::Terminated => {
// TODO: When wait_for_handoff supports blocking with a
// timeout, this will have to be smarter
Handoff::Idle | Handoff::Terminated => {
break;
}
}