Next Generation WASM Microkernel Operating System
at trap_handler 489 lines 14 kB view raw
1// Copyright 2025 Jonas Kruckenberg 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 8use super::Once; 9use crate::loom::UnsafeCell; 10use core::{ 11 fmt, 12 mem::MaybeUninit, 13 panic::{RefUnwindSafe, UnwindSafe}, 14}; 15use util::loom_const_fn; 16 17/// A synchronization primitive which can be written to only once. 18/// 19/// Thread-safe variant of [`core::cell::OnceCell`]. 20pub struct OnceLock<T> { 21 once: Once, 22 data: UnsafeCell<MaybeUninit<T>>, 23} 24 25impl<T> OnceLock<T> { 26 loom_const_fn! { 27 #[must_use] 28 pub const fn new() -> Self { 29 Self { 30 once: Once::new(), 31 data: UnsafeCell::new(MaybeUninit::uninit()), 32 } 33 } 34 } 35 36 /// # Panics 37 /// 38 /// Panics if the closure panics. 39 pub fn get_or_init<F: FnOnce() -> T>(&self, f: F) -> &T { 40 self.once.call_once(|| { 41 self.data.with_mut(|data| { 42 // SAFETY: `Once` ensures this is only called once 43 unsafe { (*data).as_mut_ptr().write(f()) } 44 }); 45 }); 46 47 // SAFETY: `Once` ensures this is only called once 48 unsafe { self.force_get() } 49 } 50 51 /// # Errors 52 /// 53 /// Returns an error if the given closure errors. 54 /// 55 /// # Panics 56 /// 57 /// Panics if the closure panics. 58 pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> 59 where 60 F: FnOnce() -> Result<T, E>, 61 { 62 let mut error = None; 63 64 self.once.call_once(|| { 65 #[allow(tail_expr_drop_order, reason = "")] 66 match f() { 67 Ok(val) => { 68 self.data.with_mut(|data| { 69 // SAFETY: `Once` ensures this is only called once 70 unsafe { (*data).as_mut_ptr().write(val) } 71 }); 72 } 73 Err(err) => error = Some(err), 74 } 75 }); 76 77 #[allow(if_let_rescope, reason = "")] 78 if let Some(err) = error { 79 Err(err) 80 } else { 81 // SAFETY: `Once` ensures this is only called once 82 unsafe { Ok(self.force_get()) } 83 } 84 } 85 86 /// Gets the reference to the underlying value. 87 /// 88 /// Returns `None` if the cell is empty, or being initialized. This 89 /// method never blocks. 90 pub fn get(&self) -> Option<&T> { 91 self.once.is_completed().then(|| { 92 // Safety: `is_completed` ensures value is properly initialized 93 unsafe { self.force_get() } 94 }) 95 } 96 97 /// Gets the mutable reference to the underlying value. 98 /// 99 /// Returns `None` if the cell is empty. This method never blocks. 100 pub fn get_mut(&mut self) -> Option<&mut T> { 101 self.once.is_completed().then(|| { 102 // Safety: `is_completed` ensures value is properly initialized 103 unsafe { self.force_get_mut() } 104 }) 105 } 106 107 /// Blocks the current thread until the cell is initialized. 108 pub fn wait(&self) -> &T { 109 self.once.wait(); 110 111 // Safety: we have waited until the data is initialized 112 unsafe { self.force_get() } 113 } 114 115 /// Sets the contents of this cell to `value`. 116 /// 117 /// May block if another thread is currently attempting to initialize the cell. The cell is 118 /// guaranteed to contain a value when set returns, though not necessarily the one provided. 119 /// 120 /// Returns `Ok(())` if the cell's value was set by this call. 121 /// 122 /// # Errors 123 /// 124 /// Returns the value in the `Err` variant is the cell was full. 125 #[inline] 126 pub fn set(&self, value: T) -> Result<(), T> { 127 match self.try_insert(value) { 128 Ok(_) => Ok(()), 129 Err((_, value)) => Err(value), 130 } 131 } 132 133 /// Sets the contents of this cell to `value` if the cell was empty, then 134 /// returns a reference to it. 135 /// 136 /// May block if another thread is currently attempting to initialize the cell. The cell is 137 /// guaranteed to contain a value when set returns, though not necessarily the one provided. 138 /// 139 /// Returns `Ok(&value)` if the cell was empty 140 /// 141 /// # Errors 142 /// 143 /// Returns `Err(&current_value, value)` if the cell was full. 144 #[inline] 145 pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> { 146 let mut value = Some(value); 147 let res = self.get_or_init(|| { 148 // Safety: we have initialized `value` to a `Some` above 149 unsafe { value.take().unwrap_unchecked() } 150 }); 151 match value { 152 None => Ok(res), 153 Some(value) => Err((res, value)), 154 } 155 } 156 157 /// Takes the value out of this `OnceLock`, moving it back to an uninitialized state. 158 /// 159 /// Has no effect and returns `None` if the `OnceLock` hasn't been initialized. 160 /// 161 /// Safety is guaranteed by requiring a mutable reference. 162 #[inline] 163 pub fn take(&mut self) -> Option<T> { 164 if self.is_initialized() { 165 self.once = Once::new(); 166 self.data.with(|data| { 167 // SAFETY: `self.value` is initialized and contains a valid `T`. 168 // `self.once` is reset, so `is_initialized()` will be false again 169 // which prevents the value from being read twice. 170 Some(unsafe { MaybeUninit::assume_init_read(&*data) }) 171 }) 172 } else { 173 None 174 } 175 } 176 177 /// Consumes the `OnceLock`, returning the wrapped value. Returns 178 /// `None` if the cell was empty. 179 #[inline] 180 pub fn into_inner(mut self) -> Option<T> { 181 self.take() 182 } 183 184 #[inline] 185 fn is_initialized(&self) -> bool { 186 self.once.is_completed() 187 } 188 189 unsafe fn force_get(&self) -> &T { 190 self.data.with(|data| { 191 // SAFETY: 192 // * `UnsafeCell`/inner deref: data never changes again 193 // * `MaybeUninit`/outer deref: data was initialized 194 unsafe { &*(*data).as_ptr() } 195 }) 196 } 197 198 unsafe fn force_get_mut(&mut self) -> &mut T { 199 self.data.with_mut(|data| { 200 // SAFETY: 201 // * `UnsafeCell`/inner deref: data never changes again 202 // * `MaybeUninit`/outer deref: data was initialized 203 unsafe { &mut *(*data).as_mut_ptr() } 204 }) 205 } 206} 207 208// Safety: synchronization primitive 209unsafe impl<T: Sync + Send> Sync for OnceLock<T> {} 210// Safety: synchronization primitive 211unsafe impl<T: Send> Send for OnceLock<T> {} 212 213impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T> {} 214impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {} 215 216impl<T> Default for OnceLock<T> { 217 fn default() -> Self { 218 Self::new() 219 } 220} 221 222impl<T: fmt::Debug> fmt::Debug for OnceLock<T> { 223 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 224 let mut d = f.debug_tuple("OnceLock"); 225 match self.get() { 226 Some(v) => d.field(v), 227 None => d.field(&format_args!("<uninit>")), 228 }; 229 d.finish() 230 } 231} 232 233impl<T: Clone> Clone for OnceLock<T> { 234 #[inline] 235 fn clone(&self) -> OnceLock<T> { 236 let cell = Self::new(); 237 if let Some(value) = self.get() { 238 match cell.set(value.clone()) { 239 Ok(()) => (), 240 Err(_) => unreachable!(), 241 } 242 } 243 cell 244 } 245} 246 247impl<T> From<T> for OnceLock<T> { 248 /// Creates a new cell with its contents set to `value`. 249 /// 250 /// # Example 251 /// 252 /// ``` 253 /// use std::sync::OnceLock; 254 /// 255 /// # fn main() -> Result<(), i32> { 256 /// let a = OnceLock::from(3); 257 /// let b = OnceLock::new(); 258 /// b.set(3)?; 259 /// assert_eq!(a, b); 260 /// Ok(()) 261 /// # } 262 /// ``` 263 #[inline] 264 fn from(value: T) -> Self { 265 let cell = Self::new(); 266 match cell.set(value) { 267 Ok(()) => cell, 268 Err(_) => unreachable!(), 269 } 270 } 271} 272 273impl<T: PartialEq> PartialEq for OnceLock<T> { 274 /// Equality for two `OnceLock`s. 275 /// 276 /// Two `OnceLock`s are equal if they either both contain values and their 277 /// values are equal, or if neither contains a value. 278 /// 279 /// # Examples 280 /// 281 /// ``` 282 /// use std::sync::OnceLock; 283 /// 284 /// let five = OnceLock::new(); 285 /// five.set(5).unwrap(); 286 /// 287 /// let also_five = OnceLock::new(); 288 /// also_five.set(5).unwrap(); 289 /// 290 /// assert!(five == also_five); 291 /// 292 /// assert!(OnceLock::<u32>::new() == OnceLock::<u32>::new()); 293 /// ``` 294 #[inline] 295 fn eq(&self, other: &OnceLock<T>) -> bool { 296 self.get() == other.get() 297 } 298} 299 300impl<T: Eq> Eq for OnceLock<T> {} 301 302#[expect(clippy::undocumented_unsafe_blocks, reason = "")] 303unsafe impl<#[may_dangle] T> Drop for OnceLock<T> { 304 #[inline] 305 fn drop(&mut self) { 306 if self.is_initialized() { 307 self.data.with_mut(|data| { 308 // SAFETY: The cell is initialized and being dropped, so it can't 309 // be accessed again. We also don't touch the `T` other than 310 // dropping it, which validates our usage of #[may_dangle]. 311 unsafe { MaybeUninit::assume_init_drop(&mut *data) } 312 }); 313 } 314 } 315} 316 317#[cfg(test)] 318mod tests { 319 use super::*; 320 use crate::loom::thread; 321 use crate::loom::{AtomicUsize, Ordering}; 322 use std::sync::mpsc::channel; 323 324 fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R { 325 thread::spawn(f).join().unwrap() 326 } 327 328 #[test] 329 fn sync_once_cell() { 330 static ONCE_CELL: OnceLock<i32> = OnceLock::new(); 331 332 assert!(ONCE_CELL.get().is_none()); 333 334 spawn_and_wait(|| { 335 ONCE_CELL.get_or_init(|| 92); 336 assert_eq!(ONCE_CELL.get(), Some(&92)); 337 }); 338 339 ONCE_CELL.get_or_init(|| panic!("Kaboom!")); 340 assert_eq!(ONCE_CELL.get(), Some(&92)); 341 } 342 343 #[test] 344 fn sync_once_cell_get_mut() { 345 let mut c = OnceLock::new(); 346 assert!(c.get_mut().is_none()); 347 c.set(90).unwrap(); 348 *c.get_mut().unwrap() += 2; 349 assert_eq!(c.get_mut(), Some(&mut 92)); 350 } 351 352 #[test] 353 fn sync_once_cell_drop() { 354 static DROP_CNT: AtomicUsize = AtomicUsize::new(0); 355 struct Dropper; 356 impl Drop for Dropper { 357 fn drop(&mut self) { 358 DROP_CNT.fetch_add(1, Ordering::SeqCst); 359 } 360 } 361 362 let x = OnceLock::new(); 363 spawn_and_wait(move || { 364 x.get_or_init(|| Dropper); 365 assert_eq!(DROP_CNT.load(Ordering::SeqCst), 0); 366 drop(x); 367 }); 368 369 assert_eq!(DROP_CNT.load(Ordering::SeqCst), 1); 370 } 371 372 #[test] 373 fn sync_once_cell_drop_empty() { 374 let x = OnceLock::<String>::new(); 375 drop(x); 376 } 377 378 #[test] 379 fn clone() { 380 let s = OnceLock::new(); 381 let c = s.clone(); 382 assert!(c.get().is_none()); 383 384 s.set("hello".to_string()).unwrap(); 385 let c = s.clone(); 386 assert_eq!(c.get().map(String::as_str), Some("hello")); 387 } 388 389 #[test] 390 fn from_impl() { 391 assert_eq!(OnceLock::from("value").get(), Some(&"value")); 392 assert_ne!(OnceLock::from("foo").get(), Some(&"bar")); 393 } 394 395 #[test] 396 fn partialeq_impl() { 397 assert!(OnceLock::from("value") == OnceLock::from("value")); 398 assert!(OnceLock::from("foo") != OnceLock::from("bar")); 399 400 assert!(OnceLock::<String>::new() == OnceLock::new()); 401 assert!(OnceLock::<String>::new() != OnceLock::from("value".to_owned())); 402 } 403 404 #[test] 405 fn into_inner() { 406 let cell: OnceLock<String> = OnceLock::new(); 407 assert_eq!(cell.into_inner(), None); 408 let cell = OnceLock::new(); 409 cell.set("hello".to_string()).unwrap(); 410 assert_eq!(cell.into_inner(), Some("hello".to_string())); 411 } 412 413 #[test] 414 fn is_sync_send() { 415 fn assert_traits<T: Send + Sync>() {} 416 assert_traits::<OnceLock<String>>(); 417 } 418 419 #[test] 420 fn eval_once_macro() { 421 macro_rules! eval_once { 422 (|| -> $ty:ty { 423 $($body:tt)* 424 }) => {{ 425 static ONCE_CELL: OnceLock<$ty> = OnceLock::new(); 426 fn init() -> $ty { 427 $($body)* 428 } 429 ONCE_CELL.get_or_init(init) 430 }}; 431 } 432 433 let fib: &'static Vec<i32> = eval_once! { 434 || -> Vec<i32> { 435 let mut res = vec![1, 1]; 436 for i in 0..10 { 437 let next = res[i] + res[i + 1]; 438 res.push(next); 439 } 440 res 441 } 442 }; 443 assert_eq!(fib[5], 8) 444 } 445 446 #[test] 447 fn sync_once_cell_does_not_leak_partially_constructed_boxes() { 448 static ONCE_CELL: OnceLock<String> = OnceLock::new(); 449 450 let n_readers = 10; 451 let n_writers = 3; 452 const MSG: &str = "Hello, World"; 453 454 let (tx, rx) = channel(); 455 456 for _ in 0..n_readers { 457 let tx = tx.clone(); 458 thread::spawn(move || { 459 loop { 460 if let Some(msg) = ONCE_CELL.get() { 461 tx.send(msg).unwrap(); 462 break; 463 } 464 #[cfg(target_env = "sgx")] 465 std::thread::yield_now(); 466 } 467 }); 468 } 469 for _ in 0..n_writers { 470 thread::spawn(move || { 471 let _ = ONCE_CELL.set(MSG.to_owned()); 472 }); 473 } 474 475 for _ in 0..n_readers { 476 let msg = rx.recv().unwrap(); 477 assert_eq!(msg, MSG); 478 } 479 } 480 481 #[test] 482 fn dropck() { 483 let cell = OnceLock::new(); 484 { 485 let s = String::new(); 486 cell.set(&s).unwrap(); 487 } 488 } 489}