FiberMgr

em.utils/FiberMgr.em
import em from '@$$emscript'
export const $U = em.$declare('MODULE')

import * as Common from '@em.mcu/Common.em'

export type Body = cb_t<[arg_t]>
export type Obj = ref_t<Fiber>

class Fiber extends $struct {
    link: ref_t<Fiber>
    body: Body
    arg: arg_t
    post: () => void
}

class List extends $struct {
    head: ref_t<Fiber>
    tail: ref_t<Fiber>
    empty: () => bool_t
    give: (elem: ref_t<Fiber>) => void
    take: () => ref_t<Fiber>
}
let FiberFac = $factory(Fiber.$make())

let ready_list = List.$make()

export namespace em$meta {

    export function create(body: Body, arg: arg_t = 0): Obj {
        let fiber = FiberFac.$create()
        fiber.$$.body = body
        fiber.$$.arg = arg
        return fiber
    }
}

function dispatch() {
    while (!ready_list.empty()) {
        let fiber = ready_list.take()
        Common.GlobalInterrupts.$$.enable()
        fiber.$$.body(fiber.$$.arg)
        Common.GlobalInterrupts.$$.disable()
    }
}

export function run() {
    Common.Idle.$$.wakeup()
    Common.GlobalInterrupts.$$.enable()
    for (; ;) {
        Common.GlobalInterrupts.$$.disable()
        dispatch()
        Common.Idle.$$.exec()
    }
}

function Fiber__post(self: ref_t<Fiber>): void {
    let key = Common.GlobalInterrupts.$$.disable()
    if (self.$$.link == $null) ready_list.give(self)
    Common.GlobalInterrupts.$$.restore(key)
}

function List__empty(self: ref_t<List>): bool_t {
    return self.$$.head == $null
}

function List__give(self: ref_t<List>, elem: ref_t<Fiber>): void {
    if (self.$$.empty()) {
        self.$$.head = elem
    }
    else {
        self.$$.tail.$$.link = elem
    }
    self.$$.tail = elem
    elem.$$.link = $null
}

function List__take(self: ref_t<List>): ref_t<Fiber> {
    let e = self.$$.head
    self.$$.head = e.$$.link
    e.$$.link = $null
    if (self.$$.head == $null) self.$$.tail = $null
    return e
}