• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 Amanieu d'Antras
2 //
3 // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4 // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5 // http://opensource.org/licenses/MIT>, at your option. This file may not be
6 // copied, modified, or distributed except according to those terms.
7 
8 use crate::util::UncheckedOptionExt;
9 use core::{
10     fmt, mem,
11     sync::atomic::{fence, AtomicU8, Ordering},
12 };
13 use parking_lot_core::{self, SpinWait, DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN};
14 
15 const DONE_BIT: u8 = 1;
16 const POISON_BIT: u8 = 2;
17 const LOCKED_BIT: u8 = 4;
18 const PARKED_BIT: u8 = 8;
19 
20 /// Current state of a `Once`.
21 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
22 pub enum OnceState {
23     /// A closure has not been executed yet
24     New,
25 
26     /// A closure was executed but panicked.
27     Poisoned,
28 
29     /// A thread is currently executing a closure.
30     InProgress,
31 
32     /// A closure has completed successfully.
33     Done,
34 }
35 
36 impl OnceState {
37     /// Returns whether the associated `Once` has been poisoned.
38     ///
39     /// Once an initialization routine for a `Once` has panicked it will forever
40     /// indicate to future forced initialization routines that it is poisoned.
41     #[inline]
poisoned(self) -> bool42     pub fn poisoned(self) -> bool {
43         matches!(self, OnceState::Poisoned)
44     }
45 
46     /// Returns whether the associated `Once` has successfully executed a
47     /// closure.
48     #[inline]
done(self) -> bool49     pub fn done(self) -> bool {
50         matches!(self, OnceState::Done)
51     }
52 }
53 
54 /// A synchronization primitive which can be used to run a one-time
55 /// initialization. Useful for one-time initialization for globals, FFI or
56 /// related functionality.
57 ///
58 /// # Differences from the standard library `Once`
59 ///
60 /// - Only requires 1 byte of space, instead of 1 word.
61 /// - Not required to be `'static`.
62 /// - Relaxed memory barriers in the fast path, which can significantly improve
63 ///   performance on some architectures.
64 /// - Efficient handling of micro-contention using adaptive spinning.
65 ///
66 /// # Examples
67 ///
68 /// ```
69 /// use parking_lot::Once;
70 ///
71 /// static START: Once = Once::new();
72 ///
73 /// START.call_once(|| {
74 ///     // run initialization here
75 /// });
76 /// ```
77 pub struct Once(AtomicU8);
78 
79 impl Once {
80     /// Creates a new `Once` value.
81     #[inline]
new() -> Once82     pub const fn new() -> Once {
83         Once(AtomicU8::new(0))
84     }
85 
86     /// Returns the current state of this `Once`.
87     #[inline]
state(&self) -> OnceState88     pub fn state(&self) -> OnceState {
89         let state = self.0.load(Ordering::Acquire);
90         if state & DONE_BIT != 0 {
91             OnceState::Done
92         } else if state & LOCKED_BIT != 0 {
93             OnceState::InProgress
94         } else if state & POISON_BIT != 0 {
95             OnceState::Poisoned
96         } else {
97             OnceState::New
98         }
99     }
100 
101     /// Performs an initialization routine once and only once. The given closure
102     /// will be executed if this is the first time `call_once` has been called,
103     /// and otherwise the routine will *not* be invoked.
104     ///
105     /// This method will block the calling thread if another initialization
106     /// routine is currently running.
107     ///
108     /// When this function returns, it is guaranteed that some initialization
109     /// has run and completed (it may not be the closure specified). It is also
110     /// guaranteed that any memory writes performed by the executed closure can
111     /// be reliably observed by other threads at this point (there is a
112     /// happens-before relation between the closure and code executing after the
113     /// return).
114     ///
115     /// # Examples
116     ///
117     /// ```
118     /// use parking_lot::Once;
119     ///
120     /// static mut VAL: usize = 0;
121     /// static INIT: Once = Once::new();
122     ///
123     /// // Accessing a `static mut` is unsafe much of the time, but if we do so
124     /// // in a synchronized fashion (e.g. write once or read all) then we're
125     /// // good to go!
126     /// //
127     /// // This function will only call `expensive_computation` once, and will
128     /// // otherwise always return the value returned from the first invocation.
129     /// fn get_cached_val() -> usize {
130     ///     unsafe {
131     ///         INIT.call_once(|| {
132     ///             VAL = expensive_computation();
133     ///         });
134     ///         VAL
135     ///     }
136     /// }
137     ///
138     /// fn expensive_computation() -> usize {
139     ///     // ...
140     /// # 2
141     /// }
142     /// ```
143     ///
144     /// # Panics
145     ///
146     /// The closure `f` will only be executed once if this is called
147     /// concurrently amongst many threads. If that closure panics, however, then
148     /// it will *poison* this `Once` instance, causing all future invocations of
149     /// `call_once` to also panic.
150     #[inline]
call_once<F>(&self, f: F) where F: FnOnce(),151     pub fn call_once<F>(&self, f: F)
152     where
153         F: FnOnce(),
154     {
155         if self.0.load(Ordering::Acquire) == DONE_BIT {
156             return;
157         }
158 
159         let mut f = Some(f);
160         self.call_once_slow(false, &mut |_| unsafe { f.take().unchecked_unwrap()() });
161     }
162 
163     /// Performs the same function as `call_once` except ignores poisoning.
164     ///
165     /// If this `Once` has been poisoned (some initialization panicked) then
166     /// this function will continue to attempt to call initialization functions
167     /// until one of them doesn't panic.
168     ///
169     /// The closure `f` is yielded a structure which can be used to query the
170     /// state of this `Once` (whether initialization has previously panicked or
171     /// not).
172     #[inline]
call_once_force<F>(&self, f: F) where F: FnOnce(OnceState),173     pub fn call_once_force<F>(&self, f: F)
174     where
175         F: FnOnce(OnceState),
176     {
177         if self.0.load(Ordering::Acquire) == DONE_BIT {
178             return;
179         }
180 
181         let mut f = Some(f);
182         self.call_once_slow(true, &mut |state| unsafe {
183             f.take().unchecked_unwrap()(state)
184         });
185     }
186 
187     // This is a non-generic function to reduce the monomorphization cost of
188     // using `call_once` (this isn't exactly a trivial or small implementation).
189     //
190     // Additionally, this is tagged with `#[cold]` as it should indeed be cold
191     // and it helps let LLVM know that calls to this function should be off the
192     // fast path. Essentially, this should help generate more straight line code
193     // in LLVM.
194     //
195     // Finally, this takes an `FnMut` instead of a `FnOnce` because there's
196     // currently no way to take an `FnOnce` and call it via virtual dispatch
197     // without some allocation overhead.
198     #[cold]
call_once_slow(&self, ignore_poison: bool, f: &mut dyn FnMut(OnceState))199     fn call_once_slow(&self, ignore_poison: bool, f: &mut dyn FnMut(OnceState)) {
200         let mut spinwait = SpinWait::new();
201         let mut state = self.0.load(Ordering::Relaxed);
202         loop {
203             // If another thread called the closure, we're done
204             if state & DONE_BIT != 0 {
205                 // An acquire fence is needed here since we didn't load the
206                 // state with Ordering::Acquire.
207                 fence(Ordering::Acquire);
208                 return;
209             }
210 
211             // If the state has been poisoned and we aren't forcing, then panic
212             if state & POISON_BIT != 0 && !ignore_poison {
213                 // Need the fence here as well for the same reason
214                 fence(Ordering::Acquire);
215                 panic!("Once instance has previously been poisoned");
216             }
217 
218             // Grab the lock if it isn't locked, even if there is a queue on it.
219             // We also clear the poison bit since we are going to try running
220             // the closure again.
221             if state & LOCKED_BIT == 0 {
222                 match self.0.compare_exchange_weak(
223                     state,
224                     (state | LOCKED_BIT) & !POISON_BIT,
225                     Ordering::Acquire,
226                     Ordering::Relaxed,
227                 ) {
228                     Ok(_) => break,
229                     Err(x) => state = x,
230                 }
231                 continue;
232             }
233 
234             // If there is no queue, try spinning a few times
235             if state & PARKED_BIT == 0 && spinwait.spin() {
236                 state = self.0.load(Ordering::Relaxed);
237                 continue;
238             }
239 
240             // Set the parked bit
241             if state & PARKED_BIT == 0 {
242                 if let Err(x) = self.0.compare_exchange_weak(
243                     state,
244                     state | PARKED_BIT,
245                     Ordering::Relaxed,
246                     Ordering::Relaxed,
247                 ) {
248                     state = x;
249                     continue;
250                 }
251             }
252 
253             // Park our thread until we are woken up by the thread that owns the
254             // lock.
255             let addr = self as *const _ as usize;
256             let validate = || self.0.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT;
257             let before_sleep = || {};
258             let timed_out = |_, _| unreachable!();
259             unsafe {
260                 parking_lot_core::park(
261                     addr,
262                     validate,
263                     before_sleep,
264                     timed_out,
265                     DEFAULT_PARK_TOKEN,
266                     None,
267                 );
268             }
269 
270             // Loop back and check if the done bit was set
271             spinwait.reset();
272             state = self.0.load(Ordering::Relaxed);
273         }
274 
275         struct PanicGuard<'a>(&'a Once);
276         impl<'a> Drop for PanicGuard<'a> {
277             fn drop(&mut self) {
278                 // Mark the state as poisoned, unlock it and unpark all threads.
279                 let once = self.0;
280                 let state = once.0.swap(POISON_BIT, Ordering::Release);
281                 if state & PARKED_BIT != 0 {
282                     let addr = once as *const _ as usize;
283                     unsafe {
284                         parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN);
285                     }
286                 }
287             }
288         }
289 
290         // At this point we have the lock, so run the closure. Make sure we
291         // properly clean up if the closure panicks.
292         let guard = PanicGuard(self);
293         let once_state = if state & POISON_BIT != 0 {
294             OnceState::Poisoned
295         } else {
296             OnceState::New
297         };
298         f(once_state);
299         mem::forget(guard);
300 
301         // Now unlock the state, set the done bit and unpark all threads
302         let state = self.0.swap(DONE_BIT, Ordering::Release);
303         if state & PARKED_BIT != 0 {
304             let addr = self as *const _ as usize;
305             unsafe {
306                 parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN);
307             }
308         }
309     }
310 }
311 
312 impl Default for Once {
313     #[inline]
default() -> Once314     fn default() -> Once {
315         Once::new()
316     }
317 }
318 
319 impl fmt::Debug for Once {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result320     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
321         f.debug_struct("Once")
322             .field("state", &self.state())
323             .finish()
324     }
325 }
326 
327 #[cfg(test)]
328 mod tests {
329     use crate::Once;
330     use std::panic;
331     use std::sync::mpsc::channel;
332     use std::thread;
333 
334     #[test]
smoke_once()335     fn smoke_once() {
336         static O: Once = Once::new();
337         let mut a = 0;
338         O.call_once(|| a += 1);
339         assert_eq!(a, 1);
340         O.call_once(|| a += 1);
341         assert_eq!(a, 1);
342     }
343 
344     #[test]
stampede_once()345     fn stampede_once() {
346         static O: Once = Once::new();
347         static mut RUN: bool = false;
348 
349         let (tx, rx) = channel();
350         for _ in 0..10 {
351             let tx = tx.clone();
352             thread::spawn(move || {
353                 for _ in 0..4 {
354                     thread::yield_now()
355                 }
356                 unsafe {
357                     O.call_once(|| {
358                         assert!(!RUN);
359                         RUN = true;
360                     });
361                     assert!(RUN);
362                 }
363                 tx.send(()).unwrap();
364             });
365         }
366 
367         unsafe {
368             O.call_once(|| {
369                 assert!(!RUN);
370                 RUN = true;
371             });
372             assert!(RUN);
373         }
374 
375         for _ in 0..10 {
376             rx.recv().unwrap();
377         }
378     }
379 
380     #[test]
poison_bad()381     fn poison_bad() {
382         static O: Once = Once::new();
383 
384         // poison the once
385         let t = panic::catch_unwind(|| {
386             O.call_once(|| panic!());
387         });
388         assert!(t.is_err());
389 
390         // poisoning propagates
391         let t = panic::catch_unwind(|| {
392             O.call_once(|| {});
393         });
394         assert!(t.is_err());
395 
396         // we can subvert poisoning, however
397         let mut called = false;
398         O.call_once_force(|p| {
399             called = true;
400             assert!(p.poisoned())
401         });
402         assert!(called);
403 
404         // once any success happens, we stop propagating the poison
405         O.call_once(|| {});
406     }
407 
408     #[test]
wait_for_force_to_finish()409     fn wait_for_force_to_finish() {
410         static O: Once = Once::new();
411 
412         // poison the once
413         let t = panic::catch_unwind(|| {
414             O.call_once(|| panic!());
415         });
416         assert!(t.is_err());
417 
418         // make sure someone's waiting inside the once via a force
419         let (tx1, rx1) = channel();
420         let (tx2, rx2) = channel();
421         let t1 = thread::spawn(move || {
422             O.call_once_force(|p| {
423                 assert!(p.poisoned());
424                 tx1.send(()).unwrap();
425                 rx2.recv().unwrap();
426             });
427         });
428 
429         rx1.recv().unwrap();
430 
431         // put another waiter on the once
432         let t2 = thread::spawn(|| {
433             let mut called = false;
434             O.call_once(|| {
435                 called = true;
436             });
437             assert!(!called);
438         });
439 
440         tx2.send(()).unwrap();
441 
442         assert!(t1.join().is_ok());
443         assert!(t2.join().is_ok());
444     }
445 
446     #[test]
test_once_debug()447     fn test_once_debug() {
448         static O: Once = Once::new();
449 
450         assert_eq!(format!("{:?}", O), "Once { state: New }");
451     }
452 }
453