1 use std::fmt; 2 3 /// Tracks worker state 4 #[derive(Clone, Copy, Eq, PartialEq)] 5 pub(crate) struct State(usize); 6 7 /// Set when the worker is pushed onto the scheduler's stack of sleeping 8 /// threads. 9 pub(crate) const PUSHED_MASK: usize = 0b001; 10 11 /// Manages the worker lifecycle part of the state 12 const LIFECYCLE_MASK: usize = 0b1110; 13 const LIFECYCLE_SHIFT: usize = 1; 14 15 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] 16 #[repr(usize)] 17 pub(crate) enum Lifecycle { 18 /// The worker does not currently have an associated thread. 19 Shutdown = 0 << LIFECYCLE_SHIFT, 20 21 /// The worker is doing work 22 Running = 1 << LIFECYCLE_SHIFT, 23 24 /// The worker is currently asleep in the condvar 25 Sleeping = 2 << LIFECYCLE_SHIFT, 26 27 /// The worker has been notified it should process more work. 28 Notified = 3 << LIFECYCLE_SHIFT, 29 30 /// A stronger form of notification. In this case, the worker is expected to 31 /// wakeup and try to acquire more work... if it enters this state while 32 /// already busy with other work, it is expected to signal another worker. 33 Signaled = 4 << LIFECYCLE_SHIFT, 34 } 35 36 impl State { 37 /// Returns true if the worker entry is pushed in the sleeper stack is_pushed(&self) -> bool38 pub fn is_pushed(&self) -> bool { 39 self.0 & PUSHED_MASK == PUSHED_MASK 40 } 41 set_pushed(&mut self)42 pub fn set_pushed(&mut self) { 43 self.0 |= PUSHED_MASK 44 } 45 is_notified(&self) -> bool46 pub fn is_notified(&self) -> bool { 47 use self::Lifecycle::*; 48 49 match self.lifecycle() { 50 Notified | Signaled => true, 51 _ => false, 52 } 53 } 54 lifecycle(&self) -> Lifecycle55 pub fn lifecycle(&self) -> Lifecycle { 56 Lifecycle::from(self.0 & LIFECYCLE_MASK) 57 } 58 set_lifecycle(&mut self, val: Lifecycle)59 pub fn set_lifecycle(&mut self, val: Lifecycle) { 60 self.0 = (self.0 & !LIFECYCLE_MASK) | (val as usize) 61 } 62 is_signaled(&self) -> bool63 pub fn is_signaled(&self) -> bool { 64 self.lifecycle() == Lifecycle::Signaled 65 } 66 notify(&mut self)67 pub fn notify(&mut self) { 68 use self::Lifecycle::Signaled; 69 70 if self.lifecycle() != Signaled { 71 self.set_lifecycle(Signaled) 72 } 73 } 74 } 75 76 impl Default for State { default() -> State77 fn default() -> State { 78 // All workers will start pushed in the sleeping stack 79 State(PUSHED_MASK) 80 } 81 } 82 83 impl From<usize> for State { from(src: usize) -> Self84 fn from(src: usize) -> Self { 85 State(src) 86 } 87 } 88 89 impl From<State> for usize { from(src: State) -> Self90 fn from(src: State) -> Self { 91 src.0 92 } 93 } 94 95 impl fmt::Debug for State { fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result96 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 97 fmt.debug_struct("worker::State") 98 .field("lifecycle", &self.lifecycle()) 99 .field("is_pushed", &self.is_pushed()) 100 .finish() 101 } 102 } 103 104 // ===== impl Lifecycle ===== 105 106 impl From<usize> for Lifecycle { from(src: usize) -> Lifecycle107 fn from(src: usize) -> Lifecycle { 108 use self::Lifecycle::*; 109 110 debug_assert!( 111 src == Shutdown as usize 112 || src == Running as usize 113 || src == Sleeping as usize 114 || src == Notified as usize 115 || src == Signaled as usize 116 ); 117 118 unsafe { ::std::mem::transmute(src) } 119 } 120 } 121 122 impl From<Lifecycle> for usize { from(src: Lifecycle) -> usize123 fn from(src: Lifecycle) -> usize { 124 let v = src as usize; 125 debug_assert!(v & LIFECYCLE_MASK == v); 126 v 127 } 128 } 129 130 #[cfg(test)] 131 mod test { 132 use super::Lifecycle::*; 133 use super::*; 134 135 #[test] lifecycle_encode()136 fn lifecycle_encode() { 137 let lifecycles = &[Shutdown, Running, Sleeping, Notified, Signaled]; 138 139 for &lifecycle in lifecycles { 140 let mut v: usize = lifecycle.into(); 141 v &= LIFECYCLE_MASK; 142 143 assert_eq!(lifecycle, Lifecycle::from(v)); 144 } 145 } 146 147 #[test] lifecycle_ord()148 fn lifecycle_ord() { 149 assert!(Running >= Shutdown); 150 assert!(Signaled >= Notified); 151 assert!(Signaled >= Sleeping); 152 } 153 } 154