1 use std::{fmt, usize};
2 
3 /// ThreadPool state.
4 ///
5 /// The two least significant bits are the shutdown flags.  (0 for active, 1 for
6 /// shutdown on idle, 2 for shutting down). The remaining bits represent the
7 /// number of futures that still need to complete.
8 #[derive(Eq, PartialEq, Clone, Copy)]
9 pub(crate) struct State(usize);
10 
11 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
12 #[repr(usize)]
13 pub(crate) enum Lifecycle {
14     /// The thread pool is currently running
15     Running = 0,
16 
17     /// The thread pool should shutdown once it reaches an idle state.
18     ShutdownOnIdle = 1,
19 
20     /// The thread pool should start the process of shutting down.
21     ShutdownNow = 2,
22 }
23 
24 /// Mask used to extract the number of futures from the state
25 const LIFECYCLE_MASK: usize = 0b11;
26 const NUM_FUTURES_MASK: usize = !LIFECYCLE_MASK;
27 const NUM_FUTURES_OFFSET: usize = 2;
28 
29 /// Max number of futures the pool can handle.
30 pub(crate) const MAX_FUTURES: usize = usize::MAX >> NUM_FUTURES_OFFSET;
31 
32 // ===== impl State =====
33 
34 impl State {
35     #[inline]
new() -> State36     pub fn new() -> State {
37         State(0)
38     }
39 
40     /// Returns the number of futures still pending completion.
num_futures(&self) -> usize41     pub fn num_futures(&self) -> usize {
42         self.0 >> NUM_FUTURES_OFFSET
43     }
44 
45     /// Increment the number of futures pending completion.
46     ///
47     /// Returns false on failure.
inc_num_futures(&mut self)48     pub fn inc_num_futures(&mut self) {
49         debug_assert!(self.num_futures() < MAX_FUTURES);
50         debug_assert!(self.lifecycle() < Lifecycle::ShutdownNow);
51 
52         self.0 += 1 << NUM_FUTURES_OFFSET;
53     }
54 
55     /// Decrement the number of futures pending completion.
dec_num_futures(&mut self)56     pub fn dec_num_futures(&mut self) {
57         let num_futures = self.num_futures();
58 
59         if num_futures == 0 {
60             // Already zero
61             return;
62         }
63 
64         self.0 -= 1 << NUM_FUTURES_OFFSET;
65 
66         if self.lifecycle() == Lifecycle::ShutdownOnIdle && num_futures == 1 {
67             self.set_lifecycle(Lifecycle::ShutdownNow);
68         }
69     }
70 
71     /// Set the number of futures pending completion to zero
clear_num_futures(&mut self)72     pub fn clear_num_futures(&mut self) {
73         self.0 = self.0 & LIFECYCLE_MASK;
74     }
75 
lifecycle(&self) -> Lifecycle76     pub fn lifecycle(&self) -> Lifecycle {
77         (self.0 & LIFECYCLE_MASK).into()
78     }
79 
set_lifecycle(&mut self, val: Lifecycle)80     pub fn set_lifecycle(&mut self, val: Lifecycle) {
81         self.0 = (self.0 & NUM_FUTURES_MASK) | (val as usize);
82     }
83 
is_terminated(&self) -> bool84     pub fn is_terminated(&self) -> bool {
85         self.lifecycle() == Lifecycle::ShutdownNow && self.num_futures() == 0
86     }
87 }
88 
89 impl From<usize> for State {
from(src: usize) -> Self90     fn from(src: usize) -> Self {
91         State(src)
92     }
93 }
94 
95 impl From<State> for usize {
from(src: State) -> Self96     fn from(src: State) -> Self {
97         src.0
98     }
99 }
100 
101 impl fmt::Debug for State {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result102     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
103         fmt.debug_struct("pool::State")
104             .field("lifecycle", &self.lifecycle())
105             .field("num_futures", &self.num_futures())
106             .finish()
107     }
108 }
109 
110 // ===== impl Lifecycle =====
111 
112 impl From<usize> for Lifecycle {
from(src: usize) -> Lifecycle113     fn from(src: usize) -> Lifecycle {
114         use self::Lifecycle::*;
115 
116         debug_assert!(
117             src == Running as usize
118                 || src == ShutdownOnIdle as usize
119                 || src == ShutdownNow as usize
120         );
121 
122         unsafe { ::std::mem::transmute(src) }
123     }
124 }
125 
126 impl From<Lifecycle> for usize {
from(src: Lifecycle) -> usize127     fn from(src: Lifecycle) -> usize {
128         let v = src as usize;
129         debug_assert!(v & LIFECYCLE_MASK == v);
130         v
131     }
132 }
133