Next Generation WASM Microkernel Operating System
at trap_handler 103 lines 3.1 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 crate::loom::sync::Arc; 9use crate::loom::sync::{Condvar, Mutex as StdMutex}; 10use core::mem::ManuallyDrop; 11use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; 12use futures::pin_mut; 13use futures::task::WakerRef; 14use util::loom_const_fn; 15 16#[derive(Debug)] 17pub struct ThreadNotify { 18 mutex: StdMutex<bool>, 19 condvar: Condvar, 20} 21 22impl ThreadNotify { 23 loom_const_fn! { 24 const fn new() -> Self { 25 Self { 26 mutex: StdMutex::new(false), 27 condvar: Condvar::new() 28 } 29 } 30 } 31 32 #[tracing::instrument(level = "trace", skip(self))] 33 fn wait(&self) { 34 let mut notified = self.mutex.lock().unwrap(); 35 while !*notified { 36 notified = self.condvar.wait(notified).unwrap(); 37 } 38 *notified = false; 39 } 40 41 fn notify(&self) { 42 let mut signaled = self.mutex.lock().unwrap(); 43 *signaled = true; 44 self.condvar.notify_one(); 45 } 46} 47 48fn waker_ref(wake: &Arc<ThreadNotify>) -> WakerRef<'_> { 49 static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( 50 clone_arc_raw, 51 wake_arc_raw, 52 wake_by_ref_arc_raw, 53 drop_arc_raw, 54 ); 55 56 unsafe fn clone_arc_raw(data: *const ()) -> RawWaker { 57 unsafe { Arc::increment_strong_count(data.cast::<ThreadNotify>()) } 58 RawWaker::new(data, &WAKER_VTABLE) 59 } 60 61 unsafe fn wake_arc_raw(data: *const ()) { 62 let arc = unsafe { Arc::from_raw(data.cast::<ThreadNotify>()) }; 63 ThreadNotify::notify(&arc); 64 } 65 66 // used by `waker_ref` 67 unsafe fn wake_by_ref_arc_raw(data: *const ()) { 68 // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop 69 let arc = ManuallyDrop::new(unsafe { Arc::from_raw(data.cast::<ThreadNotify>()) }); 70 ThreadNotify::notify(&arc); 71 } 72 73 unsafe fn drop_arc_raw(data: *const ()) { 74 drop(unsafe { Arc::from_raw(data.cast::<ThreadNotify>()) }) 75 } 76 77 // simply copy the pointer instead of using Arc::into_raw, 78 // as we don't actually keep a refcount by using ManuallyDrop.< 79 let ptr = Arc::as_ptr(wake).cast::<()>(); 80 81 let waker = ManuallyDrop::new(unsafe { Waker::from_raw(RawWaker::new(ptr, &WAKER_VTABLE)) }); 82 WakerRef::new_unowned(waker) 83} 84 85pub fn block_on<F: Future>(f: F) -> F::Output { 86 pin_mut!(f); 87 88 crate::loom::thread_local! { 89 static CURRENT_THREAD_NOTIFY: Arc<ThreadNotify> = Arc::new(ThreadNotify::new()); 90 } 91 92 CURRENT_THREAD_NOTIFY.with(|thread_notify| { 93 let waker = waker_ref(&thread_notify); 94 let mut cx = Context::from_waker(&waker); 95 loop { 96 if let Poll::Ready(t) = f.as_mut().poll(&mut cx) { 97 return t; 98 } 99 100 thread_notify.wait(); 101 } 102 }) 103}