ref: 22f8aa508f0313cadc30f941f99fe5f0eb5b155f
dir: /lib/thread/spawn+osx.myr/
use sys
use std
pkg thread =
type tid = uint64
const spawn : (fn : (-> void) -> std.result(tid, byte[:]))
;;
const Stacksz = 8*std.MiB
extern const exit : (-> void)
extern const start : (-> void)
const __init__ = {
var ret
ret = sys.bsdthread_register(\
(start : void#), \ /* start */
(0 : void#), \ /* wqthread */
(0 : uint32), \ /* sz */
(0 : uint32), \ /* dummy */
(0 : void#), \ /* targconc */
(0 : uint32)) /* queueoff */
if ret < 0
std.fatal("unable to init threads: {}", ret)
;;
}
const spawn = {fn
-> spawnstk(fn, Stacksz)
}
const spawnstk = {fn, sz
var stk : byte#, tid, ret
var szp, f, tos, env, envsz
stk = getstk(sz)
if stk == sys.Mapbad
-> `std.Err "couldn't get stack"
;;
tid = -1
/* find top of stack */
tos = (stk : std.intptr) + (sz : std.intptr)
/* store the stack size */
tos -= sizeof(sys.size)
sz -= sizeof(sys.size)
szp = (tos : sys.size#)
szp# = Stacksz
/* store the function we call */
envsz = std.fnenvsz(fn)
tos -= (envsz : std.intptr)
sz -= (envsz : sys.size)
env = tos
tos -= sizeof((->void))
sz -= sizeof((->void))
f = (tos : (->void)#)
f# = std.fnbdup(fn, (env : byte#)[:envsz])
var repr = (&fn : int64[2]#)#
ret = sys.bsdthread_create( \
(tramp : void#), \ /* start */
(tos : void#), \ /* arg */
(tos : void#), \ /* stack */
(0 : void#), \ /* pthread struct */
0x01000000) /* flags (PTHREAD_START_CUSTOM): don't alloc stack in kernel */
if ret == (-1 : void#)
-> `std.Err "couldn't spawn thread"
;;
-> `std.Ok (ret : tid)
}
const getstk = {sz
var p, m
std.put("allocating stack {x}\n", sz)
p = sys.mmap((0 : byte#), sz, sys.Mprotrw, sys.Mpriv | sys.Manon, -1, 0)
if p == sys.Mapbad
-> p
;;
m = (p : std.intptr)
-> (m : byte#)
}
/*
thread trampoline, called by `start`. We set up the args
for the closure and env on the stack, and then we call it
from here, doing the cleanup and exit at the end.
*/
const tramp = {f : (-> void)#
f#()
exit()
}