shithub: mc

ref: f2d12752c483648d554700e6ac7dc100801dfa59
dir: /lib/thread/spawn+freebsd.myr/

View raw version
use sys
use std

use "common"
use "fsbase"
use "tls"
use "types"

pkg thread =
	const spawn : (fn : (-> void) -> std.result(tid, byte[:]))
;;


const Stacksz = 8*std.MiB
extern const exit : (-> void)

const spawn = {fn
	-> spawnstk(fn, Stacksz)
}

const spawnstk = {fn, sz
	var stk, tos, stksz, hdr, tid = -1, 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, stksz, hdr) = initstk(stk, fn, sz)

	ret = sys.thr_new(&[
		.startfn = (startthread : void#),
		.arg = (tos : void#),
		.stkbase = (stk : byte#),
		.stksz = stksz,
		.tid = (&hdr.tid : uint64#),
		.ptid = &tid,
		.flags = 2,
		.rtp = Zptr,
	], sizeof(sys.thrparam))

	if ret < 0
		sys.munmap(stk, sz)
		-> `std.Err "couldn't spawn thread"
	;;
	-> `std.Ok (tid : tid)
}

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

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

	var fn1 = {
		/*
		We write `hdr.len` here because it follows `hdr.tid` so it gets
		overwritten by the kernel in `thr_new`. Even though `sys.pid`
		is 32 bits, `thr_param.tid` is a `uint64#` for legacy reasons.
		*/
		hdr.len = len
		setfsbase(hdr)
		fn()
		std.fnfree(fn)
	}

	envsz = std.fnenvsz(fn1)
	tos -= (envsz : std.intptr)
	stksz -= (envsz : sys.size)
	env = tos
	tos -= sizeof((->void))
	stksz -= sizeof((->void))
	fp = (tos : (->void)#)
	fp# = std.fnbdup(fn1, (env : byte#)[:envsz])
	-> ((tos : byte#), stksz, hdr)
}

const startthread = {f : (-> void)#
	f#()
	exit()
}