Maintainers
Pricing
Enterprise
More
More
Documentation
Try Live
Rankings
Install
Blog
Docs7
Ask
New
Add Docs
Corosensei
https://docs.rs/corosensei
Admin
A library for coroutine management and related functionalities.
Tokens:
134,355
Snippets:
1,424
Trust Score:
9.1
Update:
4 months ago
Context
Chat
Benchmark
Latest
Show doc for...
Code
Info
Show Results
Tokens:
Raw
Copy
Link
Tokens:
Raw
Copy
Link
### Linked Backtrace Output Example Source: https://docs.rs/corosensei/latest/src/corosensei/lib.rs.html?search=std%3A%3Avec An example of a linked backtrace captured from within a coroutine. It shows the call stack, including the parent function `sub_function` from which the coroutine was resumed. ```text 0: backtrace::main::{{closure}} at examples/backtrace.rs:11:21 corosensei::coroutine::Coroutine<Input,Yield,Return,Stack>::with_stack::coroutine_func::{{closure}} at src/coroutine.rs:163:62 <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once at /rustc/8f9080db423ca0fb6bef0686ce9a93940cdf1f13/library/core/src/panic/unwind_safe.rs:272:9 std::panicking::try::do_call at /rustc/8f9080db423ca0fb6bef0686ce9a93940cdf1f13/library/std/src/panicking.rs:559:40 std::panicking::try at /rustc/8f9080db423ca0fb6bef0686ce9a93940cdf1f13/library/std/src/panicking.rs:523:19 1: std::panic::catch_unwind at /rustc/8f9080db423ca0fb6bef0686ce9a93940cdf1f13/library/std/src/panic.rs:149:14 corosensei::unwind::catch_unwind_at_root at src/unwind.rs:227:13 corosensei::coroutine::Coroutine<Input,Yield,Return,Stack>::with_stack::coroutine_func at src/coroutine.rs:163:30 2: stack_init_trampoline 3: corosensei::arch::x86_64::switch_and_link at src/unwind.rs:137:17 corosensei::coroutine::Coroutine<Input,Yield,Return,Stack>::resume_inner at src/coroutine.rs:239:13 corosensei::coroutine::Coroutine<Input,Yield,Return,Stack>::resume at src/coroutine.rs:218:19 backtrace::sub_function at examples/backtrace.rs:6:5 4: backtrace::main at examples/backtrace.rs:15:5 ``` -------------------------------- ### Example Search Patterns Source: https://docs.rs/corosensei/latest/src/corosensei/scoped.rs.html?search= Illustrates common search patterns used within the Corosensei project for finding specific types or function signatures. ```text std::vec ``` ```text u32 -> bool ``` ```text Option<T>, (T -> U) -> Option<U> ``` -------------------------------- ### Coroutine Panic Handling Example Source: https://docs.rs/corosensei/latest/src/corosensei/lib.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Demonstrates how to create a coroutine, resume it, and catch panics that occur within the coroutine. The output shows the sequence of events from coroutine creation to panic and recovery. ```rust use corosensei::Coroutine; fn main() { let mut coroutine = Coroutine::new(move |_, ()| { println!("[coroutine] yielding 42"); let _ = 42; println!("[coroutine] panicking"); panic!("foobar"); }); println!("[main] creating coroutine"); println!("[main] resuming coroutine"); let result = coroutine.resume(()); println!("[main] got value {:?} from coroutine", result); println!("[main] resuming coroutine"); let result = coroutine.resume(()); println!("[main] caught panic \"{:?}\" from coroutine", result.unwrap_err().downcast_ref::<&'static str>().unwrap()); println!("[main] exiting"); } ``` -------------------------------- ### Creating and Using a ScopedCoroutine Source: https://docs.rs/corosensei/latest/corosensei/struct.ScopedCoroutine.html Demonstrates how to create a ScopedCoroutine, execute it within a scope, and interact with it using resume operations. This example shows a counter incremented by inputs passed during coroutine suspension and resumption. ```rust use corosensei::ScopedCoroutine; let mut counter = 0; let coroutine = ScopedCoroutine::new(|yielder, input| { if input == 0 { return; } counter += input; loop { let input = yielder.suspend(()); if input == 0 { break; } counter += input; } }); coroutine.scope(|mut coroutine| { coroutine.as_mut().resume(1); coroutine.as_mut().resume(2); coroutine.as_mut().resume(3); coroutine.as_mut().resume(4); coroutine.as_mut().resume(5); }); assert_eq!(counter, 15); ``` -------------------------------- ### Coroutine Panic and Recovery Example Source: https://docs.rs/corosensei/latest/src/corosensei/lib.rs.html?search=std%3A%3Avec Demonstrates how a coroutine can panic and how the parent can catch and handle this panic. This is useful for isolating potentially failing operations within a coroutine. ```rust use corosensei::Coroutine; fn main() { let mut coroutine = Coroutine::new(move |_, ()| { println!("[coroutine] yielding 42"); let _ = 42; println!("[coroutine] panicking"); panic!("foobar"); }); println!("[main] creating coroutine"); println!("[main] resuming coroutine"); let result = coroutine.resume(()); if let Err(err) = result { println!("[main] caught panic \"{}\" from coroutine", err.downcast_ref::<&'static str>().unwrap()); } println!("[main] exiting"); } ``` -------------------------------- ### Coroutine Execution and Panic Handling Example Source: https://docs.rs/corosensei/latest/src/corosensei/lib.rs.html?search= Demonstrates the lifecycle of a coroutine, including creation, yielding, resuming, and handling panics. This snippet shows how a panic within a coroutine is caught by the parent. ```rust use corosensei::Coroutine; fn main() { let mut coroutine = Coroutine::new(|_, ()| { println!("[coroutine] yielding 42"); Coroutine::yield_with(42) }); println!("[main] creating coroutine"); println!("[main] resuming coroutine"); let value = coroutine.resume(()).unwrap(); println!("[main] got value {} from coroutine", value); let mut coroutine = Coroutine::new(|_, ()| { println!("[coroutine] panicking"); panic!("foobar"); }); println!("[main] resuming coroutine"); let result = coroutine.resume(()); println!("[main] caught panic \"{}\" from coroutine", result.unwrap_err().downcast_ref::<&'static str>().unwrap() ); println!("[main] exiting"); } ``` -------------------------------- ### ScopedCoroutine Example with Default Stack Source: https://docs.rs/corosensei/latest/src/corosensei/scoped.rs.html?search=std%3A%3Avec Illustrates the usage of ScopedCoroutine with the default stack, showcasing its ability to handle non-'static lifetimes and captured variables within a scoped execution. ```rust use corosensei::ScopedCoroutine; let mut counter = 0; let coroutine = ScopedCoroutine::new(|yielder, input| { if input == 0 { return; } counter += input; loop { let input = yielder.suspend(()); if input == 0 { break; } counter += input; } }); coroutine.scope(|mut coroutine| { coroutine.as_mut().resume(1); coroutine.as_mut().resume(2); coroutine.as_mut().resume(3); coroutine.as_mut().resume(4); coroutine.as_mut().resume(5); }); assert_eq!(counter, 15); ``` -------------------------------- ### Coroutine Panic and Recovery Example Source: https://docs.rs/corosensei/latest/src/corosensei/lib.rs.html Demonstrates how a coroutine can panic and how the parent can catch and handle this panic. This snippet shows the expected output when a coroutine panics and the parent recovers. ```rust use corosensei::Coroutine; fn main() { let mut coroutine = Coroutine::new(move |_, ()| { panic!("foobar"); }); let result = coroutine.resume(()); assert!(result.is_err()); assert_eq!( result.unwrap_err().downcast_ref::<&'static str>().unwrap(), "foobar" ); println!("[main] exiting"); } ``` ```text [main] creating coroutine [main] resuming coroutine [coroutine] yielding 42 [main] got value 42 from coroutine [main] resuming coroutine [coroutine] panicking thread 'main' panicked at 'foobar', examples/panic.rs:13:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace [main] caught panic "foobar" from coroutine [main] exiting ``` -------------------------------- ### Rust Example for Extracting Trap Handler Registers Source: https://docs.rs/corosensei/latest/src/corosensei/arch/x86_64.rs.html Demonstrates how to use Rust's pattern matching to extract individual registers from the `TrapHandlerRegs` struct. This is recommended for ensuring all registers are updated correctly. ```rust # use corosensei::trap::TrapHandlerRegs; # let regs = TrapHandlerRegs { rip: 0, rsp: 0, rbp: 0, rdi: 0, rsi: 0 }; let TrapHandlerRegs { rip, rsp, rbp, rdi, rsi } = regs; ``` -------------------------------- ### Setup Trap Handler and Return Source: https://docs.rs/corosensei/latest/corosensei/trap/struct.CoroutineTrapHandler.html?search= Sets up the stack and register state to execute a given function when the trap handler returns, causing the coroutine to exit with the function's result. The stack is reset, and returned registers must be updated. ```rust pub unsafe fn setup_trap_handler<F>(&self, f: F) -> TrapHandlerRegs where F: FnOnce() -> Return + 'static, ``` -------------------------------- ### Coroutine Panic Propagation Example Source: https://docs.rs/corosensei/latest/corosensei/index.html Illustrates how panics occurring within a coroutine are propagated to the caller. The coroutine is considered complete after a panic. ```Rust use std::panic::{catch_unwind, AssertUnwindSafe}; use corosensei::Coroutine; fn main() { println!("[main] creating coroutine"); let mut coroutine = Coroutine::new(|yielder, ()| { println!("[coroutine] yielding 42"); yielder.suspend(42); println!("[coroutine] panicking"); panic!("foobar"); }); println!("[main] resuming coroutine"); let result = catch_unwind(AssertUnwindSafe(|| coroutine.resume(()))); println!( "[main] got value {} from coroutine", result.unwrap().as_yield().unwrap() ); println!("[main] resuming coroutine"); let result = catch_unwind(AssertUnwindSafe(|| coroutine.resume(()))); println!( "[main] caught panic \"{}\" from coroutine", result.unwrap_err().downcast_ref::<&'static str>().unwrap() ); println!("[main] exiting"); } ``` -------------------------------- ### Coroutine Panic Propagation Example Source: https://docs.rs/corosensei/latest/src/corosensei/lib.rs.html?search= Illustrates how panics within a coroutine unwind through the coroutine stack and then out to the caller. Shows how to catch panics using `std::panic::catch_unwind`. ```rust use std::panic::{catch_unwind, AssertUnwindSafe}; use corosensei::Coroutine; fn main() { println!("[main] creating coroutine"); let mut coroutine = Coroutine::new(|yielder, ()| { println!("[coroutine] yielding 42"); yielder.suspend(42); println!("[coroutine] panicking"); panic!("foobar"); }); println!("[main] resuming coroutine"); let result = catch_unwind(AssertUnwindSafe(|| coroutine.resume(()))); println!( "[main] got value {} from coroutine", result.unwrap().as_yield().unwrap() ); println!("[main] resuming coroutine"); let result = catch_unwind(AssertUnwindSafe(|| coroutine.resume(()))); println!( "[main] caught panic \"{}\" from coroutine", ``` -------------------------------- ### Setup Trap Trampoline for Handler Execution Source: https://docs.rs/corosensei/latest/src/corosensei/arch/x86_64.rs.html?search= Prepares the stack and registers to jump to a trap handler function with a specific argument. This function ensures the correct state for resuming execution after a trap. ```rust let parent_link = stack_base.get() - PARENT_LINK_OFFSET; // Everything below this can be overwritten. Write the object to the stack. let mut sp = parent_link; allocate_obj_on_stack(&mut sp, 16, val); let val_ptr = sp; // Set up a return address which returns to stack_init_trampoline. This has // the necessary unwinding metadata to switch back to the primary stack when // unwinding. push( &mut sp, Some(stack_init_trampoline_return.as_ptr() as StackWord), ); // Set up registers for entry into the function. TrapHandlerRegs { rip: handler as u64, rsp: sp as u64, rdi: val_ptr as u64, rsi: parent_link as u64, rbp: parent_link as u64, } ``` -------------------------------- ### Scoped Coroutine Example with Counter Source: https://docs.rs/corosensei/latest/src/corosensei/scoped.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Demonstrates creating and running a ScopedCoroutine that increments a counter based on input values. The coroutine suspends and resumes to process multiple inputs. ```rust use corosensei::ScopedCoroutine; let mut counter = 0; let coroutine = ScopedCoroutine::new(|yielder: &Yielder<i32, ()>, input| { if input == 0 { return; } counter += input; loop { let input = yielder.suspend(()); if input == 0 { break; } counter += input; } }); coroutine.scope(|mut coroutine| { coroutine.as_mut().resume(1); coroutine.as_mut().resume(2); coroutine.as_mut().resume(3); coroutine.as_mut().resume(4); coroutine.as_mut().resume(5); }); assert_eq!(counter, 15); ``` -------------------------------- ### Coroutine Output Log Source: https://docs.rs/corosensei/latest/src/corosensei/lib.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E This is the expected output log for the coroutine panic handling example, showing the sequence of messages printed to the console. ```text [main] creating coroutine [main] resuming coroutine [coroutine] yielding 42 [main] got value 42 from coroutine [main] resuming coroutine [coroutine] panicking thread 'main' panicked at 'foobar', examples/panic.rs:13:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace [main] caught panic "foobar" from coroutine [main] exiting ``` -------------------------------- ### Scoped Coroutine Example with Counter Source: https://docs.rs/corosensei/latest/src/corosensei/scoped.rs.html Demonstrates creating and running a ScopedCoroutine that increments a counter. The coroutine suspends and resumes to process inputs, and the counter is asserted after the scope. ```rust use corosensei::{ScopedCoroutine, Yielder}; let mut counter = 0; let coroutine = ScopedCoroutine::new(|yielder: &Yielder<i32, ()>, input| { if input == 0 { return; } counter += input; loop { let input = yielder.suspend(()); if input == 0 { break; } counter += input; } }); coroutine.scope(|mut coroutine| { coroutine.as_mut().resume(1); coroutine.as_mut().resume(2); coroutine.as_mut().resume(3); coroutine.as_mut().resume(4); coroutine.as_mut().resume(5); }); assert_eq!(counter, 15); ``` -------------------------------- ### Start Fiber Switch with Sanitizer Source: https://docs.rs/corosensei/latest/src/corosensei/sanitizer.rs.html Initiates a fiber switch by notifying the AddressSanitizer runtime. It saves the current stack information and returns a pointer to the fake stack save area. Requires the 'sanitizer' feature. ```rust pub(crate) unsafe fn start_switch(&self) -> *mut u8 { let mut fake_stack = core::ptr::null_mut(); __sanitizer_start_switch_fiber(&mut fake_stack, self.bottom, self.size); fake_stack } ``` -------------------------------- ### SanitizerFiber Methods (Enabled) Source: https://docs.rs/corosensei/latest/src/corosensei/sanitizer.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Provides inline methods for managing fiber switching and memory unpoisoning when the 'sanitizer' feature is enabled. Includes functions to start and finish fiber switches, derive SanitizerFiber from a parent link, and unpoison the stack. ```rust impl SanitizerFiber { #[inline] pub(crate) unsafe fn start_switch(&self) -> *mut u8 { let mut fake_stack = core::ptr::null_mut(); __sanitizer_start_switch_fiber(&mut fake_stack, self.bottom, self.size); fake_stack } #[inline] pub(crate) unsafe fn finish_switch(fake_stack: *mut u8) -> Self { let mut bottom = core::ptr::null(); let mut size = 0; __sanitizer_finish_switch_fiber(fake_stack, &mut bottom, &mut size); Self { bottom, size } } #[inline] pub(crate) unsafe fn from_parent_link(parent_link: *mut StackPointer) -> *mut Self { parent_link.byte_add(crate::arch::PARENT_LINK_OFFSET).cast() } #[inline] pub(crate) unsafe fn unpoison_stack(&self) { __asan_unpoison_memory_region(self.bottom, self.size); } } ``` -------------------------------- ### Backtrace Output with Linked Stack Source: https://docs.rs/corosensei/latest/src/corosensei/lib.rs.html?search=u32+-%3E+bool The expected backtrace output from the linked backtraces example, showing the call stack including the parent function `sub_function`. ```text 0: backtrace::main::{{closure}} at examples/backtrace.rs:11:21 corosensei::coroutine::Coroutine<Input,Yield,Return,Stack>::with_stack::coroutine_func::{{closure}} at src/coroutine.rs:163:62 <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once at /rustc/8f9080db423ca0fb6bef0686ce9a93940cdf1f13/library/core/src/panic/unwind_safe.rs:272:9 std::panicking::try::do_call at /rustc/8f9080db423ca0fb6bef0686ce9a93940cdf1f13/library/std/src/panicking.rs:559:40 std::panicking::try at /rustc/8f9080db423ca0fb6bef0686ce9a93940cdf1f13/library/std/src/panicking.rs:523:19 1: std::panic::catch_unwind at /rustc/8f9080db423ca0fb6bef0686ce9a93940cdf1f13/library/std/src/panic.rs:149:14 corosensei::unwind::catch_unwind_at_root at src/unwind.rs:227:13 corosensei::coroutine::Coroutine<Input,Yield,Return,Stack>::with_stack::coroutine_func at src/coroutine.rs:163:30 2: stack_init_trampoline 3: corosensei::arch::x86_64::switch_and_link at src/unwind.rs:137:17 corosensei::coroutine::Coroutine<Input,Yield,Return,Stack>::resume_inner at src/coroutine.rs:239:13 corosensei::coroutine::Coroutine<Input,Yield,Return,Stack>::resume at src/coroutine.rs:218:19 backtrace::sub_function at examples/backtrace.rs:6:5 4: backtrace::main at examples/backtrace.rs:15:5 ``` -------------------------------- ### Setup Trap Trampoline Source: https://docs.rs/corosensei/latest/src/corosensei/arch/x86_64.rs.html?search=std%3A%3Avec Sets up the stack and register state for a trap handler to jump to a given function with a specific argument. It preserves the parent link, allocates space for the object, and sets up return addresses and registers. ```rust let parent_link = stack_base.get() - PARENT_LINK_OFFSET; // Everything below this can be overwritten. Write the object to the stack. let mut sp = parent_link; allocate_obj_on_stack(&mut sp, 16, val); let val_ptr = sp; // Set up a return address which returns to stack_init_trampoline. This has // the necessary unwinding metadata to switch back to the primary stack when // unwinding. push( &mut sp, Some(stack_init_trampoline_return.as_ptr() as StackWord), ); // Set up registers for entry into the function. TrapHandlerRegs { rip: handler as u64, rsp: sp as u64, rdi: val_ptr as u64, rsi: parent_link as u64, rbp: parent_link as u64, } ``` -------------------------------- ### Rust Function to Setup Trap Trampoline Source: https://docs.rs/corosensei/latest/src/corosensei/arch/x86_64.rs.html Sets up the stack and register state for a trap handler. It prepares the stack by writing the object and a return address, then configures registers to jump to a specified handler function with a given argument. ```rust pub unsafe fn setup_trap_trampoline<T>( stack_base: StackPointer, val: T, handler: TrapHandler<T>, ) -> TrapHandlerRegs { // Preserve the top 16 bytes of the stack since they contain the parent // link. let parent_link = stack_base.get() - PARENT_LINK_OFFSET; // Everything below this can be overwritten. Write the object to the stack. let mut sp = parent_link; allocate_obj_on_stack(&mut sp, 16, val); let val_ptr = sp; // Set up a return address which returns to stack_init_trampoline. This has // the necessary unwinding metadata to switch back to the primary stack when // unwinding. push( &mut sp, Some(stack_init_trampoline_return.as_ptr() as StackWord), ); // Set up registers for entry into the function. TrapHandlerRegs { rip: handler as u64, rsp: sp as u64, rdi: val_ptr as u64, rsi: parent_link as u64, rbp: parent_link as u64, } } ``` -------------------------------- ### Setup Trap Handler for Return Source: https://docs.rs/corosensei/latest/src/corosensei/trap.rs.html Configures the coroutine's stack and registers to execute a given function upon returning from a trap handler, ultimately exiting the coroutine with the function's result. The coroutine stack is reset, and all previous data is discarded. ```rust pub unsafe fn setup_trap_handler<F>(&self, f: F) -> TrapHandlerRegs where F: FnOnce() -> Return, F: 'static, { initial_func_abi! { // This function is executed on the coroutine stack once execution // is resumed from the trap handler. unsafe fn trap_handler<F: FnOnce() -> Return, Return>( f: *mut F, parent_link: *mut StackPointer ) -> ! { // This must be called after a stack overflow exception, but it // doesn't hurt to call it for other exception types as well. #[cfg(windows)] reset_guard_page(); let result = crate::unwind::catch_unwind_at_root(f.read()); // If using sanitizers, restore the parent's stack bounds. unsafe { (*SanitizerFiber::from_parent_link(parent_link)).start_switch(); } let mut result = ManuallyDrop::new(result); arch::switch_and_reset(util::encode_val(&mut result), parent_link); } } // Clear any existing ASAN poisoning on the stack before it is re-used. unsafe { sanitizer::unpoison_stack_range(self.stack_base, self.stack_limit); } // Move the value into the coroutine stack so that it is still available // after the trap handler returns. Then defer to the arch-specific code } ``` -------------------------------- ### Linked Backtraces in Coroutines Source: https://docs.rs/corosensei/latest/src/corosensei/lib.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Demonstrates how coroutines preserve and link backtraces, allowing debugging tools to show the call stack that led to the coroutine's execution. The example shows a backtrace that includes the parent function `sub_function`. ```rust use backtrace::Backtrace; use corosensei::Coroutine; #[inline(never)] fn sub_function(coroutine: &mut Coroutine<(), (), ()>) { coroutine.resume(()); } fn main() { let mut coroutine = Coroutine::new(move |_, ()| { let trace = Backtrace::new(); println!("{:?}", trace); }); sub_function(&mut coroutine); } ``` -------------------------------- ### Setup Trap Handler for Return Source: https://docs.rs/corosensei/latest/src/corosensei/trap.rs.html?search=std%3A%3Avec Configures the coroutine's stack and registers to execute a provided function upon returning from a trap handler. The result of this function will be used as the coroutine's return value. This function resets the coroutine's stack and requires careful handling of memory access due to strict safety requirements. ```rust pub unsafe fn setup_trap_handler<F>(&self, f: F) -> TrapHandlerRegs where F: FnOnce() -> Return, F: 'static, { initial_func_abi! { // This function is executed on the coroutine stack once execution // is resumed from the trap handler. unsafe fn trap_handler<F: FnOnce() -> Return, Return>( f: *mut F, parent_link: *mut StackPointer ) -> ! { // This must be called after a stack overflow exception, but it // doesn't hurt to call it for other exception types as well. #[cfg(windows)] reset_guard_page(); let result = crate::unwind::catch_unwind_at_root(f.read()); // If using sanitizers, restore the parent's stack bounds. unsafe { (*SanitizerFiber::from_parent_link(parent_link)).start_switch(); } let mut result = ManuallyDrop::new(result); arch::switch_and_reset(util::encode_val(&mut result), parent_link); } } // Clear any existing ASAN poisoning on the stack before it is re-used. unsafe { sanitizer::unpoison_stack_range(self.stack_base, self.stack_limit); } // Move the value into the coroutine stack so that it is still available // after the trap handler returns. Then defer to the arch-specific code // to set up the register state for a call. } ``` -------------------------------- ### started Source: https://docs.rs/corosensei/latest/src/corosensei/coroutine.rs.html Returns whether this coroutine has been resumed at least once. ```APIDOC ## started ### Description Returns whether this coroutine has been resumed at least once. ### Method `started` ### Parameters None ### Response #### Success Response - **bool** - `true` if the coroutine has been resumed, `false` otherwise. ### Example ```rust if coroutine.started() { // Coroutine has been resumed before } else { // Coroutine has not been resumed yet } ``` ``` -------------------------------- ### started Source: https://docs.rs/corosensei/latest/src/corosensei/coroutine.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Returns whether this coroutine has been resumed at least once. ```APIDOC ## started ### Description Checks if the coroutine has been initiated and resumed at least once since its creation. ### Method `started(&self) -> bool` ### Parameters None ### Response #### Success Response - **bool** - `true` if the coroutine has been resumed, `false` otherwise. ### Response Example ```json { "example": "true" } ``` ``` -------------------------------- ### Coroutine Initialization Source: https://docs.rs/corosensei/latest/src/corosensei/coroutine.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Sets up the stack and initial state for a new coroutine, preparing it to execute the provided function. ```rust unsafe { // Set up the stack so that the coroutine starts executing // coroutine_func. Write the given function object to the stack so // its address is passed to coroutine_func on the first resume. let stack_ptr = arch::init_stack(&stack, coroutine_func::<Input, Yield, Return, F>, func); let sanitizer_fiber = stack.sanitizer_fiber(); Self { stack, stack_ptr: Some(stack_ptr), initial_stack_ptr: stack_ptr, drop_fn: drop_fn::<F>, sanitizer_fiber, marker: PhantomData, marker2: PhantomData, } } ``` -------------------------------- ### Coroutine Creation and Basic Usage Source: https://docs.rs/corosensei/latest/corosensei/index.html Demonstrates how to create a coroutine, resume it with input, and handle yielded values or return values. This is useful for implementing cooperative multitasking or state machines. ```Rust use corosensei::{Coroutine, CoroutineResult}; fn main() { println!("[main] creating coroutine"); let mut coroutine = Coroutine::new(|yielder, input| { println!("[coroutine] coroutine started with input {}", input); for i in 0..5 { println!("[coroutine] yielding {}", i); let input = yielder.suspend(i); println!("[coroutine] got {} from parent", input) } println!("[coroutine] exiting coroutine"); }); let mut counter = 100; loop { println!("[main] resuming coroutine with argument {}", counter); match coroutine.resume(counter) { CoroutineResult::Yield(i) => println!("[main] got {:?} from coroutine", i), CoroutineResult::Return(()) => break, } counter += 1; } println!("[main] exiting"); } ``` -------------------------------- ### started Source: https://docs.rs/corosensei/latest/src/corosensei/coroutine.rs.html?search= Checks if the coroutine has been resumed at least once since its creation. ```APIDOC ## started ### Description Returns a boolean indicating whether this coroutine has been resumed at least once. ### Method `started(&self) -> bool` ### Parameters None ### Request Example None ### Response #### Success Response - `bool`: `true` if the coroutine has been resumed, `false` otherwise. #### Response Example ```json { "example": "true" } ``` ``` -------------------------------- ### Get Sanitizer Fiber Source: https://docs.rs/corosensei/latest/src/corosensei/coroutine.rs.html?search= Returns the associated sanitizer fiber. This is an internal helper function. ```rust #[inline] fn sanitizer_fiber(&self) -> SanitizerFiber { self.sanitizer_fiber } ``` -------------------------------- ### Get Stack Limit Source: https://docs.rs/corosensei/latest/src/corosensei/coroutine.rs.html?search= Returns the base of the stack pointer. This is an internal helper function. ```rust #[inline] fn limit(&self) -> StackPointer { self.stack_base } ``` -------------------------------- ### Checking if Coroutine Has Started Source: https://docs.rs/corosensei/latest/corosensei/struct.ScopedCoroutineRef.html Returns true if the coroutine has been resumed at least once, indicating that its execution has begun. ```rust pub fn started(&self) -> bool ``` -------------------------------- ### ScopedCoroutineRef::started Source: https://docs.rs/corosensei/latest/src/corosensei/scoped.rs.html?search= Checks if the coroutine has been resumed at least once. Returns true if the coroutine has started execution, false otherwise. ```APIDOC ## ScopedCoroutineRef::started ### Description Returns whether this coroutine has been resumed at least once. ### Method `started` ### Parameters None ### Returns `bool` - `true` if the coroutine has started execution, `false` otherwise. ``` -------------------------------- ### Get Stack Base Address Source: https://docs.rs/corosensei/latest/corosensei/stack/struct.DefaultStack.html Returns the base address of the stack. For stacks that grow downwards, this is the highest memory address. ```rust fn base(&self) -> StackPointer ``` -------------------------------- ### Coroutine Basic Usage Source: https://docs.rs/corosensei Demonstrates the fundamental creation, yielding, and resuming of a coroutine. Use this to understand the core coroutine lifecycle. ```Rust use corosensei::{Coroutine, CoroutineResult}; fn main() { println!("[main] creating coroutine"); let mut coroutine = Coroutine::new(|yielder, input| { println!("[coroutine] coroutine started with input {}", input); for i in 0..5 { println!("[coroutine] yielding {}", i); let input = yielder.suspend(i); println!("[coroutine] got {} from parent", input) } println!("[coroutine] exiting coroutine"); }); let mut counter = 100; loop { println!("[main] resuming coroutine with argument {}", counter); match coroutine.resume(counter) { CoroutineResult::Yield(i) => println!("[main] got {{:?}} from coroutine", i), CoroutineResult::Return(()) => break, } counter += 1; } println!("[main] exiting"); } ``` -------------------------------- ### Get SanitizerFiber from Parent Link Source: https://docs.rs/corosensei/latest/src/corosensei/sanitizer.rs.html Calculates the memory address of the SanitizerFiber associated with a parent stack pointer. Requires the 'sanitizer' feature. ```rust pub(crate) unsafe fn from_parent_link(parent_link: *mut StackPointer) -> *mut Self { parent_link.byte_add(crate::arch::PARENT_LINK_OFFSET).cast() } ``` -------------------------------- ### Get Stack Limit Address Source: https://docs.rs/corosensei/latest/corosensei/stack/struct.DefaultStack.html Returns the maximum limit address of the stack. For stacks that grow downwards, this is the lowest memory address. ```rust fn limit(&self) -> StackPointer ``` -------------------------------- ### x86_64 Stack Layout for Running Coroutine (UEFI) Source: https://docs.rs/corosensei/latest/src/corosensei/arch/x86_64.rs.html Illustrates the stack layout on UEFI targets when a coroutine is running. An additional 'Secondary RIP' is present below 'Saved RBX' to accommodate SEH unwinding requirements, which always pops a return address. ```text | | ~ ... ~ | | +----------------+ | Secondary RIP | <- Only on UEFI; used by the SEH unwinder. +----------------+ | Saved RBX | +----------------+ | Saved RIP | +----------------+ | Saved RBP | +----------------+ <- Parent link points here. ``` -------------------------------- ### x86_64 Inline Assembly for Function Call Source: https://docs.rs/corosensei/latest/src/corosensei/arch/x86_64.rs.html Sets up arguments and performs a jump to a function using inline assembly. This avoids issues with the CPU's return address predictor by using JMP instead of CALL. ```Assembly mov rdx, rsp ``` ```Assembly lea rcx, [rip + 0f] ``` ```Assembly push rcx ``` ```Assembly jmp [rsi + 8] ``` ```Assembly 0: ``` ```Assembly int3 ``` ```Assembly cfi!(".cfi_endproc") ``` ```Assembly asm_function_alt_entry!("stack_init_trampoline_return") ``` ```Assembly asm_function_end!("stack_init_trampoline") ``` -------------------------------- ### Coroutine Trap Handler Setup Source: https://docs.rs/corosensei/latest/src/corosensei/coroutine.rs.html?search=std%3A%3Avec Returns a CoroutineTrapHandler for managing traps within a coroutine. This is an unsafe operation requiring careful usage. ```rust pub fn trap_handler(&self) -> CoroutineTrapHandler<Return> { CoroutineTrapHandler { stack_base: adjusted_stack_base(&self.stack), stack_limit: self.stack.limit(), marker: PhantomData, } } ``` -------------------------------- ### x86_64 Stack Layout for Running Coroutine (UEFI Target) Source: https://docs.rs/corosensei/latest/src/corosensei/arch/x86_64.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Details the stack layout on UEFI targets when a coroutine is running, including the secondary RIP for SEH unwinding. ```text | | ~ | | +----------------+ | Secondary RIP | +----------------+ | Saved RBX | +----------------+ | Saved RIP | +----------------+ | Saved RBP | +----------------+ <- ``` -------------------------------- ### Coroutine Send Trait Constraint Example Source: https://docs.rs/corosensei/latest/src/corosensei/coroutine.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Illustrates that Coroutine does not implement the Send trait by default, as its stack contents may not always be Send. ```rust /// ```compile_fail /// fn send<T: Send>() {} /// send::<corosensei::Coroutine<(), ()>>(); /// ``` ``` -------------------------------- ### Stack Trait Implementation for DefaultStack Source: https://docs.rs/corosensei/latest/src/corosensei/stack/unix.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Implements the `Stack` trait for `DefaultStack`, providing methods to get the base and limit of the allocated stack memory. ```rust unsafe impl Stack for DefaultStack { #[inline] fn base(&self) -> StackPointer { self.base } #[inline] fn limit(&self) -> StackPointer { StackPointer::new(self.base.get() - self.mmap_len).unwrap() } } ``` -------------------------------- ### Scoped Coroutine Creation with Default Stack Source: https://docs.rs/corosensei/latest/src/corosensei/scoped.rs.html?search= Shows how to create a ScopedCoroutine using the default stack. This is a convenient way to instantiate a coroutine when a specific stack implementation is not required. ```rust use corosensei::ScopedCoroutine; let mut counter = 0; let coroutine = ScopedCoroutine::new(|yielder, input| { if input == 0 { return; } counter += input; loop { let input = yielder.suspend(()); if input == 0 { break; } counter += input; } }); ``` -------------------------------- ### Get Coroutine Trap Handler Source: https://docs.rs/corosensei/latest/src/corosensei/scoped.rs.html?search= Returns a CoroutineTrapHandler for managing traps like invalid memory accesses within the coroutine. This is an extremely unsafe operation. ```rust pub fn trap_handler(&self) -> CoroutineTrapHandler<Input, Yield, Return, Stack> { self.inner.trap_handler() } ``` -------------------------------- ### Stack Initialization Trampoline Assembly Source: https://docs.rs/corosensei/latest/src/corosensei/arch/x86_64.rs.html?search=std%3A%3Avec Sets up the initial function call on a new stack using assembly. Avoids CALL instruction for better return address predictor alignment by using JMP. ```assembly mov rdx, rsp lea rcx, [rip + 0f] push rcx jmp [rsi + 8] ``` -------------------------------- ### Getting Coroutine Trap Handler Source: https://docs.rs/corosensei/latest/corosensei/struct.ScopedCoroutineRef.html Returns a CoroutineTrapHandler for managing traps like invalid memory access within the coroutine. This is an extremely unsafe operation. ```rust pub fn trap_handler(&self) -> CoroutineTrapHandler<Return> ``` -------------------------------- ### ScopedCoroutineRef::CoroutineTrapHandler Source: https://docs.rs/corosensei/latest/src/corosensei/scoped.rs.html?search=std%3A%3Avec Returns a `CoroutineTrapHandler` which can be used to handle traps that occur inside the coroutine. Examples of traps that can be handled are invalid memory accesses and stack overflows. ```APIDOC ## ScopedCoroutineRef::CoroutineTrapHandler ### Description Returns a [`CoroutineTrapHandler`] which can be used to handle traps that occur inside the coroutine. Examples of traps that can be handled are invalid memory accesses and stack overflows. The returned [`CoroutineTrapHandler`] can be used in a trap handler to force the trapping coroutine to return with a specific value, after which is it considered to have completed and can no longer be resumed. Needless to say, this is extremely unsafe and must be used with extreme care. See [`CoroutineTrapHandler::setup_trap_handler`] for the exact usage. ### Method (Implicitly accessed via `self` to get a `CoroutineTrapHandler`) ### Parameters None ### Returns A `CoroutineTrapHandler` instance. ### Safety Extremely unsafe and must be used with extreme care. ``` -------------------------------- ### DefaultStack::new Source: https://docs.rs/corosensei/latest/corosensei/stack/struct.DefaultStack.html Creates a new DefaultStack with a specified minimum capacity. This is the primary constructor for the DefaultStack. ```APIDOC ## DefaultStack::new ### Description Creates a new stack which has at least the given capacity. ### Signature `pub fn new(size: usize) -> Result<Self>` ### Parameters #### Path Parameters - **size** (usize) - Required - The minimum capacity for the new stack. ### Response #### Success Response (Result<Self>) - **Self** - The newly created `DefaultStack` instance. #### Error Response (Result<Self>) - **Error** - An error if the stack could not be created. ``` -------------------------------- ### x86_64 Assembly for switch_and_link Source: https://docs.rs/corosensei/latest/src/corosensei/arch/x86_64.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Implements context switching to a coroutine. Saves parent context, sets up the new stack frame, and prepares for coroutine execution. Uses `inlateout` and `in` for argument passing and `lateout` for clobbered registers. ```rust asm!( "ret", "2:", "push rbp", "mov [rsi - 16], rsp", "lea rsp, [rdx + 8]", "pop rbx", "pop rbp", "rdi" => ret_val, "rdx" => parent_link as u64, lateout("r12") _, lateout("r13") _, lateout("r14") _, lateout("r15") _, clobber_abi("sysv64"), ); ``` -------------------------------- ### Stack Trait Source: https://docs.rs/corosensei/latest/corosensei/stack/trait.Stack.html?search= Defines the interface for stack ownership. It requires methods to get the base and limit addresses of the stack, ensuring proper memory management and safety. ```APIDOC ## Trait Stack ### Description A trait for objects that hold ownership of a stack. ### Safety To preserve memory safety, a stack must have a guard page which catches stack overflows. It must also contain at least `MIN_STACK_SIZE` bytes of usable memory. ### Required Methods #### fn base(&self) -> StackPointer Returns the base address of the stack. This is the highest address since stacks grow downwards on most modern architectures. Must be aligned to `STACK_ALIGNMENT`. #### fn limit(&self) -> StackPointer Returns the maximum limit address of the stack. This is the lowest address since stacks grow downwards on most modern architectures. This limit must include any guard pages in the stack. Must be aligned to `STACK_ALIGNMENT`. ### Dyn Compatibility This trait **is** dyn compatible. ``` -------------------------------- ### Define initial_func_abi macro for x86_64 SysV64 ABI Source: https://docs.rs/corosensei/latest/src/corosensei/unwind.rs.html?search= Defines a macro to correctly apply the `sysv64-unwind` ABI to function definitions for `InitialFunc` on x86_64. ```Rust macro_rules! initial_func_abi { (unsafe fn $($tt:tt)*) => { unsafe extern "sysv64-unwind" fn $($tt)* } } ``` -------------------------------- ### x86_64 Stack Layout for Initialized Coroutine Source: https://docs.rs/corosensei/latest/src/corosensei/arch/x86_64.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Presents the stack layout immediately after a coroutine has been initialized but before its first resume. The parent link is not yet filled. ```text +--------------+ <- | Initial func | +--------------+ | Parent link | +--------------+ | ~ Initial obj ~ | +--------------+ | Initial RIP | +--------------+ <- ``` -------------------------------- ### x86_64 Stack Initialization Trampoline Source: https://docs.rs/corosensei/latest/src/corosensei/arch/x86_64.rs.html This assembly code defines the `stack_init_trampoline` function, which serves as the base entry point for coroutines. It sets up the stack frame, handles unwinding information for both DWARF CFI and UEFI SEH, and prepares the stack for the initial coroutine execution. ```rust global_asm!( ".balign 16", asm_function_begin!("stack_init_trampoline"), cfi!(".cfi_startproc"), seh!(".seh_proc stack_init_trampoline"), cfi!(cfi_signal_frame!()), "push rbp", "mov [rsi - 16], rsp", "sub rsi, 16", "lea rsp, [rdx + 8]", "mov rbp, [rsi + 16]" ); ``` -------------------------------- ### Drop Initial Coroutine Object Source: https://docs.rs/corosensei/latest/src/corosensei/arch/x86_64.rs.html?search=std%3A%3Avec Drops the initial object on a coroutine stack that has not yet started execution. It calculates the pointer to the object and calls the provided drop function. ```rust let ptr = (stack_ptr.get() as *mut u8).add(8); drop_fn(ptr); ``` -------------------------------- ### Valgrind Stack Registration for powerpc64 (No-op) Source: https://docs.rs/corosensei/latest/src/corosensei/stack/valgrind.rs.html Provides a no-operation placeholder for Valgrind stack registration on powerpc64 architecture, as Valgrind support is pending. The function returns the default value without performing any Valgrind-specific operations. ```rust type Value = u64; // FIXME: look at Valgrind later, use a no-op for now. #[inline] unsafe fn valgrind_request(default: Value, _args: &[Value; 6]) -> Value { default } ```