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);