]> git.lizzy.rs Git - rust.git/blob - library/std/src/sys_common/lazy_box.rs
Auto merge of #97577 - betrusted-io:add-xous-target, r=nagisa
[rust.git] / library / std / src / sys_common / lazy_box.rs
1 #![allow(dead_code)] // Only used on some platforms.
2
3 // This is used to wrap pthread {Mutex, Condvar, RwLock} in.
4
5 use crate::marker::PhantomData;
6 use crate::ops::{Deref, DerefMut};
7 use crate::ptr::null_mut;
8 use crate::sync::atomic::{
9     AtomicPtr,
10     Ordering::{AcqRel, Acquire},
11 };
12
13 pub(crate) struct LazyBox<T: LazyInit> {
14     ptr: AtomicPtr<T>,
15     _phantom: PhantomData<T>,
16 }
17
18 pub(crate) trait LazyInit {
19     /// This is called before the box is allocated, to provide the value to
20     /// move into the new box.
21     ///
22     /// It might be called more than once per LazyBox, as multiple threads
23     /// might race to initialize it concurrently, each constructing and initializing
24     /// their own box. (All but one of them will be destroyed right after.)
25     fn init() -> Box<Self>;
26 }
27
28 impl<T: LazyInit> LazyBox<T> {
29     #[inline]
30     pub const fn new() -> Self {
31         Self { ptr: AtomicPtr::new(null_mut()), _phantom: PhantomData }
32     }
33
34     #[inline]
35     fn get_pointer(&self) -> *mut T {
36         let ptr = self.ptr.load(Acquire);
37         if ptr.is_null() { self.initialize() } else { ptr }
38     }
39
40     #[cold]
41     fn initialize(&self) -> *mut T {
42         let new_ptr = Box::into_raw(T::init());
43         match self.ptr.compare_exchange(null_mut(), new_ptr, AcqRel, Acquire) {
44             Ok(_) => new_ptr,
45             Err(ptr) => {
46                 // Lost the race to another thread.
47                 // Drop the box we created, and use the one from the other thread instead.
48                 drop(unsafe { Box::from_raw(new_ptr) });
49                 ptr
50             }
51         }
52     }
53 }
54
55 impl<T: LazyInit> Deref for LazyBox<T> {
56     type Target = T;
57     #[inline]
58     fn deref(&self) -> &T {
59         unsafe { &*self.get_pointer() }
60     }
61 }
62
63 impl<T: LazyInit> DerefMut for LazyBox<T> {
64     #[inline]
65     fn deref_mut(&mut self) -> &mut T {
66         unsafe { &mut *self.get_pointer() }
67     }
68 }
69
70 impl<T: LazyInit> Drop for LazyBox<T> {
71     fn drop(&mut self) {
72         let ptr = *self.ptr.get_mut();
73         if !ptr.is_null() {
74             drop(unsafe { Box::from_raw(ptr) });
75         }
76     }
77 }