use crate::stack::{Stack, pop, push};
use crate::value::{Value, WeaveMessage};
use std::sync::Arc;
use super::strand_lifecycle::{block_forever, cleanup_strand};
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_yield(stack: Stack) -> Stack {
if stack.is_null() {
eprintln!("yield: stack is null (fatal programming error)");
crate::arena::arena_reset();
cleanup_strand();
block_forever();
}
let (stack, value) = unsafe { pop(stack) };
let (stack, ctx) = unsafe { pop(stack) };
let (yield_chan, resume_chan) = match &ctx {
Value::WeaveCtx {
yield_chan,
resume_chan,
} => (Arc::clone(yield_chan), Arc::clone(resume_chan)),
_ => {
eprintln!(
"yield: expected WeaveCtx on stack, got {:?}. \
yield can only be called inside strand.weave with context threaded through.",
ctx
);
crate::arena::arena_reset();
cleanup_strand();
block_forever();
}
};
let msg_to_send = WeaveMessage::Value(value.clone());
if yield_chan.sender.send(msg_to_send).is_err() {
crate::arena::arena_reset();
cleanup_strand();
block_forever();
}
use crate::scheduler::ACTIVE_STRANDS;
use std::sync::atomic::Ordering;
ACTIVE_STRANDS.fetch_sub(1, Ordering::AcqRel);
let resume_msg = match resume_chan.receiver.recv() {
Ok(msg) => msg,
Err(_) => {
crate::arena::arena_reset();
block_forever();
}
};
match resume_msg {
WeaveMessage::Cancel => {
let _ = yield_chan.sender.send(WeaveMessage::Done);
crate::arena::arena_reset();
block_forever();
}
WeaveMessage::Value(resume_value) => {
ACTIVE_STRANDS.fetch_add(1, Ordering::AcqRel);
let stack = unsafe { push(stack, ctx) };
unsafe { push(stack, resume_value) }
}
WeaveMessage::Done => {
crate::arena::arena_reset();
block_forever();
}
}
}