11use core:: fmt;
22use core:: cell:: UnsafeCell ;
33use core:: sync:: atomic:: AtomicUsize ;
4- use core:: sync:: atomic:: Ordering :: { Acquire , Release , AcqRel , SeqCst } ;
4+ use core:: sync:: atomic:: Ordering :: { Acquire , Release , AcqRel } ;
55use crate :: task:: { LocalWaker , Waker } ;
66
77/// A synchronization primitive for task wakeup.
@@ -124,53 +124,14 @@ pub struct AtomicWaker {
124124// Thread A still holds the `wake` lock, the call to `register` will result
125125// in the task waking itself and get scheduled again.
126126
127- /// Idle state empty
128- const EMPTY : usize = 0 ;
129-
130- /// Idle state with a waker in the cell
131- const HOLDS : usize = 0b100 ;
127+ /// Idle state
128+ const WAITING : usize = 0 ;
132129
133130/// A new waker value is being registered with the `AtomicWaker` cell.
134- const REGISTERING : usize = 0b001 ;
131+ const REGISTERING : usize = 0b01 ;
135132
136133/// The waker currently registered with the `AtomicWaker` cell is being woken.
137- const WAKING : usize = 0b010 ;
138-
139- // State transition diagram
140- // Can be viewed/edited with service like this:
141- // https://dreampuf.github.io/GraphvizOnline/
142- /*
143-
144- digraph G {
145- // Any fixed-width font will do
146- node [fontname=Monaco];
147-
148- // Solid lines are transitions on function enter
149- // and dashed lines are second transitions in a function call.
150- // (There are at most two transitions per function call).
151-
152- // register thread state transitions are red
153- "EMPTY" -> "REGISTERING" [color=red];
154- "HOLDS" -> "REGISTERING" [color=red];
155- "REGISTERING" -> "HOLDS" [color=red style=dashed];
156- "REGISTERING|WAKING" -> "EMPTY" [color=red style=dashed];
157-
158- // wake thread state transitions are blue
159- "REGISTERING" -> "REGISTERING|WAKING" [color=blue];
160- "EMPTY" -> "WAKING" [color=blue];
161- "HOLDS" -> "WAKING|HOLDS" [color=blue];
162- "WAKING|HOLDS" -> "EMPTY" [color=blue style=dashed];
163- "WAKING" -> "EMPTY" [color=blue style=dashed];
164-
165- // intermediate states (when at least one process is running)
166- "REGISTERING|WAKING" [style=dashed];
167- "WAKING|HOLDS" [style=dashed];
168- "WAKING" [style=dashed];
169- "REGISTERING" [style=dashed];
170- }
171-
172- */
173-
134+ const WAKING : usize = 0b10 ;
174135
175136impl AtomicWaker {
176137 /// Create an `AtomicWaker`.
@@ -180,7 +141,7 @@ impl AtomicWaker {
180141 impl AssertSync for Waker { }
181142
182143 AtomicWaker {
183- state : AtomicUsize :: new ( EMPTY ) ,
144+ state : AtomicUsize :: new ( WAITING ) ,
184145 waker : UnsafeCell :: new ( None ) ,
185146 }
186147 }
@@ -237,66 +198,63 @@ impl AtomicWaker {
237198 /// }
238199 /// ```
239200 pub fn register ( & self , lw : & LocalWaker ) {
240- let state = self . state . load ( SeqCst ) ;
241- if ( state == EMPTY || state == HOLDS )
242- && self . state . compare_and_swap ( state, REGISTERING , Acquire ) == state
243- {
244- return unsafe {
245- debug_assert_eq ! ( state == HOLDS , ( * self . waker. get( ) ) . is_some( ) ) ;
246-
247- // Locked acquired, update the waker cell
248- * self . waker . get ( ) = Some ( lw. clone ( ) . into_waker ( ) ) ;
249-
250- // Release the lock. If the state transitioned to include
251- // the `WAKING` bit, this means that a wake has been
252- // called concurrently, so we have to remove the waker and
253- // wake it.`
254- //
255- // Start by assuming that the state is `REGISTERING` as this
256- // is what we jut set it to.
257- let res = self . state . compare_exchange (
258- REGISTERING , HOLDS , AcqRel , Acquire ) ;
259-
260- match res {
261- Ok ( _) => { }
262- Err ( actual) => {
263- // This branch can only be reached if a
264- // concurrent thread called `wake`. In this
265- // case, `actual` **must** be `REGISTERING |
266- // `WAKING`.
267- debug_assert_eq ! ( actual, REGISTERING | WAKING ) ;
268-
269- // Take the waker to wake once the atomic operation has
270- // completed.
271- let waker = ( * self . waker . get ( ) ) . take ( ) . unwrap ( ) ;
272-
273- // Just swap, because no one could change state while state == `REGISTERING` | `WAKING`.
274- self . state . swap ( EMPTY , AcqRel ) ;
275-
276- // The atomic swap was complete, now
277- // wake the task and return.
278- waker. wake ( ) ;
201+ match self . state . compare_and_swap ( WAITING , REGISTERING , Acquire ) {
202+ WAITING => {
203+ unsafe {
204+ // Locked acquired, update the waker cell
205+ * self . waker . get ( ) = Some ( lw. clone ( ) . into_waker ( ) ) ;
206+
207+ // Release the lock. If the state transitioned to include
208+ // the `WAKING` bit, this means that a wake has been
209+ // called concurrently, so we have to remove the waker and
210+ // wake it.`
211+ //
212+ // Start by assuming that the state is `REGISTERING` as this
213+ // is what we jut set it to.
214+ let res = self . state . compare_exchange (
215+ REGISTERING , WAITING , AcqRel , Acquire ) ;
216+
217+ match res {
218+ Ok ( _) => { }
219+ Err ( actual) => {
220+ // This branch can only be reached if a
221+ // concurrent thread called `wake`. In this
222+ // case, `actual` **must** be `REGISTERING |
223+ // `WAKING`.
224+ debug_assert_eq ! ( actual, REGISTERING | WAKING ) ;
225+
226+ // Take the waker to wake once the atomic operation has
227+ // completed.
228+ let waker = ( * self . waker . get ( ) ) . take ( ) . unwrap ( ) ;
229+
230+ // Just swap, because no one could change state while state == `REGISTERING` | `WAKING`.
231+ self . state . swap ( WAITING , AcqRel ) ;
232+
233+ // The atomic swap was complete, now
234+ // wake the task and return.
235+ waker. wake ( ) ;
236+ }
279237 }
280238 }
281239 }
282- }
283-
284- if state == WAKING || state == WAKING | HOLDS || state == EMPTY || state == HOLDS {
285- // Currently in the process of waking the task, i.e.,
286- // `wake` is currently being called on the old task handle.
287- // So, we call wake on the new waker
288- lw . wake ( ) ;
289- } else {
290- // In this case, a concurrent thread is holding the
291- // "registering" lock. This probably indicates a bug in the
292- // caller's code as racing to call `register` doesn't make much
293- // sense.
294- //
295- // We just want to maintain memory safety. It is ok to drop the
296- // call to `register`.
297- debug_assert ! (
298- state == REGISTERING ||
299- state == REGISTERING | WAKING ) ;
240+ WAKING => {
241+ // Currently in the process of waking the task, i.e.,
242+ // `wake` is currently being called on the old task handle.
243+ // So, we call wake on the new waker
244+ lw . wake ( ) ;
245+ }
246+ state => {
247+ // In this case, a concurrent thread is holding the
248+ // "registering" lock. This probably indicates a bug in the
249+ // caller's code as racing to call `register` doesn't make much
250+ // sense.
251+ //
252+ // We just want to maintain memory safety. It is ok to drop the
253+ // call to `register`.
254+ debug_assert ! (
255+ state == REGISTERING ||
256+ state == REGISTERING | WAKING ) ;
257+ }
300258 }
301259 }
302260
@@ -318,27 +276,16 @@ impl AtomicWaker {
318276 ///
319277 /// If a waker has not been registered, this returns `None`.
320278 pub fn take ( & self ) -> Option < Waker > {
321- let state = self . state . load ( SeqCst ) ;
322-
323- if state == EMPTY || state & WAKING != 0 {
324- // One of:
325- // * no waker inside, nothing to take
326- // * another process is calling wake now
327- return None ;
328- }
329-
330279 // AcqRel ordering is used in order to acquire the value of the `task`
331280 // cell as well as to establish a `release` ordering with whatever
332281 // memory the `AtomicWaker` is associated with.
333- let state = self . state . fetch_or ( WAKING , AcqRel ) ;
334- match state {
335- EMPTY | HOLDS => {
282+ match self . state . fetch_or ( WAKING , AcqRel ) {
283+ WAITING => {
336284 // The waking lock has been acquired.
337285 let waker = unsafe { ( * self . waker . get ( ) ) . take ( ) } ;
338- debug_assert_eq ! ( state == HOLDS , waker. is_some( ) ) ;
339286
340287 // Release the lock
341- self . state . fetch_and ( !( WAKING | HOLDS ) , Release ) ;
288+ self . state . fetch_and ( !WAKING , Release ) ;
342289
343290 waker
344291 }
@@ -353,9 +300,7 @@ impl AtomicWaker {
353300 debug_assert ! (
354301 state == REGISTERING ||
355302 state == REGISTERING | WAKING ||
356- state == WAKING ||
357- state == WAKING | HOLDS ) ;
358-
303+ state == WAKING ) ;
359304 None
360305 }
361306 }
0 commit comments