use crate::stack::{Stack, pop, push};
use crate::tagged_stack::StackValue;
use crate::value::{Value, WeaveChannelData, WeaveMessage};
use may::sync::mpmc;
use std::sync::Arc;
use super::strand_lifecycle::cleanup_strand;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_weave(stack: Stack) -> Stack {
if stack.is_null() {
eprintln!("strand.weave: stack is null (fatal programming error)");
std::process::abort();
}
let (yield_sender, yield_receiver) = mpmc::channel();
let yield_chan = Arc::new(WeaveChannelData {
sender: yield_sender,
receiver: yield_receiver,
});
let (resume_sender, resume_receiver) = mpmc::channel();
let resume_chan = Arc::new(WeaveChannelData {
sender: resume_sender,
receiver: resume_receiver,
});
let (stack, quot_value) = unsafe { pop(stack) };
let weave_ctx_yield = Arc::clone(&yield_chan);
let weave_ctx_resume = Arc::clone(&resume_chan);
let handle_yield = Arc::clone(&yield_chan);
let handle_resume = Arc::clone(&resume_chan);
match quot_value {
Value::Quotation { wrapper, .. } => {
if wrapper == 0 {
eprintln!(
"strand.weave: quotation wrapper function pointer is null (compiler bug)"
);
std::process::abort();
}
use crate::scheduler::ACTIVE_STRANDS;
use may::coroutine;
use std::sync::atomic::Ordering;
let fn_ptr: extern "C" fn(Stack) -> Stack = unsafe { std::mem::transmute(wrapper) };
let (child_stack, child_base) = unsafe { crate::stack::clone_stack_with_base(stack) };
let stack_addr = child_stack as usize;
let base_addr = child_base as usize;
unsafe {
coroutine::spawn(move || {
let child_stack = stack_addr as *mut StackValue;
let child_base = base_addr as *mut StackValue;
if !child_base.is_null() {
crate::stack::patch_seq_set_stack_base(child_base);
}
let first_msg = match weave_ctx_resume.receiver.recv() {
Ok(msg) => msg,
Err(_) => {
return;
}
};
let first_value = match first_msg {
WeaveMessage::Cancel => {
crate::arena::arena_reset();
return;
}
WeaveMessage::Value(v) => v,
WeaveMessage::Done => {
return;
}
};
ACTIVE_STRANDS.fetch_add(1, Ordering::Release);
let weave_ctx = Value::WeaveCtx {
yield_chan: weave_ctx_yield.clone(),
resume_chan: weave_ctx_resume.clone(),
};
let stack_with_ctx = push(child_stack, weave_ctx);
let stack_with_value = push(stack_with_ctx, first_value);
let final_stack = fn_ptr(stack_with_value);
let (_, ctx_value) = pop(final_stack);
if let Value::WeaveCtx { yield_chan, .. } = ctx_value {
let _ = yield_chan.sender.send(WeaveMessage::Done);
}
crate::arena::arena_reset();
cleanup_strand();
});
}
}
Value::Closure { fn_ptr, env } => {
if fn_ptr == 0 {
eprintln!("strand.weave: closure function pointer is null (compiler bug)");
std::process::abort();
}
use crate::scheduler::ACTIVE_STRANDS;
use may::coroutine;
use std::sync::atomic::Ordering;
let fn_ref: extern "C" fn(Stack, *const Value, usize) -> Stack =
unsafe { std::mem::transmute(fn_ptr) };
let env_clone: Vec<Value> = env.iter().cloned().collect();
let child_base = crate::stack::alloc_stack();
let base_addr = child_base as usize;
unsafe {
coroutine::spawn(move || {
let child_base = base_addr as *mut StackValue;
crate::stack::patch_seq_set_stack_base(child_base);
let first_msg = match weave_ctx_resume.receiver.recv() {
Ok(msg) => msg,
Err(_) => {
return;
}
};
let first_value = match first_msg {
WeaveMessage::Cancel => {
crate::arena::arena_reset();
return;
}
WeaveMessage::Value(v) => v,
WeaveMessage::Done => {
return;
}
};
ACTIVE_STRANDS.fetch_add(1, Ordering::Release);
let weave_ctx = Value::WeaveCtx {
yield_chan: weave_ctx_yield.clone(),
resume_chan: weave_ctx_resume.clone(),
};
let stack_with_ctx = push(child_base, weave_ctx);
let stack_with_value = push(stack_with_ctx, first_value);
let final_stack = fn_ref(stack_with_value, env_clone.as_ptr(), env_clone.len());
let (_, ctx_value) = pop(final_stack);
if let Value::WeaveCtx { yield_chan, .. } = ctx_value {
let _ = yield_chan.sender.send(WeaveMessage::Done);
}
crate::arena::arena_reset();
cleanup_strand();
});
}
}
_ => {
eprintln!(
"strand.weave: expected Quotation or Closure, got {:?} (compiler bug or memory corruption)",
quot_value
);
std::process::abort();
}
}
let handle = Value::WeaveCtx {
yield_chan: handle_yield,
resume_chan: handle_resume,
};
unsafe { push(stack, handle) }
}