PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/libphobos/libdruntime/core/sys/windows/threadaux.d

https://gitlab.com/4144/gcc
D | 388 lines | 298 code | 49 blank | 41 comment | 25 complexity | 239f97a5d7606f5dd7849dd0ff1003a5 MD5 | raw file
  1. /**
  2. * This module provides OS specific helper function for threads support
  3. *
  4. * Copyright: Copyright Digital Mars 2010 - 2010.
  5. * License: Distributed under the
  6. * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
  7. * (See accompanying file LICENSE)
  8. * Source: $(DRUNTIMESRC core/sys/windows/_threadaux.d)
  9. * Authors: Rainer Schuetze
  10. */
  11. /* NOTE: This file has been patched from the original DMD distribution to
  12. * work with the GDC compiler.
  13. */
  14. module core.sys.windows.threadaux;
  15. version (Windows):
  16. import core.sys.windows.basetsd/+ : HANDLE+/;
  17. import core.sys.windows.winbase/+ : CloseHandle, GetCurrentThreadId, GetCurrentProcessId,
  18. GetModuleHandleA, GetProcAddress+/;
  19. import core.sys.windows.windef/+ : BOOL, DWORD, FALSE, HRESULT+/;
  20. import core.stdc.stdlib;
  21. public import core.thread;
  22. extern(Windows)
  23. HANDLE OpenThread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId) nothrow @nogc;
  24. extern (C) extern __gshared int _tls_index;
  25. extern (C) // rt.minfo
  26. {
  27. void rt_moduleTlsCtor();
  28. void rt_moduleTlsDtor();
  29. }
  30. private:
  31. ///////////////////////////////////////////////////////////////////
  32. struct thread_aux
  33. {
  34. // don't let symbols leak into other modules
  35. enum SystemProcessInformation = 5;
  36. enum STATUS_INFO_LENGTH_MISMATCH = 0xc0000004;
  37. // structs subject to change according to MSDN, more info at http://undocumented.ntinternals.net
  38. // declarations according to http://processhacker.sourceforge.net/doc/ntexapi_8h_source.html
  39. // NOTE: the declarations assume default alignment for Win64 and contain some padding data
  40. struct UNICODE_STRING
  41. {
  42. short Length;
  43. short MaximumLength;
  44. wchar* Buffer;
  45. }
  46. // process or thread ID, documentation says it is a HANDLE, but it's actually the ID (a DWORD)
  47. alias size_t PTID;
  48. struct _SYSTEM_PROCESS_INFORMATION
  49. {
  50. int NextEntryOffset; // When this entry is 0, there are no more processes to be read.
  51. int NumberOfThreads;
  52. long WorkingSetPrivateSize;
  53. uint HardFaultCount;
  54. uint NumberOfThreadsHighWatermark;
  55. ulong CycleTime;
  56. long CreateTime;
  57. long UserTime;
  58. long KernelTime;
  59. UNICODE_STRING ImageName;
  60. int BasePriority;
  61. PTID /*Unique*/ProcessId;
  62. PTID InheritedFromUniqueProcessId;
  63. uint HandleCount;
  64. uint SessionId;
  65. size_t UniqueProcessKey;
  66. size_t PeakVirtualSize;
  67. size_t VirtualSize;
  68. uint PageFaultCount;
  69. size_t PeakWorkingSetSize;
  70. size_t WorkingSetSize;
  71. size_t QuotaPeakPagedPoolUsage;
  72. size_t QuotaPagedPoolUsage;
  73. size_t QuotaPeakNonPagedPoolUsage;
  74. size_t QuotaNonPagedPoolUsage;
  75. size_t PagefileUsage;
  76. size_t PeakPagefileUsage;
  77. size_t PrivatePageCount;
  78. long ReadOperationCount;
  79. long WriteOperationCount;
  80. long OtherOperationCount;
  81. long ReadTransferCount;
  82. long WriteTransferCount;
  83. long OtherTransferCount;
  84. // SYSTEM_THREAD_INFORMATION or SYSTEM_EXTENDED_THREAD_INFORMATION structures follow.
  85. }
  86. struct _SYSTEM_THREAD_INFORMATION
  87. {
  88. long KernelTime;
  89. long UserTime;
  90. long CreateTime;
  91. uint WaitTime;
  92. void* StartAddress;
  93. PTID ProcessId;
  94. PTID ThreadId;
  95. int Priority;
  96. int BasePriority;
  97. uint ContextSwitches;
  98. uint ThreadState;
  99. int WaitReason;
  100. int reserved;
  101. }
  102. alias fnNtQuerySystemInformation = extern(Windows)
  103. HRESULT function( uint SystemInformationClass, void* info, uint infoLength, uint* ReturnLength ) nothrow @nogc;
  104. enum ThreadBasicInformation = 0;
  105. struct THREAD_BASIC_INFORMATION
  106. {
  107. int ExitStatus;
  108. void** TebBaseAddress;
  109. PTID ProcessId;
  110. PTID ThreadId;
  111. size_t AffinityMask;
  112. int Priority;
  113. int BasePriority;
  114. }
  115. alias fnNtQueryInformationThread = extern(Windows)
  116. int function( HANDLE ThreadHandle, uint ThreadInformationClass, void* buf, uint size, uint* ReturnLength ) nothrow @nogc;
  117. enum SYNCHRONIZE = 0x00100000;
  118. enum THREAD_GET_CONTEXT = 8;
  119. enum THREAD_QUERY_INFORMATION = 0x40;
  120. enum THREAD_SUSPEND_RESUME = 2;
  121. ///////////////////////////////////////////////////////////////////
  122. // get the thread environment block (TEB) of the thread with the given handle
  123. static void** getTEB( HANDLE hnd ) nothrow @nogc
  124. {
  125. HANDLE nthnd = GetModuleHandleA( "NTDLL" );
  126. assert( nthnd, "cannot get module handle for ntdll" );
  127. fnNtQueryInformationThread fn = cast(fnNtQueryInformationThread) GetProcAddress( nthnd, "NtQueryInformationThread" );
  128. assert( fn, "cannot find NtQueryInformationThread in ntdll" );
  129. THREAD_BASIC_INFORMATION tbi;
  130. int Status = (*fn)(hnd, ThreadBasicInformation, &tbi, tbi.sizeof, null);
  131. assert(Status == 0);
  132. return tbi.TebBaseAddress;
  133. }
  134. // get the thread environment block (TEB) of the thread with the given identifier
  135. static void** getTEB( uint id ) nothrow @nogc
  136. {
  137. HANDLE hnd = OpenThread( THREAD_QUERY_INFORMATION, FALSE, id );
  138. assert( hnd, "OpenThread failed" );
  139. void** teb = getTEB( hnd );
  140. CloseHandle( hnd );
  141. return teb;
  142. }
  143. // get linear address of TEB of current thread
  144. static void** getTEB() nothrow @nogc
  145. {
  146. version (Win32)
  147. {
  148. version (GNU_InlineAsm)
  149. {
  150. void** teb;
  151. asm pure nothrow @nogc { "movl %%fs:0x18, %0;" : "=r" teb; }
  152. return teb;
  153. }
  154. else
  155. {
  156. asm pure nothrow @nogc
  157. {
  158. naked;
  159. mov EAX,FS:[0x18];
  160. ret;
  161. }
  162. }
  163. }
  164. else version (Win64)
  165. {
  166. version (GNU_InlineAsm)
  167. {
  168. void** teb;
  169. asm pure nothrow @nogc { "movq %%gs:0x30, %0;" : "=r" teb; }
  170. return teb;
  171. }
  172. else
  173. {
  174. asm pure nothrow @nogc
  175. {
  176. naked;
  177. mov RAX,0x30;
  178. mov RAX,GS:[RAX]; // immediate value causes fixup
  179. ret;
  180. }
  181. }
  182. }
  183. else
  184. {
  185. static assert(false);
  186. }
  187. }
  188. // get the stack bottom (the top address) of the thread with the given handle
  189. static void* getThreadStackBottom( HANDLE hnd ) nothrow @nogc
  190. {
  191. void** teb = getTEB( hnd );
  192. return teb[1];
  193. }
  194. // get the stack bottom (the top address) of the thread with the given identifier
  195. static void* getThreadStackBottom( uint id ) nothrow @nogc
  196. {
  197. void** teb = getTEB( id );
  198. return teb[1];
  199. }
  200. // create a thread handle with full access to the thread with the given identifier
  201. static HANDLE OpenThreadHandle( uint id ) nothrow @nogc
  202. {
  203. return OpenThread( SYNCHRONIZE|THREAD_GET_CONTEXT|THREAD_QUERY_INFORMATION|THREAD_SUSPEND_RESUME, FALSE, id );
  204. }
  205. ///////////////////////////////////////////////////////////////////
  206. // enumerate threads of the given process calling the passed function on each thread
  207. // using function instead of delegate here to avoid allocating closure
  208. static bool enumProcessThreads( uint procid, bool function( uint id, void* context ) dg, void* context )
  209. {
  210. HANDLE hnd = GetModuleHandleA( "NTDLL" );
  211. fnNtQuerySystemInformation fn = cast(fnNtQuerySystemInformation) GetProcAddress( hnd, "NtQuerySystemInformation" );
  212. if ( !fn )
  213. return false;
  214. uint sz = 16384;
  215. uint retLength;
  216. HRESULT rc;
  217. char* buf;
  218. for ( ; ; )
  219. {
  220. buf = cast(char*) core.stdc.stdlib.malloc(sz);
  221. if (!buf)
  222. return false;
  223. rc = fn( SystemProcessInformation, buf, sz, &retLength );
  224. if ( rc != STATUS_INFO_LENGTH_MISMATCH )
  225. break;
  226. core.stdc.stdlib.free( buf );
  227. sz *= 2;
  228. }
  229. scope(exit) core.stdc.stdlib.free( buf );
  230. if (rc != 0)
  231. return false;
  232. auto pinfo = cast(_SYSTEM_PROCESS_INFORMATION*) buf;
  233. auto pend = cast(_SYSTEM_PROCESS_INFORMATION*) (buf + retLength);
  234. for ( ; pinfo < pend; )
  235. {
  236. if ( pinfo.ProcessId == procid )
  237. {
  238. auto tinfo = cast(_SYSTEM_THREAD_INFORMATION*)(pinfo + 1);
  239. for ( int i = 0; i < pinfo.NumberOfThreads; i++, tinfo++ )
  240. if ( tinfo.ProcessId == procid )
  241. if ( !dg( cast(uint) tinfo.ThreadId, context ) ) // IDs are actually DWORDs
  242. return false;
  243. }
  244. if ( pinfo.NextEntryOffset == 0 )
  245. break;
  246. pinfo = cast(_SYSTEM_PROCESS_INFORMATION*) (cast(char*) pinfo + pinfo.NextEntryOffset);
  247. }
  248. return true;
  249. }
  250. static bool enumProcessThreads( bool function( uint id, void* context ) dg, void* context )
  251. {
  252. return enumProcessThreads( GetCurrentProcessId(), dg, context );
  253. }
  254. // execute function on the TLS for the given thread
  255. alias extern(C) void function() externCVoidFunc;
  256. static void impersonate_thread( uint id, externCVoidFunc fn )
  257. {
  258. impersonate_thread(id, () => fn());
  259. }
  260. static void impersonate_thread( uint id, scope void delegate() dg)
  261. {
  262. if ( id == GetCurrentThreadId() )
  263. {
  264. dg();
  265. return;
  266. }
  267. // temporarily set current TLS array pointer to the array pointer of the referenced thread
  268. void** curteb = getTEB();
  269. void** teb = getTEB( id );
  270. assert( teb && curteb );
  271. void** curtlsarray = cast(void**) curteb[11];
  272. void** tlsarray = cast(void**) teb[11];
  273. if ( !curtlsarray || !tlsarray )
  274. return;
  275. curteb[11] = tlsarray;
  276. // swap out the TLS slots aswell
  277. version (Win64)
  278. {
  279. enum TEB_offset_TlsSlots = 0x1480;
  280. enum TEB_offset_TlsExpansionSlots = 0x1780;
  281. }
  282. else
  283. {
  284. enum TEB_offset_TlsSlots = 0xE10;
  285. enum TEB_offset_TlsExpansionSlots = 0xF94;
  286. }
  287. void* tlsSlotsAdr(void** teb) { return cast(void*) teb + TEB_offset_TlsSlots; }
  288. ref void* tlsExpansionSlots(void** teb) { return *cast(void**)(cast(void*) teb + TEB_offset_TlsExpansionSlots); }
  289. import core.stdc.string;
  290. void*[64] slots = void;
  291. memcpy(slots.ptr, tlsSlotsAdr(curteb), slots.sizeof);
  292. void* extraSlots = tlsExpansionSlots(curteb);
  293. memcpy(tlsSlotsAdr(curteb), tlsSlotsAdr(teb), slots.sizeof);
  294. tlsExpansionSlots(curteb) = tlsExpansionSlots(teb);
  295. dg();
  296. curteb[11] = curtlsarray;
  297. // copy the TLS slots back in case they have been changed in dg
  298. memcpy(tlsSlotsAdr(teb), tlsSlotsAdr(curteb), slots.sizeof);
  299. tlsExpansionSlots(teb) = tlsExpansionSlots(curteb);
  300. memcpy(tlsSlotsAdr(curteb), slots.ptr, slots.sizeof);
  301. tlsExpansionSlots(curteb) = extraSlots;
  302. }
  303. }
  304. public:
  305. // forward as few symbols as possible into the "global" name space
  306. alias thread_aux.getTEB getTEB;
  307. alias thread_aux.getThreadStackBottom getThreadStackBottom;
  308. alias thread_aux.OpenThreadHandle OpenThreadHandle;
  309. alias thread_aux.enumProcessThreads enumProcessThreads;
  310. alias thread_aux.impersonate_thread impersonate_thread;
  311. // get the start of the TLS memory of the thread with the given handle
  312. void* GetTlsDataAddress( HANDLE hnd ) nothrow
  313. {
  314. if ( void** teb = getTEB( hnd ) )
  315. if ( void** tlsarray = cast(void**) teb[11] )
  316. return tlsarray[_tls_index];
  317. return null;
  318. }
  319. // get the start of the TLS memory of the thread with the given identifier
  320. void* GetTlsDataAddress( uint id ) nothrow
  321. {
  322. HANDLE hnd = OpenThread( thread_aux.THREAD_QUERY_INFORMATION, FALSE, id );
  323. assert( hnd, "OpenThread failed" );
  324. void* tls = GetTlsDataAddress( hnd );
  325. CloseHandle( hnd );
  326. return tls;
  327. }
  328. ///////////////////////////////////////////////////////////////////
  329. // run rt_moduleTlsCtor in the context of the given thread
  330. void thread_moduleTlsCtor( uint id )
  331. {
  332. thread_aux.impersonate_thread(id, &rt_moduleTlsCtor);
  333. }
  334. ///////////////////////////////////////////////////////////////////
  335. // run rt_moduleTlsDtor in the context of the given thread
  336. void thread_moduleTlsDtor( uint id )
  337. {
  338. thread_aux.impersonate_thread(id, &rt_moduleTlsDtor);
  339. }