1
1
use super :: { Notify , SetError } ;
2
- use crate :: loom:: cell:: UnsafeCell ;
2
+ use crate :: { loom:: cell:: UnsafeCell , pin } ;
3
3
use std:: fmt;
4
4
use std:: mem:: MaybeUninit ;
5
5
use std:: ops:: Drop ;
6
6
use std:: ptr;
7
7
use std:: sync:: atomic:: { AtomicBool , Ordering } ;
8
+ use std:: sync:: Mutex ;
8
9
9
10
// This file contains an implementation of an SetOnce. The value of SetOnce
10
11
// can only be modified once during initialization.
@@ -73,6 +74,9 @@ pub struct SetOnce<T> {
73
74
value_set : AtomicBool ,
74
75
value : UnsafeCell < MaybeUninit < T > > ,
75
76
notify : Notify ,
77
+ // we lock the mutex inside set to ensure
78
+ // only one caller of set can run at a time
79
+ lock : Mutex < ( ) > ,
76
80
}
77
81
78
82
impl < T > Default for SetOnce < T > {
@@ -105,13 +109,11 @@ impl<T: Eq> Eq for SetOnce<T> {}
105
109
106
110
impl < T > Drop for SetOnce < T > {
107
111
fn drop ( & mut self ) {
108
- if self . initialized ( ) {
112
+ if * self . value_set . get_mut ( ) {
109
113
// SAFETY: We're inside the drop implementation of SetOnce
110
114
// AND we're also initalized. This is the best way to ensure
111
115
// out data gets dropped
112
- unsafe {
113
- let _ = self . value . with_mut ( |ptr| ptr:: read ( ptr) . assume_init ( ) ) ;
114
- }
116
+ unsafe { self . value . with_mut ( |ptr| ptr:: drop_in_place ( ptr as * mut T ) ) }
115
117
// no need to set the flag to false as this set once is being
116
118
// dropped
117
119
}
@@ -124,6 +126,7 @@ impl<T> From<T> for SetOnce<T> {
124
126
value_set : AtomicBool :: new ( true ) ,
125
127
value : UnsafeCell :: new ( MaybeUninit :: new ( value) ) ,
126
128
notify : Notify :: new ( ) ,
129
+ lock : Mutex :: new ( ( ) ) ,
127
130
}
128
131
}
129
132
}
@@ -135,6 +138,7 @@ impl<T> SetOnce<T> {
135
138
value_set : AtomicBool :: new ( false ) ,
136
139
value : UnsafeCell :: new ( MaybeUninit :: uninit ( ) ) ,
137
140
notify : Notify :: new ( ) ,
141
+ lock : Mutex :: new ( ( ) ) ,
138
142
}
139
143
}
140
144
@@ -177,6 +181,7 @@ impl<T> SetOnce<T> {
177
181
value_set : AtomicBool :: new ( false ) ,
178
182
value : UnsafeCell :: new ( MaybeUninit :: uninit ( ) ) ,
179
183
notify : Notify :: const_new ( ) ,
184
+ lock : Mutex :: new ( ( ) ) ,
180
185
}
181
186
}
182
187
@@ -227,6 +232,7 @@ impl<T> SetOnce<T> {
227
232
value_set : AtomicBool :: new ( true ) ,
228
233
value : UnsafeCell :: new ( MaybeUninit :: new ( value) ) ,
229
234
notify : Notify :: const_new ( ) ,
235
+ lock : Mutex :: new ( ( ) ) ,
230
236
}
231
237
}
232
238
@@ -257,6 +263,9 @@ impl<T> SetOnce<T> {
257
263
// called only when the value_set AtomicBool is flipped from FALSE to TRUE
258
264
// meaning that the value is being set from uinitialized to initialized via
259
265
// this function
266
+ //
267
+ // The caller also has to ensure writes on `value` are syncronized with a
268
+ // external lock to prevent mutliple set_value calls at the same time.
260
269
unsafe fn set_value ( & self , value : T ) {
261
270
unsafe {
262
271
self . value . with_mut ( |ptr| ( * ptr) . as_mut_ptr ( ) . write ( value) ) ;
@@ -282,19 +291,30 @@ impl<T> SetOnce<T> {
282
291
return Err ( SetError :: AlreadyInitializedError ( value) ) ;
283
292
}
284
293
285
- // Using release ordering so any threads that read a true from this
286
- // atomic is able to read the value we just stored.
287
- if !self . value_set . swap ( true , Ordering :: Release ) {
288
- // SAFETY: We are swapping the value_set AtomicBool from FALSE to
289
- // TRUE with it being previously false and followed by that we are
290
- // initializing the unsafe Cell field with the value
291
- unsafe {
292
- self . set_value ( value) ;
293
- }
294
+ // SAFETY: lock the mutex to ensure only one caller of set
295
+ // can run at a time.
296
+ match self . lock . lock ( ) {
297
+ Ok ( _) => {
298
+ // Using release ordering so any threads that read a true from this
299
+ // atomic is able to read the value we just stored.
300
+ if !self . value_set . swap ( true , Ordering :: Release ) {
301
+ // SAFETY: We are swapping the value_set AtomicBool from FALSE to
302
+ // TRUE with it being previously false and followed by that we are
303
+ // initializing the unsafe Cell field with the value
304
+ unsafe {
305
+ self . set_value ( value) ;
306
+ }
294
307
295
- Ok ( ( ) )
296
- } else {
297
- Err ( SetError :: InitializingError ( value) )
308
+ Ok ( ( ) )
309
+ } else {
310
+ Err ( SetError :: AlreadyInitializedError ( value) )
311
+ }
312
+ }
313
+ Err ( _) => {
314
+ // If we failed to lock the mutex, it means some other task is
315
+ // trying to set the value, so we return an error.
316
+ Err ( SetError :: InitializingError ( value) )
317
+ }
298
318
}
299
319
}
300
320
@@ -317,16 +337,45 @@ impl<T> SetOnce<T> {
317
337
}
318
338
}
319
339
320
- /// Waits until the `SetOnce` has been initialized. Once the `SetOnce` is
321
- /// initialized the wakers are notified and the Future returned from this
322
- /// function completes.
340
+ /// Waits until set is called. The future returned will keep blocking until
341
+ /// the `SetOnce` is initialized.
342
+ ///
343
+ /// If the `SetOnce` is already initialized, it will return the value
344
+ // immediately.
345
+ ///
346
+ /// # Panics
347
+ ///
348
+ /// If the `SetOnce` is not initialized after waiting, it will panic. To
349
+ /// avoid this, use `get_wait()` which returns an `Option<&T>` instead of
350
+ /// `&T`.
351
+ pub async fn wait ( & self ) -> & T {
352
+ match self . get_wait ( ) . await {
353
+ Some ( val) => val,
354
+ _ => panic ! ( "SetOnce::wait called but the SetOnce is not initialized" ) ,
355
+ }
356
+ }
357
+
358
+ /// Waits until set is called.
323
359
///
324
- /// If this function is called after the `SetOnce` is initialized then
325
- /// empty future is returned which completes immediately.
326
- pub async fn wait ( & self ) {
327
- if !self . initialized ( ) {
328
- let _ = self . notify . notified ( ) . await ;
360
+ /// If the state failed to initalize it will return `None`.
361
+ pub async fn get_wait ( & self ) -> Option < & T > {
362
+ let notify_fut = self . notify . notified ( ) ;
363
+ pin ! ( notify_fut) ;
364
+
365
+ if self . value_set . load ( Ordering :: Acquire ) {
366
+ // SAFETY: the state is initialized
367
+ return Some ( unsafe { self . get_unchecked ( ) } ) ;
368
+ }
369
+ // wait until the value is set
370
+ ( & mut notify_fut) . await ;
371
+
372
+ // look at the state again
373
+ if self . value_set . load ( Ordering :: Acquire ) {
374
+ // SAFETY: the state is initialized
375
+ return Some ( unsafe { self . get_unchecked ( ) } ) ;
329
376
}
377
+
378
+ None
330
379
}
331
380
}
332
381
0 commit comments