ref: 9a5f51b12293227ab7559c11d8fa5bcf18e49302
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() }