summaryrefslogtreecommitdiff
path: root/lib/thread/tls+osx.myr
blob: 763f3f3cc3b39efd1fbbd8cf24f82202c9d9afed (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
use std

use "common"
use "types"

pkg thread =
	generic      tlsalloc : (-> tlskey(@a#))
	generic      tlsset   : (k : tlskey(@a#), v : @a# -> void)
	generic      tlsget   : (k : tlskey(@a#) -> @a#)
	extern const tid      : (-> tid)

	pkglocal const        tlsoob    : (k : tlskey(void) -> void)
	pkglocal extern const tlslen    : (-> tlskey(void))
	pkglocal const        setgsbase : (h : tlshdr# -> void)
	pkglocal extern const getgsbase : (-> tlshdr#)
;;

const Staticcap = 8

var _hdr
var _cap = Staticcap

generic tlsalloc = {
	std.assert(tid() == 0, "error: tlsalloc must be called from main thread\n")
	if _hdr == Zptr
		/* `_hdr` is lazily initialized here since we can't set it in start.s */
		_hdr = getgsbase()
	;;

	if _hdr.len++ == _cap
		std.assert(_cap < 0x8000_0000, "error: max tls slots exceeded\n")
		var l = sizeof(tlshdr) + ((_cap : std.size) * sizeof(void#))
		var h = std.bytealloc(sizeof(tlshdr) + ((_cap *= 2 : std.size) * sizeof(void#)))

		std.memblit(h, (_hdr : byte#), l)
		setgsbase((h : tlshdr#))
		/* this is ugly... the initial tls region is statically allocated */
		if _cap != Staticcap * 2
			std.bytefree((_hdr : byte#), l)
		;;
		_hdr = (h : tlshdr#)
	;;
	-> (_hdr.len - 1 : tlskey(@a#))
}

generic tlsset = {k, v
	_tlsset((k : tlskey(void)), (v : void#))
}

generic tlsget = {k
	-> (_tlsget((k : tlskey(void))) : @a#)
}

const tlsoob = {k
	std.fput(std.Err, "error: tlskey {} out of bounds {}\n", k, tlslen())
	std.suicide()
}

const setgsbase = {h
	match _setgsbase(h)
	| 0xf: /* yes, this indicates success; no, it's not documented */
	| err:
		std.fput(std.Err, "error: setgsbase returned {}\n", err)
		std.suicide()
	;;
}

extern const _tlsset    : (k : tlskey(void), v : void# -> void)
extern const _tlsget    : (k : tlskey(void) -> void#)
extern const _setgsbase : (h : tlshdr# -> int64)