ref: 029ee78d874168fde67ee212e06cd116ce1f0db4
dir: /lib/thread/tls+osx.myr/
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)