title | date | author |
---|---|---|
Scalable Stack Overview |
2025-01-08 00:44:00 -0800 |
loongs-zhang |
use open_coroutine_core::co;
use open_coroutine_core::common::constants::CoroutineState;
use open_coroutine_core::coroutine::suspender::Suspender;
use open_coroutine_core::coroutine::Coroutine;
fn main() -> std::io::Result<()> {
let mut co = co!(|_: &Suspender<(), i32>, ()| {
fn recurse(i: u32, p: &mut [u8; 10240]) {
// You can also use `maybe_grow` in thread.
Coroutine::<(), i32, ()>::maybe_grow(|| {
// Ensure the stack allocation isn't optimized away.
unsafe { std::ptr::read_volatile(&p) };
if i > 0 {
recurse(i - 1, &mut [0; 10240]);
}
})
.expect("allocate stack failed")
}
// Use ~500KB of stack.
recurse(50, &mut [0; 10240]);
})?;
assert_eq!(co.resume()?, CoroutineState::Complete(()));
Ok(())
}
The default stack size of coroutine is 128KB, which is sufficient for most scenarios, but there are still some scenarios that are not applicable, such as recursive algorithms. The scalable stack enables annotating fixed points in programs where the stack may want to grow larger. Spills over to the heap if the stack has hit its limit.
flowchart TD
Cond1{In coroutine}
Cond2{Approach the limit}
Cond3{Is the first growing up?}
C[Create a new stack]
RC[Run code on current stack]
RN1[Run code on new stack]
maybe_grow --> Cond1
Cond1 -- Yes --> Cond2
Cond2 -- Yes --> C
Cond2 -- No --> RC
C --> RN1
Cond1 -- No --> Cond3
Cond3 -- Yes --> C
Cond3 -- No --> Cond2