maniac_runtime/generator/
rt.rs1use std::any::Any;
6use std::cell::Cell;
7use std::mem::MaybeUninit;
8use std::ptr;
9
10use crate::generator::reg_context::RegContext;
11
12thread_local! {
13 static ROOT_CONTEXT_P: Cell<*mut Context> = const { Cell::new(ptr::null_mut()) };
15}
16
17#[derive(Debug, Copy, Clone, Eq, PartialEq)]
19pub enum Error {
20 Done,
22 Cancel,
24 TypeErr,
26 StackErr,
28 ContextErr,
30}
31
32#[repr(C)]
34#[repr(align(128))]
35pub struct Context {
36 pub regs: RegContext,
38 child: *mut Context,
40 pub parent: *mut Context,
42 pub para: MaybeUninit<*mut dyn Any>,
44 pub ret: MaybeUninit<*mut dyn Any>,
46 pub _ref: usize,
48 pub local_data: *mut u8,
50 pub err: Option<Box<dyn Any + Send>>,
52 pub stack_guard: (usize, usize),
54}
55
56impl Context {
57 pub fn new() -> Context {
59 Context {
60 regs: RegContext::empty(),
61 para: MaybeUninit::zeroed(),
62 ret: MaybeUninit::zeroed(),
63 _ref: 1, err: None,
65 child: ptr::null_mut(),
66 parent: ptr::null_mut(),
67 local_data: ptr::null_mut(),
68 stack_guard: (0, 0),
69 }
70 }
71
72 #[inline]
74 pub fn is_generator(&self) -> bool {
75 !std::ptr::eq(self.parent, self)
76 }
77
78 #[inline]
80 pub fn get_para<A>(&mut self) -> Option<A>
81 where
82 A: Any,
83 {
84 let para = unsafe {
85 let para_ptr = *self.para.as_mut_ptr();
86 assert!(!para_ptr.is_null());
87 &mut *para_ptr
88 };
89 match para.downcast_mut::<Option<A>>() {
90 Some(v) => v.take(),
91 None => type_error::<A>("get yield type mismatch error detected"),
92 }
93 }
94
95 #[inline]
97 pub fn co_get_para<A>(&mut self) -> Option<A> {
98 let para = unsafe {
99 let para_ptr = *self.para.as_mut_ptr();
100 debug_assert!(!para_ptr.is_null());
101 &mut *(para_ptr as *mut Option<A>)
102 };
103 para.take()
104 }
105
106 #[inline]
122 pub fn co_set_para<A>(&mut self, data: A) {
123 let para = unsafe {
124 let para_ptr = *self.para.as_mut_ptr();
125 debug_assert!(!para_ptr.is_null());
126 &mut *(para_ptr as *mut Option<A>)
127 };
128 *para = Some(data);
129 }
130
131 #[inline]
133 pub fn set_ret<T>(&mut self, v: T)
134 where
135 T: Any,
136 {
137 let ret = unsafe {
138 let ret_ptr = *self.ret.as_mut_ptr();
139 assert!(!ret_ptr.is_null());
140 &mut *ret_ptr
141 };
142 match ret.downcast_mut::<Option<T>>() {
143 Some(r) => *r = Some(v),
144 None => type_error::<T>("yield type mismatch error detected"),
145 }
146 }
147
148 #[inline]
151 pub fn co_set_ret<T>(&mut self, v: T) {
152 let ret = unsafe {
153 let ret_ptr = *self.ret.as_mut_ptr();
154 debug_assert!(!ret_ptr.is_null());
155 &mut *(ret_ptr as *mut Option<T>)
156 };
157 *ret = Some(v);
158 }
159}
160
161pub struct ContextStack {
163 pub(crate) root: *mut Context,
164}
165
166impl ContextStack {
167 #[cold]
168 fn init_root() -> *mut Context {
169 let root = Box::leak(Box::new(Context::new()));
170 root.parent = root; ROOT_CONTEXT_P.set(root);
172 root
173 }
174
175 pub fn current() -> ContextStack {
177 let mut root = ROOT_CONTEXT_P.get();
178
179 if root.is_null() {
180 root = Self::init_root();
181 }
182
183 #[cfg(all(not(debug_assertions), any(windows, target_os = "macos")))]
188 {
189 let _thread = std::thread::current();
190 let _thread = std::thread::current();
191 }
192
193 ContextStack { root }
194 }
195
196 #[inline]
198 pub fn top(&self) -> &'static mut Context {
199 unsafe {
200 let root = &*self.root;
201 &mut *root.parent
202 }
203 }
204
205 #[inline]
207 pub fn co_ctx(&self) -> Option<&'static mut Context> {
208 let mut ctx = self.top();
210
211 while !std::ptr::eq(ctx, self.root) {
212 if !ctx.local_data.is_null() {
213 return Some(ctx);
214 }
215 ctx = unsafe { &mut *ctx.parent };
216 }
217 None
219 }
220
221 #[inline]
223 pub fn push_context(&self, ctx: *mut Context) {
224 let root = unsafe { &mut *self.root };
225 let ctx = unsafe { &mut *ctx };
226 let top = unsafe { &mut *root.parent };
227 let new_top = ctx.parent;
228
229 top.child = ctx;
231 ctx.parent = top;
232
233 root.parent = new_top;
235 }
236
237 #[inline]
239 pub fn pop_context(&self, ctx: *mut Context) -> &'static mut Context {
240 let root = unsafe { &mut *self.root };
241 let ctx = unsafe { &mut *ctx };
242 let parent = unsafe { &mut *ctx.parent };
243
244 ctx.parent = root.parent;
246 parent.child = ptr::null_mut();
248
249 root.parent = parent;
251
252 parent
253 }
254}
255
256#[inline]
257#[cold]
258fn type_error<A>(msg: &str) -> ! {
259 log::error!("{msg}, expected type: {}", std::any::type_name::<A>());
260 std::panic::panic_any(Error::TypeErr)
261}
262
263#[inline]
265pub fn is_generator() -> bool {
266 let env = ContextStack::current();
267 let root = unsafe { &mut *env.root };
268 !root.child.is_null()
269}
270
271#[inline]
274pub fn get_local_data() -> *mut u8 {
275 let env = ContextStack::current();
276 env.co_ctx().map_or(ptr::null_mut(), |ctx| ctx.local_data)
277}
278
279pub mod guard {
280 use crate::generator::is_generator;
281 use crate::generator::rt::ContextStack;
282 use crate::generator::stack::sys::page_size;
283 use std::ops::Range;
284
285 pub type Guard = Range<usize>;
286
287 pub fn current() -> Guard {
288 assert!(is_generator());
289 let guard = unsafe { (*(*ContextStack::current().root).child).stack_guard };
290
291 guard.0 - page_size()..guard.1
292 }
293}
294
295#[cfg(test)]
296mod test {
297 use super::is_generator;
298
299 #[test]
300 fn test_is_context() {
301 assert!(!is_generator());
303 }
304
305 #[test]
306 fn test_overflow() {
307 use crate::generator::*;
308 use std::panic::catch_unwind;
309
310 for _ in 0..2 {
312 let result = catch_unwind(|| {
313 let mut g = Gn::new_scoped(move |_s: Scope<(), ()>| {
314 let guard = super::guard::current();
315
316 std::hint::black_box(unsafe { *(guard.start as *const usize) });
318
319 eprintln!("entered unreachable code");
320 std::process::abort();
321 });
322
323 g.next();
324 });
325
326 assert!(matches!(
327 result.map_err(|err| *err.downcast::<Error>().unwrap()),
328 Err(Error::StackErr)
329 ));
330 }
331 }
332}