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::std::marker::PhantomData; 6 use crate::std::ops::{Deref, DerefMut}; 7 use crate::std::ptr::null_mut; 8 use crate::std::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 passed to `cancel_init` right after. 25 fn init() -> Box<Self>; 26 27 /// Any surplus boxes from `init()` that lost the initialization race 28 /// are passed to this function for disposal. 29 /// 30 /// The default implementation calls destroy(). 31 fn cancel_init(x: Box<Self>) { 32 Self::destroy(x); 33 } 34 35 /// This is called to destroy a used box. 36 /// 37 /// The default implementation just drops it. 38 fn destroy(_: Box<Self>) {} 39 } 40 41 impl<T: LazyInit> LazyBox<T> { 42 #[inline] 43 pub const fn new() -> Self { 44 Self { 45 ptr: AtomicPtr::new(null_mut()), 46 _phantom: PhantomData, 47 } 48 } 49 50 #[inline] 51 fn get_pointer(&self) -> *mut T { 52 let ptr = self.ptr.load(Acquire); 53 if ptr.is_null() { 54 self.initialize() 55 } else { 56 ptr 57 } 58 } 59 60 #[cold] 61 fn initialize(&self) -> *mut T { 62 let new_ptr = Box::into_raw(T::init()); 63 match self 64 .ptr 65 .compare_exchange(null_mut(), new_ptr, AcqRel, Acquire) 66 { 67 Ok(_) => new_ptr, 68 Err(ptr) => { 69 // Lost the race to another thread. 70 // Drop the box we created, and use the one from the other thread instead. 71 T::cancel_init(unsafe { Box::from_raw(new_ptr) }); 72 ptr 73 } 74 } 75 } 76 } 77 78 impl<T: LazyInit> Deref for LazyBox<T> { 79 type Target = T; 80 #[inline] 81 fn deref(&self) -> &T { 82 unsafe { &*self.get_pointer() } 83 } 84 } 85 86 impl<T: LazyInit> DerefMut for LazyBox<T> { 87 #[inline] 88 fn deref_mut(&mut self) -> &mut T { 89 unsafe { &mut *self.get_pointer() } 90 } 91 } 92 93 impl<T: LazyInit> Drop for LazyBox<T> { 94 fn drop(&mut self) { 95 let ptr = *self.ptr.get_mut(); 96 if !ptr.is_null() { 97 T::destroy(unsafe { Box::from_raw(ptr) }); 98 } 99 } 100 } 101