aboutsummaryrefslogtreecommitdiff
path: root/embassy-sync/src
diff options
context:
space:
mode:
authorwanglei <[email protected]>2024-07-31 00:24:39 +0800
committerwanglei <[email protected]>2024-07-31 10:31:56 +0800
commit93696c912e7264e101308a3f205272dcdd44e6b2 (patch)
tree68bbdbe12ed30bf40f0c3f9f89027aec534c7781 /embassy-sync/src
parente89ff7d12904d030c0efe3d92623ef7a208fa5eb (diff)
embassy-sync: fix the data of LazyLock never drop
Using `union` can save more space. And the `MaybeUninit<T>` will never drop the T, when dropping the `MaybeUninit<T>`. Fixed it. Signed-off-by: wanglei <[email protected]>
Diffstat (limited to 'embassy-sync/src')
-rw-r--r--embassy-sync/src/lazy_lock.rs41
1 files changed, 31 insertions, 10 deletions
diff --git a/embassy-sync/src/lazy_lock.rs b/embassy-sync/src/lazy_lock.rs
index 2b5742491..cf88bfdf8 100644
--- a/embassy-sync/src/lazy_lock.rs
+++ b/embassy-sync/src/lazy_lock.rs
@@ -1,7 +1,7 @@
1//! Synchronization primitive for initializing a value once, allowing others to get a reference to the value. 1//! Synchronization primitive for initializing a value once, allowing others to get a reference to the value.
2 2
3use core::cell::Cell; 3use core::cell::UnsafeCell;
4use core::mem::MaybeUninit; 4use core::mem::ManuallyDrop;
5use core::sync::atomic::{AtomicBool, Ordering}; 5use core::sync::atomic::{AtomicBool, Ordering};
6 6
7/// The `LazyLock` is a synchronization primitive that allows for 7/// The `LazyLock` is a synchronization primitive that allows for
@@ -23,8 +23,12 @@ use core::sync::atomic::{AtomicBool, Ordering};
23/// ``` 23/// ```
24pub struct LazyLock<T, F = fn() -> T> { 24pub struct LazyLock<T, F = fn() -> T> {
25 init: AtomicBool, 25 init: AtomicBool,
26 init_fn: Cell<Option<F>>, 26 data: UnsafeCell<Data<T, F>>,
27 data: Cell<MaybeUninit<T>>, 27}
28
29union Data<T, F> {
30 value: ManuallyDrop<T>,
31 f: ManuallyDrop<F>,
28} 32}
29 33
30unsafe impl<T, F> Sync for LazyLock<T, F> {} 34unsafe impl<T, F> Sync for LazyLock<T, F> {}
@@ -34,8 +38,9 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
34 pub const fn new(init_fn: F) -> Self { 38 pub const fn new(init_fn: F) -> Self {
35 Self { 39 Self {
36 init: AtomicBool::new(false), 40 init: AtomicBool::new(false),
37 init_fn: Cell::new(Some(init_fn)), 41 data: UnsafeCell::new(Data {
38 data: Cell::new(MaybeUninit::zeroed()), 42 f: ManuallyDrop::new(init_fn),
43 }),
39 } 44 }
40 } 45 }
41 46
@@ -44,7 +49,7 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
44 #[inline] 49 #[inline]
45 pub fn get(&self) -> &T { 50 pub fn get(&self) -> &T {
46 self.ensure_init_fast(); 51 self.ensure_init_fast();
47 unsafe { (*self.data.as_ptr()).assume_init_ref() } 52 unsafe { &(*self.data.get()).value }
48 } 53 }
49 54
50 /// Consume the `LazyLock`, returning the underlying value. The 55 /// Consume the `LazyLock`, returning the underlying value. The
@@ -53,7 +58,10 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
53 #[inline] 58 #[inline]
54 pub fn into_inner(self) -> T { 59 pub fn into_inner(self) -> T {
55 self.ensure_init_fast(); 60 self.ensure_init_fast();
56 unsafe { self.data.into_inner().assume_init() } 61 let this = ManuallyDrop::new(self);
62 let data = unsafe { core::ptr::read(&this.data) }.into_inner();
63
64 ManuallyDrop::into_inner(unsafe { data.value })
57 } 65 }
58 66
59 /// Initialize the `LazyLock` if it has not been initialized yet. 67 /// Initialize the `LazyLock` if it has not been initialized yet.
@@ -75,10 +83,23 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
75 fn ensure_init(&self) { 83 fn ensure_init(&self) {
76 critical_section::with(|_| { 84 critical_section::with(|_| {
77 if !self.init.load(Ordering::Acquire) { 85 if !self.init.load(Ordering::Acquire) {
78 let init_fn = self.init_fn.take().unwrap(); 86 let data = unsafe { &mut *self.data.get() };
79 self.data.set(MaybeUninit::new(init_fn())); 87 let f = unsafe { ManuallyDrop::take(&mut data.f) };
88 let value = f();
89 data.value = ManuallyDrop::new(value);
90
80 self.init.store(true, Ordering::Release); 91 self.init.store(true, Ordering::Release);
81 } 92 }
82 }); 93 });
83 } 94 }
84} 95}
96
97impl<T, F> Drop for LazyLock<T, F> {
98 fn drop(&mut self) {
99 if self.init.load(Ordering::Acquire) {
100 unsafe { ManuallyDrop::drop(&mut self.data.get_mut().value) };
101 } else {
102 unsafe { ManuallyDrop::drop(&mut self.data.get_mut().f) };
103 }
104 }
105}