summaryrefslogtreecommitdiff
path: root/lib/thread/spawn+osx.myr
blob: 4e995981955fd76413d5d39f0fa30ef339b1804a (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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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()
}