///|
/// Observable lifecycle of a single-threaded native fiber.
pub(all) enum NativeFiberPhase {
Ready
Running
Suspended
Returned
Cancelled
} derive(Debug, Eq)
///|
/// Result of entering or continuing a native fiber.
pub(all) enum NativeFiberEvent {
Yielded(Int64)
Finished(Int64)
} derive(Debug, Eq)
///|
/// Result of advancing a stackful JIT invocation.
pub(all) enum NativeJITContinuationEvent {
NativeHostcallSuspended
NativeJITReturned(Int)
} derive(Debug, Eq)
///|
pub suberror NativeFiberError {
StackAllocationFailed(Int64)
WrongThread
InvalidTransition(NativeFiberPhase)
InvalidState(Int)
UnexpectedYield(Int64)
NativeFailure(Int)
} derive(Debug, Eq)
///|
pub impl Show for NativeFiberError with fn output(self, logger) {
logger.write_string(@types.compact_show_repr(Repr(self).to_string()))
}
///|
/// Fixed-stack, single-threaded native fiber.
///
/// The external object owns a guarded native stack and the entry closure. A
/// fiber may only be continued or cancelled on the thread that created it.
struct NativeFiber {
raw : NativeFiberObject
}
///|
/// Stackful JIT invocation whose entry frame is entirely native.
///
/// MoonBit hostcall callbacks always return before this continuation yields.
struct NativeJITContinuation {
raw : NativeFiberObject
}
///|
pub fn NativeFiber::new(
entry : () -> Int64,
stack_size? : Int64 = 1024L * 1024L,
) -> NativeFiber raise NativeFiberError {
let call_closure : FuncRef[(() -> Int64) -> Int64] = fn(f) { f() }
let raw = c_native_fiber_alloc(call_closure, entry, stack_size)
let fiber : NativeFiber = { raw, }
if !native_fiber_is_allocated(raw) {
raise StackAllocationFailed(stack_size)
}
fiber
}
///|
pub fn NativeJITContext::start_continuation(
self : NativeJITContext,
trampoline_ptr : Int64,
func_ptr : Int64,
values : FixedArray[Int64],
values_len : Int,
stack_size? : Int64 = 1024L * 1024L,
) -> NativeJITContinuation raise NativeFiberError {
let raw = c_native_jit_continuation_alloc(
self.handle,
trampoline_ptr,
func_ptr,
values,
values_len,
stack_size,
)
let continuation = NativeJITContinuation::{ raw, }
if !native_fiber_is_allocated(raw) {
raise StackAllocationFailed(stack_size)
}
continuation
}
///|
pub fn NativeFiber::phase(self : NativeFiber) -> NativeFiberPhase {
native_fiber_phase(self.raw)
}
///|
pub fn NativeFiber::continue_with(
self : NativeFiber,
value? : Int64 = 0L,
) -> NativeFiberEvent raise NativeFiberError {
match native_fiber_advance(self.raw, value) {
FiberSuspended(value) => Yielded(value)
FiberReturned(value) => Finished(value)
FiberAdvanceFailed(failure) => raise failure.to_error()
}
}
///|
pub fn NativeJITContinuation::continue_with(
self : NativeJITContinuation,
value? : Int64 = 0L,
) -> NativeJITContinuationEvent raise NativeFiberError {
match native_jit_continuation_advance(self.raw, value) {
JITHostcallSuspended => NativeHostcallSuspended
JITReturned(code) => NativeJITReturned(code)
JITAdvanceFailed(failure) => raise failure.to_error()
}
}
///|
/// Resume a continuation stopped at an imported hostcall.
///
/// `retry=true` re-enters only the suspended hostcall before continuing the
/// native guest frame. It never restarts the guest function from its entry.
pub fn NativeJITContinuation::continue_after_hostcall(
self : NativeJITContinuation,
retry~ : Bool,
) -> NativeJITContinuationEvent raise NativeFiberError {
self.continue_with(value=if retry { 1L } else { 0L })
}
///|
pub fn NativeJITContinuation::cancel(
self : NativeJITContinuation,
) -> Unit raise NativeFiberError {
match native_fiber_cancel(self.raw) {
None => ()
Some(failure) => raise failure.to_error()
}
}
///|
pub fn NativeJITContinuation::phase(
self : NativeJITContinuation,
) -> NativeFiberPhase {
native_fiber_phase(self.raw)
}
///|
/// Suspend the currently running native fiber and return the next resume value.
pub fn NativeFiber::suspend(value : Int64) -> Int64 {
c_native_fiber_yield(value)
}
///|
pub fn NativeFiber::cancel(self : NativeFiber) -> Unit raise NativeFiberError {
match native_fiber_cancel(self.raw) {
None => ()
Some(failure) => raise failure.to_error()
}
}
///|
pub fn NativeFiber::stack_size(self : NativeFiber) -> Int64 {
c_native_fiber_stack_size(self.raw)
}
///|
pub fn NativeFiber::guard_size(self : NativeFiber) -> Int64 {
c_native_fiber_guard_size(self.raw)
}
///|
pub impl Debug for NativeFiber with fn to_repr(self) {
Repr::ctor("NativeFiber", [
(Some("phase"), Repr(self.phase())),
(Some("stack_size"), Repr(self.stack_size())),
(Some("guard_size"), Repr(self.guard_size())),
])
}