Skip to main content

kernel_api/
executor.rs

1use alloc::boxed::Box;
2use alloc::sync::Arc;
3use alloc::task::Wake;
4use core::mem::MaybeUninit;
5use core::pin::pin;
6use core::sync::atomic::Ordering;
7use core::task::{Context, Poll, Waker};
8use log::{debug, trace};
9use crate::threading::{ThreadMeta, ThreadState};
10
11impl Wake for ThreadMeta {
12	fn wake(self: Arc<Self>) {
13		self.wake_by_ref();
14	}
15
16	fn wake_by_ref(self: &Arc<Self>) {
17		trace!("wake thread {:?}", self.thread_id);
18		self.state.store(ThreadState::Ready, Ordering::SeqCst);
19		crate::bridge::threading::unblock_thread(self);
20	}
21}
22
23/// Blocks the current thread until the future is ready, parking the thread where possible
24#[cfg(not(feature = "use_std"))]
25pub fn block_on<T, F: Future<Output = T>>(f: F) -> T {
26	let mut f = pin!(f);
27
28	let val = loop {
29		let waker = {
30			let mut meta = MaybeUninit::<Arc<ThreadMeta>>::uninit();
31			crate::bridge::threading::with_current_thread(meta.as_mut_ptr().cast(), |meta, ptr| {
32				let ptr = ptr.cast::<Arc<ThreadMeta>>();
33				meta.state.store(ThreadState::NearlyParked, Ordering::SeqCst);
34				unsafe { ptr.write(Arc::clone(meta)) };
35			});
36			let meta = unsafe { meta.assume_init() };
37			Waker::from(meta)
38		};
39
40		let mut ctx = Context::from_waker(&waker);
41
42		match f.as_mut().poll(&mut ctx) {
43			Poll::Ready(val) => {
44				debug!("future ready!");
45				crate::bridge::threading::with_current_thread(core::ptr::null_mut(), |meta, _| {
46					let _ = meta.state
47					    .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |val| {
48						    debug!("block_on replace state {val:?}");
49						    match val {
50							    ThreadState::Ready => Some(ThreadState::Running),
51							    ThreadState::Parked => Some(ThreadState::Running),
52							    ThreadState::NearlyParked => Some(ThreadState::Running),
53							    _ => None,
54						    }
55					    });
56				});
57
58				break val;
59			},
60			Poll::Pending => {
61				debug!("future pending :(");
62				crate::bridge::executor::yield_from_async_block();
63			}
64		}
65	};
66
67	val
68}
69
70/// Spawns a future on the kernel's async executor
71///
72/// The future will run to completion in the background in the context of the current thread.
73/// This means that any access via (`LocalUser`)[crate::ptr::LocalUser] will be to the current thread's
74/// address space.
75/// This also means that there is no requirement for the future to be [`Send`] nor [`Sync`].
76pub fn spawn(f: impl Future<Output = ()> + 'static) {
77	crate::bridge::executor::spawn_task(Box::pin(f));
78}