1 /* 2 Copyright 2014 Ellery Newcomer 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy of 5 this software and associated documentation files (the "Software"), to deal in 6 the Software without restriction, including without limitation the rights to 7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 of the Software, and to permit persons to whom the Software is furnished to do 9 so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be included in all 12 copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 SOFTWARE. 21 */ 22 module pyd.thread; 23 24 import std.compiler; 25 26 import core.thread; 27 import pyd.util.multi_index; 28 29 private bool isAttached = false; 30 31 alias ThreadSet = MultiIndexContainer!( 32 Thread, 33 IndexedBy!(HashedUnique!()), 34 MallocAllocator, MutableView 35 ); 36 37 __gshared ThreadSet threadSet = null; 38 39 shared static this() { 40 threadSet = ThreadSet.create(); 41 } 42 43 void ensureAttached() { 44 if (!isAttached) { 45 auto thread = Thread.getThis(); 46 if(thread is null) { 47 thread_attachThis(); 48 thread = Thread.getThis(); 49 synchronized(threadSet) { 50 threadSet.insert(thread); 51 } 52 } 53 isAttached = true; 54 } 55 } 56 57 void detachAll() { 58 synchronized(threadSet) { 59 foreach(Thread thread; threadSet[]) { 60 static if(version_minor >= 67) { 61 thread_detachInstance(thread); 62 }else{ 63 // hello, horrible hack 64 thread_detachByAddr(getThreadAddr(thread)); 65 } 66 } 67 threadSet.clear(); 68 } 69 } 70 71 static if (version_minor < 67) { 72 import core.thread; 73 import core.sync.mutex; 74 import core.atomic; 75 version(Windows) { 76 import core.sys.windows.windows; 77 } 78 version(Posix) { 79 import core.sys.posix.sys.types; 80 } 81 version(OSX) { 82 import core.sys.osx.mach.port; 83 } 84 85 class _Thread 86 { 87 __gshared const int PRIORITY_MIN; 88 __gshared const int PRIORITY_MAX; 89 __gshared const int PRIORITY_DEFAULT; 90 91 enum Call 92 { 93 NO, 94 FN, 95 DG 96 } 97 98 version( OSX ) 99 { 100 static _Thread sm_this; 101 } 102 else version( Posix ) 103 { 104 __gshared pthread_key_t sm_this; 105 } 106 else 107 { 108 static _Thread sm_this; 109 } 110 111 __gshared _Thread sm_main; 112 113 114 version( Windows ) 115 { 116 HANDLE m_hndl; 117 } 118 else version( OSX ) 119 { 120 mach_port_t m_tmach; 121 } 122 Thread.ThreadAddr m_addr; 123 Call m_call; 124 string m_name; 125 union 126 { 127 void function() m_fn; 128 void delegate() m_dg; 129 } 130 size_t m_sz; 131 version( Posix ) 132 { 133 bool m_isRunning; 134 } 135 bool m_isDaemon; 136 bool m_isInCriticalRegion; 137 Throwable m_unhandled; 138 139 static struct Context 140 { 141 void* bstack, 142 tstack; 143 Context* within; 144 Context* next, 145 prev; 146 } 147 148 149 Context m_main; 150 Context* m_curr; 151 bool m_lock; 152 void* m_tlsgcdata; 153 154 version( Windows ) 155 { 156 version( X86 ) 157 { 158 uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax 159 } 160 else version( X86_64 ) 161 { 162 ulong[16] m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax 163 // r8,r9,r10,r11,r12,r13,r14,r15 164 } 165 else 166 { 167 static assert(false, "Architecture not supported." ); 168 } 169 } 170 else version( OSX ) 171 { 172 version( X86 ) 173 { 174 uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax 175 } 176 else version( X86_64 ) 177 { 178 ulong[16] m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax 179 // r8,r9,r10,r11,r12,r13,r14,r15 180 } 181 else 182 { 183 static assert(false, "Architecture not supported." ); 184 } 185 } 186 187 188 private: 189 __gshared byte[__traits(classInstanceSize, Mutex)][2] _locks; 190 191 __gshared Context* sm_cbeg; 192 193 __gshared _Thread sm_tbeg; 194 __gshared size_t sm_tlen; 195 196 _Thread prev; 197 _Thread next; 198 199 } 200 201 Thread.ThreadAddr getThreadAddr(Thread thread) { 202 _Thread* doppelganger = cast(_Thread*) &thread; 203 return doppelganger.m_addr; 204 } 205 }