shithub: mc

ref: d68cb921e334d6fd802d6ae93398d6324cb784ff
dir: /lib/thread/spawn+osx.myr/

View raw version
use sys
use std

use "tls"
use "types"

pkg thread =
	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, tos, ret

	stk = sys.mmap((0 : byte#), sz, sys.Mprotrw, sys.Mpriv | sys.Manon, -1, 0)
	if stk == sys.Mapbad
		-> `std.Err "couldn't get stack"
	;;
	tos = initstk(stk, fn, sz)

	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 : std.size) < 0
		sys.munmap(stk, sz)
		-> `std.Err "couldn't spawn thread"
	;;
	-> `std.Ok (stk : tid)
}

const initstk = {stk, fn, sz
	var len, tos, hdr, fp, env, envsz

	len = tlslen()
	tos = (stk : std.intptr) + (sz : std.intptr)
	tos -= (sizeof(tlshdr) + ((len : std.intptr) * sizeof(void#)) + 0xf) & ~0xf
	hdr = (tos : tlshdr#)
	hdr.tid = (stk : tid)
	hdr.len = len
	hdr.base = stk
	hdr.stksz = sz
	fn = std.fndup(fn)

	var fn1 = {
		setgsbase(hdr)
		fn()
		std.fnfree(fn)
	}

	envsz = std.fnenvsz(fn1)
	tos -= (envsz : std.intptr)
	env = tos
	tos -= sizeof((->void))
	fp = (tos : (->void)#)
	fp# = std.fnbdup(fn1, (env : byte#)[:envsz])
	-> (tos : 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()
}