1
1
use core:: fmt;
2
2
use core:: cell:: UnsafeCell ;
3
3
use core:: sync:: atomic:: AtomicUsize ;
4
- use core:: sync:: atomic:: Ordering :: { Acquire , Release , AcqRel , SeqCst } ;
4
+ use core:: sync:: atomic:: Ordering :: { Acquire , Release , AcqRel } ;
5
5
use crate :: task:: { LocalWaker , Waker } ;
6
6
7
7
/// A synchronization primitive for task wakeup.
@@ -124,53 +124,14 @@ pub struct AtomicWaker {
124
124
// Thread A still holds the `wake` lock, the call to `register` will result
125
125
// in the task waking itself and get scheduled again.
126
126
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 ;
132
129
133
130
/// A new waker value is being registered with the `AtomicWaker` cell.
134
- const REGISTERING : usize = 0b001 ;
131
+ const REGISTERING : usize = 0b01 ;
135
132
136
133
/// 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 ;
174
135
175
136
impl AtomicWaker {
176
137
/// Create an `AtomicWaker`.
@@ -180,7 +141,7 @@ impl AtomicWaker {
180
141
impl AssertSync for Waker { }
181
142
182
143
AtomicWaker {
183
- state : AtomicUsize :: new ( EMPTY ) ,
144
+ state : AtomicUsize :: new ( WAITING ) ,
184
145
waker : UnsafeCell :: new ( None ) ,
185
146
}
186
147
}
@@ -237,66 +198,63 @@ impl AtomicWaker {
237
198
/// }
238
199
/// ```
239
200
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
+ }
279
237
}
280
238
}
281
239
}
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
+ }
300
258
}
301
259
}
302
260
@@ -318,27 +276,16 @@ impl AtomicWaker {
318
276
///
319
277
/// If a waker has not been registered, this returns `None`.
320
278
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
-
330
279
// AcqRel ordering is used in order to acquire the value of the `task`
331
280
// cell as well as to establish a `release` ordering with whatever
332
281
// 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 => {
336
284
// The waking lock has been acquired.
337
285
let waker = unsafe { ( * self . waker . get ( ) ) . take ( ) } ;
338
- debug_assert_eq ! ( state == HOLDS , waker. is_some( ) ) ;
339
286
340
287
// Release the lock
341
- self . state . fetch_and ( !( WAKING | HOLDS ) , Release ) ;
288
+ self . state . fetch_and ( !WAKING , Release ) ;
342
289
343
290
waker
344
291
}
@@ -353,9 +300,7 @@ impl AtomicWaker {
353
300
debug_assert ! (
354
301
state == REGISTERING ||
355
302
state == REGISTERING | WAKING ||
356
- state == WAKING ||
357
- state == WAKING | HOLDS ) ;
358
-
303
+ state == WAKING ) ;
359
304
None
360
305
}
361
306
}
0 commit comments