1use crate::worker;
6use crossbeam_utils::sync::Parker;
7use lightproc::proc_stack::ProcStack;
8use std::cell::{Cell, UnsafeCell};
9use std::future::Future;
10use std::mem;
11use std::mem::ManuallyDrop;
12use std::pin::Pin;
13use std::sync::Arc;
14use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
15
16pub fn run<F, T>(future: F, stack: ProcStack) -> T
37where
38 F: Future<Output = T>,
39{
40 unsafe {
41 let out = &mut UnsafeCell::new(None);
43
44 let future = {
46 let out = out.get();
47
48 async move {
49 *out = Some(future.await);
50 }
51 };
52
53 pin_utils::pin_mut!(future);
55
56 let future = mem::transmute::<
58 Pin<&'_ mut dyn Future<Output = ()>>,
59 Pin<&'static mut dyn Future<Output = ()>>,
60 >(future);
61
62 worker::set_stack(&stack, || block(future));
64
65 match (*out.get()).take() {
67 Some(v) => v,
68 _ => unimplemented!(),
69 }
70 }
71}
72
73fn block<F, T>(f: F) -> T
74where
75 F: Future<Output = T>,
76{
77 thread_local! {
78 static CACHE: Cell<Option<Arc<Parker>>> = Cell::new(None);
84 }
85
86 pin_utils::pin_mut!(f);
87
88 CACHE.with(|cache| {
89 let arc_parker: Arc<Parker> = cache.take().unwrap_or_else(|| Arc::new(Parker::new()));
91
92 let ptr = (&*arc_parker as *const Parker) as *const ();
93 let vt = vtable();
94
95 let waker = unsafe { ManuallyDrop::new(Waker::from_raw(RawWaker::new(ptr, vt))) };
96 let cx = &mut Context::from_waker(&waker);
97
98 loop {
99 if let Poll::Ready(t) = f.as_mut().poll(cx) {
100 cache.set(Some(arc_parker));
102 return t;
103 }
104 arc_parker.park();
105 }
106 })
107}
108
109fn vtable() -> &'static RawWakerVTable {
110 unsafe fn clone_raw(ptr: *const ()) -> RawWaker {
111 #![allow(clippy::redundant_clone)]
112 let arc = ManuallyDrop::new(Arc::from_raw(ptr as *const Parker));
113 mem::forget(arc.clone());
114 RawWaker::new(ptr, vtable())
115 }
116
117 unsafe fn wake_raw(ptr: *const ()) {
118 let arc = Arc::from_raw(ptr as *const Parker);
119 arc.unparker().unpark();
120 }
121
122 unsafe fn wake_by_ref_raw(ptr: *const ()) {
123 let arc = ManuallyDrop::new(Arc::from_raw(ptr as *const Parker));
124 arc.unparker().unpark();
125 }
126
127 unsafe fn drop_raw(ptr: *const ()) {
128 drop(Arc::from_raw(ptr as *const Parker))
129 }
130
131 &RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw)
132}