Files
tokio/tokio-threadpool/src/worker/state.rs
T

159 lines
3.8 KiB
Rust
Raw Normal View History

2018-04-03 22:35:59 -07:00
use std::fmt;
/// Tracks worker state
#[derive(Clone, Copy, Eq, PartialEq)]
2018-04-04 13:30:54 -07:00
pub(crate) struct State(usize);
2018-04-03 22:35:59 -07:00
/// Set when the worker is pushed onto the scheduler's stack of sleeping
/// threads.
pub(crate) const PUSHED_MASK: usize = 0b001;
/// Manages the worker lifecycle part of the state
const LIFECYCLE_MASK: usize = 0b1110;
const LIFECYCLE_SHIFT: usize = 1;
2018-04-04 13:30:54 -07:00
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
2018-04-03 22:35:59 -07:00
#[repr(usize)]
pub(crate) enum Lifecycle {
/// The worker does not currently have an associated thread.
Shutdown = 0 << LIFECYCLE_SHIFT,
/// The worker is currently processing its task.
Running = 1 << LIFECYCLE_SHIFT,
/// The worker is currently asleep in the condvar
Sleeping = 2 << LIFECYCLE_SHIFT,
/// The worker has been notified it should process more work.
Notified = 3 << LIFECYCLE_SHIFT,
/// A stronger form of notification. In this case, the worker is expected to
/// wakeup and try to acquire more work... if it enters this state while
/// already busy with other work, it is expected to signal another worker.
Signaled = 4 << LIFECYCLE_SHIFT,
}
2018-04-04 13:30:54 -07:00
impl State {
2018-04-03 22:35:59 -07:00
/// Returns true if the worker entry is pushed in the sleeper stack
pub fn is_pushed(&self) -> bool {
self.0 & PUSHED_MASK == PUSHED_MASK
}
pub fn set_pushed(&mut self) {
self.0 |= PUSHED_MASK
}
pub fn is_notified(&self) -> bool {
use self::Lifecycle::*;
match self.lifecycle() {
Notified | Signaled => true,
_ => false,
}
}
pub fn lifecycle(&self) -> Lifecycle {
Lifecycle::from(self.0 & LIFECYCLE_MASK)
}
pub fn set_lifecycle(&mut self, val: Lifecycle) {
self.0 = (self.0 & !LIFECYCLE_MASK) | (val as usize)
}
pub fn is_signaled(&self) -> bool {
self.lifecycle() == Lifecycle::Signaled
}
pub fn notify(&mut self) {
use self::Lifecycle::Signaled;
if self.lifecycle() != Signaled {
self.set_lifecycle(Signaled)
}
}
}
2018-04-04 13:30:54 -07:00
impl Default for State {
fn default() -> State {
2018-04-03 22:35:59 -07:00
// All workers will start pushed in the sleeping stack
2018-04-04 13:30:54 -07:00
State(PUSHED_MASK)
2018-04-03 22:35:59 -07:00
}
}
2018-04-04 13:30:54 -07:00
impl From<usize> for State {
2018-04-03 22:35:59 -07:00
fn from(src: usize) -> Self {
2018-04-04 13:30:54 -07:00
State(src)
2018-04-03 22:35:59 -07:00
}
}
2018-04-04 13:30:54 -07:00
impl From<State> for usize {
fn from(src: State) -> Self {
2018-04-03 22:35:59 -07:00
src.0
}
}
2018-04-04 13:30:54 -07:00
impl fmt::Debug for State {
2018-04-03 22:35:59 -07:00
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2018-04-04 13:30:54 -07:00
fmt.debug_struct("worker::State")
2018-04-03 22:35:59 -07:00
.field("lifecycle", &self.lifecycle())
.field("is_pushed", &self.is_pushed())
.finish()
}
}
// ===== impl Lifecycle =====
impl From<usize> for Lifecycle {
fn from(src: usize) -> Lifecycle {
use self::Lifecycle::*;
debug_assert!(
src == Shutdown as usize ||
src == Running as usize ||
src == Sleeping as usize ||
src == Notified as usize ||
src == Signaled as usize);
unsafe { ::std::mem::transmute(src) }
}
}
impl From<Lifecycle> for usize {
fn from(src: Lifecycle) -> usize {
let v = src as usize;
debug_assert!(v & LIFECYCLE_MASK == v);
v
}
}
#[cfg(test)]
mod test {
use super::*;
use super::Lifecycle::*;
#[test]
fn lifecycle_encode() {
let lifecycles = &[
Shutdown,
Running,
Sleeping,
Notified,
Signaled,
];
for &lifecycle in lifecycles {
let mut v: usize = lifecycle.into();
v &= LIFECYCLE_MASK;
assert_eq!(lifecycle, Lifecycle::from(v));
}
}
#[test]
fn lifecycle_ord() {
assert!(Running >= Shutdown);
assert!(Signaled >= Notified);
assert!(Signaled >= Sleeping);
}
}