shithub: mc

ref: d7740736da8f2ca830d558cdedd89266b9019375
dir: /lib/thread/spawn+linux.myr/

View raw version
use sys
use std

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

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

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

/* Holy shit flag mania. */
const Thrflag = sys.Clonevm | sys.Clonefs | sys.Clonefiles | \
	sys.Clonesighand | sys.Clonethread | sys.Clonesettls | \
	sys.Clonechildsettid

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

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

	ret = sys.fnclone(Thrflag,
		tos,
		Zptr,
		(hdr : byte#),
		(&hdr.tid : sys.pid#),
		Zptr,
		(startthread : void#))
	if ret < 0
		sys.munmap(stk, sz)
		-> `std.Err "couldn't spawn thread"
	;;
	-> `std.Ok (ret : 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.len = len
	hdr.base = stk
	hdr.stksz = sz

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

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