summaryrefslogtreecommitdiff
path: root/lib/thread/spawn+linux.myr
blob: a56317f7fcf7e23a49e7d6705f766f95b8f2255c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use sys
use std

pkg thread =
	type tid = sys.pid

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

extern const exit : (-> void)

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

const Stacksz = 8*std.MiB

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

const spawnstk = {fn, sz
	var stk : byte#, tid, ctid, ret

	stk = getstk(sz)
	if stk == sys.Mapbad
		-> `std.Err "couldn't get stack"
	;;
	stk = initstack(stk, fn, Stacksz)

	ret = sys.fnclone(Thrflag, \
		(stk : byte#),\
		&tid, (0 : byte#), \
		&ctid, (0 : byte#), \
		(startthread : void#))
	if ret < 0
		-> `std.Err "couldn't spawn thread"
	;;
	-> `std.Ok (ret : tid)
}

const initstack = {stk, fn, sz
	var tos, szp, fp, env, envsz

	envsz = std.fnenvsz(fn)
	tos = (stk : std.intptr)
	tos -= sizeof(int64)
	szp = (tos : sys.size#)
	szp# = sz
	tos -= (envsz : std.intptr)
	env = tos
	tos -= sizeof((->void))
	fp = (tos : (->void)#)
	fp# = std.fnbdup(fn, (env : byte#)[:envsz])
	-> (tos : byte#)
}

const getstk = {sz
	var p, m

	p = sys.mmap((0 : byte#), sz, sys.Mprotrw, sys.Mpriv | sys.Manon, -1, 0)
	if p == sys.Mapbad
		-> p
	;;
	/* stack starts at the top of memory and grows down. */
	m = (p : std.intptr)
	m += (sz : std.intptr)
	-> (m : byte#)
}

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