1 module d.rt.thread;
2 
3 extern(C) void __sd_thread_init() {
4 	_tl_gc_set_stack_bottom(getStackBottom());
5 	registerTlsSegments();
6 }
7 
8 private:
9 
10 version (linux) {
11 	void* getStackBottom() {
12 		pthread_attr_t attr;
13 		void* addr;
14 		size_t size;
15 
16 		if (pthread_getattr_np(pthread_self(), &attr)) {
17 			import core.stdc.stdlib, core.stdc.stdio;
18 			printf("pthread_getattr_np failed!".ptr);
19 			exit(1);
20 		}
21 
22 		if (pthread_attr_getstack(&attr, &addr, &size)) {
23 			import core.stdc.stdlib, core.stdc.stdio;
24 			printf("pthread_attr_getstack failed!".ptr);
25 			exit(1);
26 		}
27 
28 		if (pthread_attr_destroy(&attr)) {
29 			import core.stdc.stdlib, core.stdc.stdio;
30 			printf("pthread_attr_destroy failed!".ptr);
31 			exit(1);
32 		}
33 
34 		return addr + size;
35 	}
36 
37 	import sys.linux.link;
38 
39 	void registerTlsSegments() {
40 		dl_iterate_phdr(callback, null);
41 	}
42 
43 	extern(C) int callback(dl_phdr_info* info, size_t size, void* data) {
44 		auto tlsStart = info.dlpi_tls_data;
45 		if (tlsStart is null) {
46 			// FIXME: make sure this is not lazy initialized or something.
47 			return 0;
48 		}
49 
50 		// Force materialization. (work around a bug, evil sayers may say)
51 		ElfW!"Phdr" dummy;
52 
53 		auto segmentCount = info.dlpi_phnum;
54 		foreach (i; 0 .. segmentCount) {
55 			auto segment = info.dlpi_phdr[i];
56 
57 			import sys.linux.elf;
58 			if (segment.p_type != PT_TLS) {
59 				continue;
60 			}
61 
62 			_tl_gc_add_roots(tlsStart[0 .. segment.p_memsz]);
63 		}
64 
65 		return 0;
66 	}
67 }
68 
69 version (OSX) {
70 	void* getStackBottom() {
71 		return pthread_get_stackaddr_np(pthread_self());
72 	}
73 
74 	extern(C) void _d_dyld_registerTLSRange();
75 
76 	void registerTlsSegments() {
77 		_d_dyld_registerTLSRange();
78 	}
79 }
80 
81 version (FreeBSD) {
82 	void* getStackBottom() {
83 		pthread_attr_t attr;
84 		void* addr;
85 		size_t size;
86 
87 		pthread_attr_init(&attr);
88 		pthread_attr_get_np(pthread_self(), &attr);
89 		pthread_attr_getstack(&attr, &addr, &size);
90 		pthread_attr_destroy(&attr);
91 		return addr + size;
92 	}
93 
94 	void registerTlsSegments() {
95 		// TODO
96 	}
97 }
98 
99 // XXX: Will do for now.
100 alias pthread_t = size_t;
101 union pthread_attr_t {
102 	size_t t;
103 	ubyte[6 * size_t.sizeof + 8] d;
104 }
105 
106 extern(C):
107 
108 pthread_t pthread_self();
109 
110 version (linux) {
111 	int pthread_getattr_np(pthread_t __th, pthread_attr_t* __attr);
112 	int pthread_attr_getstack(const pthread_attr_t* __attr, void** __stackaddr,
113 	                          size_t* __stacksize);
114 	int pthread_attr_destroy(pthread_attr_t* __attr);
115 }
116 
117 version (OSX) {
118 	void* pthread_get_stackaddr_np(pthread_t __th);
119 }
120 
121 version (FreeBSD) {
122 	int pthread_attr_init(pthread_attr_t*);
123 	int pthread_attr_get_np(pthread_t, pthread_attr_t*);
124 	int pthread_attr_getstack(pthread_attr_t*, void**, size_t*);
125 	int pthread_attr_destroy(pthread_attr_t*);
126 }
127 
128 void _tl_gc_set_stack_bottom(const void* bottom);
129 void _tl_gc_add_roots(const void[] range);