The OpenD Programming Language

1 /**
2  * The osthread module provides low-level, OS-dependent code
3  * for thread creation and management.
4  *
5  * Copyright: Copyright Sean Kelly 2005 - 2012.
6  * License: Distributed under the
7  *      $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
8  *    (See accompanying file LICENSE)
9  * Authors:   Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak
10  * Source:    $(DRUNTIMESRC core/thread/osthread.d)
11  */
12 
13 module core.thread.osthread;
14 
15 import core.thread.threadbase;
16 import core.thread.context;
17 import core.thread.types;
18 import core.atomic;
19 import core.memory : GC, pageSize;
20 import core.time;
21 import core.exception : onOutOfMemoryError;
22 import core.internal.traits : externDFunc;
23 
24 version(Emscripten) {
25     extern(C) void* emscripten_stack_get_current() nothrow @nogc;
26 
27     extern(C) {
28         int SIGRTMIN() nothrow @nogc {
29             return 33;
30         }
31 
32         int pthread_kill(pthread_t thread, int sig) nothrow @nogc {
33             return 0;
34         }
35 
36         int sigsuspend(const sigset_t *mask) nothrow @nogc { return -1; }
37     }
38 }
39 
40 /+
41 version(FreeStanding) {
42 	class Thread {
43 		static void yield() @nogc nothrow { assert(0); }
44 		static void sleep(Duration d) @nogc nothrow { assert(0); }
45                 __gshared Thread t = new Thread; // CTFE'd so it isn't null
46                 static Thread getThis() @nogc nothrow {
47                     return t;
48                 }
49 	}
50 
51 	extern (C) void thread_init() @nogc nothrow @system { }
52 	extern (C) void thread_suspendAll() @nogc nothrow @system { }
53 
54         private extern (D) void resume(ThreadBase _t) nothrow @nogc {}
55 
56 
57         package extern(D) void callWithStackShell(scope callWithStackShellDg fn) nothrow @system
58         {
59             //assert(0);
60             fn(emscripten_stack_get_current());
61         }
62 
63         int createLowLevelThread(void delegate() nothrow dg, uint stacksize = 0,
64                                       void delegate() nothrow cbDllUnload = null) nothrow @nogc @system
65         { assert(0); }
66 
67         void joinLowLevelThread(int) @nogc nothrow {}
68 } else:
69 +/
70 
71 version (LDC)
72 {
73     import ldc.attributes;
74     import ldc.llvmasm;
75 
76     version (Windows) version = LDC_Windows;
77 
78     version (ARM)     version = ARM_Any;
79     version (AArch64) version = ARM_Any;
80 
81     version (MIPS32) version = MIPS_Any;
82     version (MIPS64) version = MIPS_Any;
83 
84     version (PPC)   version = PPC_Any;
85     version (PPC64) version = PPC_Any;
86 
87     version (RISCV32) version = RISCV_Any;
88     version (RISCV64) version = RISCV_Any;
89 
90     version (SupportSanitizers)
91     {
92         import ldc.sanitizers_optionally_linked;
93     }
94 }
95 
96 version (FreeStanding) {
97 	import core.stdc.stdlib; // for realloc
98 }
99 
100 ///////////////////////////////////////////////////////////////////////////////
101 // Platform Detection and Memory Allocation
102 ///////////////////////////////////////////////////////////////////////////////
103 
104 version (OSX)
105     version = Darwin;
106 else version (iOS)
107     version = Darwin;
108 else version (TVOS)
109     version = Darwin;
110 else version (WatchOS)
111     version = Darwin;
112 
113 version (D_InlineAsm_X86)
114 {
115     version (Windows)
116         version = AsmX86_Windows;
117     else version (Posix)
118         version = AsmX86_Posix;
119 }
120 else version (D_InlineAsm_X86_64)
121 {
122     version (Windows)
123     {
124         version = AsmX86_64_Windows;
125     }
126     else version (Posix)
127     {
128         version = AsmX86_64_Posix;
129     }
130 }
131 
132 version (Posix)
133 {
134     version (AsmX86_Windows)    {} else
135     version (AsmX86_Posix)      {} else
136     version (AsmX86_64_Windows) {} else
137     version (AsmX86_64_Posix)   {} else
138     version (AsmExternal)       {} else
139     {
140         // NOTE: The ucontext implementation requires architecture specific
141         //       data definitions to operate so testing for it must be done
142         //       by checking for the existence of ucontext_t rather than by
143         //       a version identifier.  Please note that this is considered
144         //       an obsolescent feature according to the POSIX spec, so a
145         //       custom solution is still preferred.
146         import core.sys.posix.ucontext;
147     }
148 }
149 
150 version (Windows)
151 {
152     import core.stdc.stdint : uintptr_t; // for _beginthreadex decl below
153     import core.stdc.stdlib;             // for malloc, atexit
154     import core.sys.windows.basetsd /+: HANDLE+/;
155     import core.sys.windows.threadaux /+: getThreadStackBottom, impersonate_thread, OpenThreadHandle+/;
156     import core.sys.windows.winbase /+: CloseHandle, CREATE_SUSPENDED, DuplicateHandle, GetCurrentThread,
157         GetCurrentThreadId, GetCurrentProcess, GetExitCodeThread, GetSystemInfo, GetThreadContext,
158         GetThreadPriority, INFINITE, ResumeThread, SetThreadPriority, Sleep,  STILL_ACTIVE,
159         SuspendThread, SwitchToThread, SYSTEM_INFO, THREAD_PRIORITY_IDLE, THREAD_PRIORITY_NORMAL,
160         THREAD_PRIORITY_TIME_CRITICAL, WAIT_OBJECT_0, WaitForSingleObject+/;
161     import core.sys.windows.windef /+: TRUE+/;
162     import core.sys.windows.winnt /+: CONTEXT, CONTEXT_CONTROL, CONTEXT_INTEGER+/;
163 
164     private extern (Windows) alias btex_fptr = uint function(void*);
165     private extern (C) uintptr_t _beginthreadex(void*, uint, btex_fptr, void*, uint, uint*) nothrow @nogc;
166 }
167 else version (Posix)
168 {
169     import core.stdc.errno;
170     import core.sys.posix.semaphore;
171     import core.sys.posix.stdlib; // for malloc, valloc, free, atexit
172     import core.sys.posix.pthread;
173     import core.sys.posix.signal;
174     import core.sys.posix.time;
175 
176     version (Darwin)
177     {
178         import core.sys.darwin.mach.thread_act;
179         import core.sys.darwin.pthread : pthread_mach_thread_np;
180     }
181 }
182 
183 version (Solaris)
184 {
185     import core.sys.solaris.sys.priocntl;
186     import core.sys.solaris.sys.types;
187     import core.sys.posix.sys.wait : idtype_t;
188 }
189 
190 version (GNU)
191 {
192     import gcc.builtins;
193 }
194 
195 /**
196  * Hook for whatever EH implementation is used to save/restore some data
197  * per stack.
198  *
199  * Params:
200  *     newContext = The return value of the prior call to this function
201  *         where the stack was last swapped out, or null when a fiber stack
202  *         is switched in for the first time.
203  */
204 private extern(C) void* _d_eh_swapContext(void* newContext) nothrow @nogc;
205 
206 // LDC: changed from `version (DigitalMars)`
207 version (all)
208 {
209     // LDC: changed from `version (Windows)`
210     version (CRuntime_Microsoft)
211     {
212         extern(D) void* swapContext(void* newContext) nothrow @nogc
213         {
214             return _d_eh_swapContext(newContext);
215         }
216     }
217     else
218     {
219         extern(C) void* _d_eh_swapContextDwarf(void* newContext) nothrow @nogc;
220 
221         extern(D) void* swapContext(void* newContext) nothrow @nogc
222         {
223             /* Detect at runtime which scheme is being used.
224              * Eventually, determine it statically.
225              */
226             static int which = 0;
227             final switch (which)
228             {
229                 case 0:
230                 {
231                     assert(newContext == null);
232                     auto p = _d_eh_swapContext(newContext);
233                     auto pdwarf = _d_eh_swapContextDwarf(newContext);
234                     if (p)
235                     {
236                         which = 1;
237                         return p;
238                     }
239                     else if (pdwarf)
240                     {
241                         which = 2;
242                         return pdwarf;
243                     }
244                     return null;
245                 }
246                 case 1:
247                     return _d_eh_swapContext(newContext);
248                 case 2:
249                     return _d_eh_swapContextDwarf(newContext);
250             }
251         }
252     }
253 }
254 else
255 {
256     extern(D) void* swapContext(void* newContext) nothrow @nogc
257     {
258         return _d_eh_swapContext(newContext);
259     }
260 }
261 
262 ///////////////////////////////////////////////////////////////////////////////
263 // Thread
264 ///////////////////////////////////////////////////////////////////////////////
265 
266 /**
267  * This class encapsulates all threading functionality for the D
268  * programming language.  As thread manipulation is a required facility
269  * for garbage collection, all user threads should derive from this
270  * class, and instances of this class should never be explicitly deleted.
271  * A new thread may be created using either derivation or composition, as
272  * in the following example.
273  */
274 class Thread : ThreadBase
275 {
276     //
277     // Standard thread data
278     //
279     version (Windows)
280     {
281         private HANDLE          m_hndl;
282     }
283 
284     version (Posix)
285     {
286         private shared bool     m_isRunning;
287     }
288 
289     version (Darwin)
290     {
291         private mach_port_t     m_tmach;
292     }
293 
294     version (Solaris)
295     {
296         private __gshared bool m_isRTClass;
297     }
298 
299     //
300     // Standard types
301     //
302     version (Windows)
303     {
304         alias TLSKey = uint;
305     }
306     else version (Posix)
307     {
308         alias TLSKey = pthread_key_t;
309     }
310 
311     ///////////////////////////////////////////////////////////////////////////
312     // Initialization
313     ///////////////////////////////////////////////////////////////////////////
314 
315 
316     /**
317      * Initializes a thread object which is associated with a static
318      * D function.
319      *
320      * Params:
321      *  fn = The thread function.
322      *  sz = The stack size for this thread.
323      *
324      * In:
325      *  fn must not be null.
326      */
327     this( void function() fn, size_t sz = 0 ) @safe pure nothrow @nogc
328     {
329         super(fn, sz);
330     }
331 
332 
333     /**
334      * Initializes a thread object which is associated with a dynamic
335      * D function.
336      *
337      * Params:
338      *  dg = The thread function.
339      *  sz = The stack size for this thread.
340      *
341      * In:
342      *  dg must not be null.
343      */
344     this( void delegate() dg, size_t sz = 0 ) @safe pure nothrow @nogc
345     {
346         super(dg, sz);
347     }
348 
349     package this( size_t sz = 0 ) @safe pure nothrow @nogc
350     {
351         super(sz);
352     }
353 
354     /**
355      * Cleans up any remaining resources used by this object.
356      */
357     ~this() nothrow @nogc
358     {
359         if (super.destructBeforeDtor())
360             return;
361 
362         version (Windows)
363         {
364             m_addr = m_addr.init;
365             CloseHandle( m_hndl );
366             m_hndl = m_hndl.init;
367         }
368         else version (Posix)
369         {
370             if (m_addr != m_addr.init)
371             {
372                 version (LDC)
373                 {
374                     // don't detach the main thread, TSan doesn't like it:
375                     // https://github.com/ldc-developers/ldc/issues/3519
376                     if (!isMainThread())
377                         pthread_detach( m_addr );
378                 }
379                 else
380                 {
381                     pthread_detach( m_addr );
382                 }
383             }
384             m_addr = m_addr.init;
385         }
386         version (Darwin)
387         {
388             m_tmach = m_tmach.init;
389         }
390     }
391 
392     //
393     // Thread entry point.  Invokes the function or delegate passed on
394     // construction (if any).
395     //
396     private final void run()
397     {
398         super.run();
399     }
400 
401     /**
402      * Provides a reference to the calling thread.
403      *
404      * Returns:
405      *  The thread object representing the calling thread.  The result of
406      *  deleting this object is undefined.  If the current thread is not
407      *  attached to the runtime, a null reference is returned.
408      */
409     static Thread getThis() @safe nothrow @nogc
410     {
411         return ThreadBase.getThis().toThread;
412     }
413 
414     ///////////////////////////////////////////////////////////////////////////
415     // Thread Context and GC Scanning Support
416     ///////////////////////////////////////////////////////////////////////////
417 
418 
419     version (Windows)
420     {
421         version (X86)
422         {
423             uint[8]         m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
424         }
425         else version (X86_64)
426         {
427             ulong[16]       m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax
428                                    // r8,r9,r10,r11,r12,r13,r14,r15
429         }
430         else
431         {
432             static assert(false, "Architecture not supported." );
433         }
434     }
435     else version (Darwin)
436     {
437         version (X86)
438         {
439             uint[8]         m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
440         }
441         else version (X86_64)
442         {
443             ulong[16]       m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax
444                                    // r8,r9,r10,r11,r12,r13,r14,r15
445         }
446         else version (AArch64)
447         {
448             ulong[33]       m_reg; // x0-x31, pc
449         }
450         else version (ARM)
451         {
452             uint[16]        m_reg; // r0-r15
453         }
454         else version (PPC)
455         {
456             // Make the assumption that we only care about non-fp and non-vr regs.
457             // ??? : it seems plausible that a valid address can be copied into a VR.
458             uint[32]        m_reg; // r0-31
459         }
460         else version (PPC64)
461         {
462             // As above.
463             ulong[32]       m_reg; // r0-31
464         }
465         else
466         {
467             static assert(false, "Architecture not supported." );
468         }
469     }
470 
471 
472     ///////////////////////////////////////////////////////////////////////////
473     // General Actions
474     ///////////////////////////////////////////////////////////////////////////
475 
476 
477     /**
478      * Starts the thread and invokes the function or delegate passed upon
479      * construction.
480      *
481      * In:
482      *  This routine may only be called once per thread instance.
483      *
484      * Throws:
485      *  ThreadException if the thread fails to start.
486      */
487     final Thread start() nothrow @system
488     in
489     {
490         assert( !next && !prev );
491     }
492     do
493     {
494         auto wasThreaded  = multiThreadedFlag;
495         multiThreadedFlag = true;
496         scope( failure )
497         {
498             if ( !wasThreaded )
499                 multiThreadedFlag = false;
500         }
501 
502         version (Windows) {} else
503         version (Posix)
504         {
505             size_t stksz = adjustStackSize( m_sz );
506 
507             pthread_attr_t  attr;
508 
509             if ( pthread_attr_init( &attr ) )
510                 onThreadError( "Error initializing thread attributes" );
511             if ( stksz && pthread_attr_setstacksize( &attr, stksz ) )
512                 onThreadError( "Error initializing thread stack size" );
513         }
514 
515         version (Shared)
516         {
517             auto ps = cast(void**).malloc(2 * size_t.sizeof);
518             if (ps is null) onOutOfMemoryError();
519         }
520 
521         version (Windows)
522         {
523             // NOTE: If a thread is just executing DllMain()
524             //       while another thread is started here, it holds an OS internal
525             //       lock that serializes DllMain with CreateThread. As the code
526             //       might request a synchronization on slock (e.g. in thread_findByAddr()),
527             //       we cannot hold that lock while creating the thread without
528             //       creating a deadlock
529             //
530             // Solution: Create the thread in suspended state and then
531             //       add and resume it with slock acquired
532             assert(m_sz <= uint.max, "m_sz must be less than or equal to uint.max");
533             version (Shared)
534                 auto threadArg = cast(void*) ps;
535             else
536                 auto threadArg = cast(void*) this;
537             m_hndl = cast(HANDLE) _beginthreadex( null, cast(uint) m_sz, &thread_entryPoint, threadArg, CREATE_SUSPENDED, &m_addr );
538             if ( cast(size_t) m_hndl == 0 )
539                 onThreadError( "Error creating thread" );
540         }
541 
542         slock.lock_nothrow();
543         scope(exit) slock.unlock_nothrow();
544         {
545             ++nAboutToStart;
546             pAboutToStart = cast(ThreadBase*)realloc(pAboutToStart, Thread.sizeof * nAboutToStart);
547             pAboutToStart[nAboutToStart - 1] = this;
548 
549             version (Posix)
550             {
551                 // NOTE: This is also set to true by thread_entryPoint, but set it
552                 //       here as well so the calling thread will see the isRunning
553                 //       state immediately.
554                 atomicStore!(MemoryOrder.raw)(m_isRunning, true);
555                 scope( failure ) atomicStore!(MemoryOrder.raw)(m_isRunning, false);
556             }
557 
558             version (Shared)
559             {
560                 auto libs = externDFunc!("rt.sections_elf_shared.pinLoadedLibraries",
561                                          void* function() @nogc nothrow)();
562 
563                 ps[0] = cast(void*)this;
564                 ps[1] = cast(void*)libs;
565 
566                 version (Windows)
567                 {
568                     if ( ResumeThread( m_hndl ) == -1 )
569                     {
570                         externDFunc!("rt.sections_elf_shared.unpinLoadedLibraries",
571                                      void function(void*) @nogc nothrow)(libs);
572                         .free(ps);
573                         onThreadError( "Error resuming thread" );
574                     }
575                 }
576                 else version (Posix)
577                 {
578                     if ( pthread_create( &m_addr, &attr, &thread_entryPoint, ps ) != 0 )
579                     {
580                         externDFunc!("rt.sections_elf_shared.unpinLoadedLibraries",
581                                      void function(void*) @nogc nothrow)(libs);
582                         .free(ps);
583                         onThreadError( "Error creating thread" );
584                     }
585                 }
586             }
587             else
588             {
589                 version (Windows)
590                 {
591                     if ( ResumeThread( m_hndl ) == -1 )
592                         onThreadError( "Error resuming thread" );
593                 }
594                 else version (Posix)
595                 {
596                     if ( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 )
597                         onThreadError( "Error creating thread" );
598                 }
599             }
600 
601             version (Posix)
602             {
603                 if ( pthread_attr_destroy( &attr ) != 0 )
604                     onThreadError( "Error destroying thread attributes" );
605             }
606 
607             version (Darwin)
608             {
609                 m_tmach = pthread_mach_thread_np( m_addr );
610                 if ( m_tmach == m_tmach.init )
611                     onThreadError( "Error creating thread" );
612             }
613 
614             return this;
615         }
616     }
617 
618     /**
619      * Waits for this thread to complete.  If the thread terminated as the
620      * result of an unhandled exception, this exception will be rethrown.
621      *
622      * Params:
623      *  rethrow = Rethrow any unhandled exception which may have caused this
624      *            thread to terminate.
625      *
626      * Throws:
627      *  ThreadException if the operation fails.
628      *  Any exception not handled by the joined thread.
629      *
630      * Returns:
631      *  Any exception not handled by this thread if rethrow = false, null
632      *  otherwise.
633      */
634     override final Throwable join( bool rethrow = true )
635     {
636         version (Windows)
637         {
638             if ( m_addr != m_addr.init && WaitForSingleObject( m_hndl, INFINITE ) != WAIT_OBJECT_0 )
639                 throw new ThreadException( "Unable to join thread" );
640             // NOTE: m_addr must be cleared before m_hndl is closed to avoid
641             //       a race condition with isRunning. The operation is done
642             //       with atomicStore to prevent compiler reordering.
643             atomicStore!(MemoryOrder.raw)(*cast(shared)&m_addr, m_addr.init);
644             CloseHandle( m_hndl );
645             m_hndl = m_hndl.init;
646         }
647         else version (Posix)
648         {
649             if ( m_addr != m_addr.init && pthread_join( m_addr, null ) != 0 )
650                 throw new ThreadException( "Unable to join thread" );
651             // NOTE: pthread_join acts as a substitute for pthread_detach,
652             //       which is normally called by the dtor.  Setting m_addr
653             //       to zero ensures that pthread_detach will not be called
654             //       on object destruction.
655             m_addr = m_addr.init;
656         }
657         if ( m_unhandled )
658         {
659             if ( rethrow )
660                 throw m_unhandled;
661             return m_unhandled;
662         }
663         return null;
664     }
665 
666 
667     ///////////////////////////////////////////////////////////////////////////
668     // Thread Priority Actions
669     ///////////////////////////////////////////////////////////////////////////
670 
671     version (Windows)
672     {
673         @property static int PRIORITY_MIN() @nogc nothrow pure @safe
674         {
675             return THREAD_PRIORITY_IDLE;
676         }
677 
678         @property static const(int) PRIORITY_MAX() @nogc nothrow pure @safe
679         {
680             return THREAD_PRIORITY_TIME_CRITICAL;
681         }
682 
683         @property static int PRIORITY_DEFAULT() @nogc nothrow pure @safe
684         {
685             return THREAD_PRIORITY_NORMAL;
686         }
687     }
688     else
689     {
690         private struct Priority
691         {
692             int PRIORITY_MIN = int.min;
693             int PRIORITY_DEFAULT = int.min;
694             int PRIORITY_MAX = int.min;
695         }
696 
697         /*
698         Lazily loads one of the members stored in a hidden global variable of
699         type `Priority`. Upon the first access of either member, the entire
700         `Priority` structure is initialized. Multiple initializations from
701         different threads calling this function are tolerated.
702 
703         `which` must be one of `PRIORITY_MIN`, `PRIORITY_DEFAULT`,
704         `PRIORITY_MAX`.
705         */
706         private static shared Priority cache;
707         private static int loadGlobal(string which)()
708         {
709             auto local = atomicLoad(mixin("cache." ~ which));
710             if (local != local.min) return local;
711             // There will be benign races
712             cache = loadPriorities;
713             return atomicLoad(mixin("cache." ~ which));
714         }
715 
716         /*
717         Loads all priorities and returns them as a `Priority` structure. This
718         function is thread-neutral.
719         */
720         private static Priority loadPriorities() @nogc nothrow @trusted
721         {
722             Priority result;
723             version (Solaris)
724             {
725                 pcparms_t pcParms;
726                 pcinfo_t pcInfo;
727 
728                 pcParms.pc_cid = PC_CLNULL;
729                 if (priocntl(idtype_t.P_PID, P_MYID, PC_GETPARMS, &pcParms) == -1)
730                     assert( 0, "Unable to get scheduling class" );
731 
732                 pcInfo.pc_cid = pcParms.pc_cid;
733                 // PC_GETCLINFO ignores the first two args, use dummy values
734                 if (priocntl(idtype_t.P_PID, 0, PC_GETCLINFO, &pcInfo) == -1)
735                     assert( 0, "Unable to get scheduling class info" );
736 
737                 pri_t* clparms = cast(pri_t*)&pcParms.pc_clparms;
738                 pri_t* clinfo = cast(pri_t*)&pcInfo.pc_clinfo;
739 
740                 result.PRIORITY_MAX = clparms[0];
741 
742                 if (pcInfo.pc_clname == "RT")
743                 {
744                     m_isRTClass = true;
745 
746                     // For RT class, just assume it can't be changed
747                     result.PRIORITY_MIN = clparms[0];
748                     result.PRIORITY_DEFAULT = clparms[0];
749                 }
750                 else
751                 {
752                     m_isRTClass = false;
753 
754                     // For all other scheduling classes, there are
755                     // two key values -- uprilim and maxupri.
756                     // maxupri is the maximum possible priority defined
757                     // for the scheduling class, and valid priorities
758                     // range are in [-maxupri, maxupri].
759                     //
760                     // However, uprilim is an upper limit that the
761                     // current thread can set for the current scheduling
762                     // class, which can be less than maxupri.  As such,
763                     // use this value for priorityMax since this is
764                     // the effective maximum.
765 
766                     // maxupri
767                     result.PRIORITY_MIN = -cast(int)(clinfo[0]);
768                     // by definition
769                     result.PRIORITY_DEFAULT = 0;
770                 }
771             }
772             else version (Posix)
773             {
774                 int         policy;
775                 sched_param param;
776                 pthread_getschedparam( pthread_self(), &policy, &param ) == 0
777                     || assert(0, "Internal error in pthread_getschedparam");
778 
779                 result.PRIORITY_MIN = sched_get_priority_min( policy );
780                 result.PRIORITY_MIN != -1
781                     || assert(0, "Internal error in sched_get_priority_min");
782                 result.PRIORITY_DEFAULT = param.sched_priority;
783                 result.PRIORITY_MAX = sched_get_priority_max( policy );
784                 result.PRIORITY_MAX != -1 ||
785                     assert(0, "Internal error in sched_get_priority_max");
786             }
787 	    else version (FreeStanding)
788 	    {
789 		assert(0);
790 	    }
791             else
792             {
793                 static assert(0, "Your code here.");
794             }
795             return result;
796         }
797 
798         /**
799          * The minimum scheduling priority that may be set for a thread.  On
800          * systems where multiple scheduling policies are defined, this value
801          * represents the minimum valid priority for the scheduling policy of
802          * the process.
803          */
804         @property static int PRIORITY_MIN() @nogc nothrow pure @trusted
805         {
806             return (cast(int function() @nogc nothrow pure @safe)
807                 &loadGlobal!"PRIORITY_MIN")();
808         }
809 
810         /**
811          * The maximum scheduling priority that may be set for a thread.  On
812          * systems where multiple scheduling policies are defined, this value
813          * represents the maximum valid priority for the scheduling policy of
814          * the process.
815          */
816         @property static const(int) PRIORITY_MAX() @nogc nothrow pure @trusted
817         {
818             return (cast(int function() @nogc nothrow pure @safe)
819                 &loadGlobal!"PRIORITY_MAX")();
820         }
821 
822         /**
823          * The default scheduling priority that is set for a thread.  On
824          * systems where multiple scheduling policies are defined, this value
825          * represents the default priority for the scheduling policy of
826          * the process.
827          */
828         @property static int PRIORITY_DEFAULT() @nogc nothrow pure @trusted
829         {
830             return (cast(int function() @nogc nothrow pure @safe)
831                 &loadGlobal!"PRIORITY_DEFAULT")();
832         }
833     }
834 
835     version (NetBSD)
836     {
837         //NetBSD does not support priority for default policy
838         // and it is not possible change policy without root access
839         int fakePriority = int.max;
840     }
841 
842     /**
843      * Gets the scheduling priority for the associated thread.
844      *
845      * Note: Getting the priority of a thread that already terminated
846      * might return the default priority.
847      *
848      * Returns:
849      *  The scheduling priority of this thread.
850      */
851     final @property int priority() @system
852     {
853         version (Windows)
854         {
855             return GetThreadPriority( m_hndl );
856         }
857         else version (NetBSD)
858         {
859            return fakePriority==int.max? PRIORITY_DEFAULT : fakePriority;
860         }
861         else version (Posix)
862         {
863             int         policy;
864             sched_param param;
865 
866             if (auto err = pthread_getschedparam(m_addr, &policy, &param))
867             {
868                 // ignore error if thread is not running => Bugzilla 8960
869                 if (!atomicLoad(m_isRunning)) return PRIORITY_DEFAULT;
870                 throw new ThreadException("Unable to get thread priority");
871             }
872             return param.sched_priority;
873         }
874     	else version (FreeStanding) { assert(0); }
875     }
876 
877 
878     /**
879      * Sets the scheduling priority for the associated thread.
880      *
881      * Note: Setting the priority of a thread that already terminated
882      * might have no effect.
883      *
884      * Params:
885      *  val = The new scheduling priority of this thread.
886      */
887     final @property void priority( int val )
888     in
889     {
890         assert(val >= PRIORITY_MIN);
891         assert(val <= PRIORITY_MAX);
892     }
893     do
894     {
895         version (Windows)
896         {
897             if ( !SetThreadPriority( m_hndl, val ) )
898                 throw new ThreadException( "Unable to set thread priority" );
899         }
900         else version (Solaris)
901         {
902             // the pthread_setschedprio(3c) and pthread_setschedparam functions
903             // are broken for the default (TS / time sharing) scheduling class.
904             // instead, we use priocntl(2) which gives us the desired behavior.
905 
906             // We hardcode the min and max priorities to the current value
907             // so this is a no-op for RT threads.
908             if (m_isRTClass)
909                 return;
910 
911             pcparms_t   pcparm;
912 
913             pcparm.pc_cid = PC_CLNULL;
914             if (priocntl(idtype_t.P_LWPID, P_MYID, PC_GETPARMS, &pcparm) == -1)
915                 throw new ThreadException( "Unable to get scheduling class" );
916 
917             pri_t* clparms = cast(pri_t*)&pcparm.pc_clparms;
918 
919             // clparms is filled in by the PC_GETPARMS call, only necessary
920             // to adjust the element that contains the thread priority
921             clparms[1] = cast(pri_t) val;
922 
923             if (priocntl(idtype_t.P_LWPID, P_MYID, PC_SETPARMS, &pcparm) == -1)
924                 throw new ThreadException( "Unable to set scheduling class" );
925         }
926         else version (NetBSD)
927         {
928            fakePriority = val;
929         }
930         else version (Posix)
931         {
932             static if (__traits(compiles, pthread_setschedprio))
933             {
934                 if (auto err = pthread_setschedprio(m_addr, val))
935                 {
936                     // ignore error if thread is not running => Bugzilla 8960
937                     if (!atomicLoad(m_isRunning)) return;
938                     throw new ThreadException("Unable to set thread priority");
939                 }
940             }
941             else
942             {
943                 // NOTE: pthread_setschedprio is not implemented on Darwin, FreeBSD, OpenBSD,
944                 //       or DragonFlyBSD, so use the more complicated get/set sequence below.
945                 int         policy;
946                 sched_param param;
947 
948                 if (auto err = pthread_getschedparam(m_addr, &policy, &param))
949                 {
950                     // ignore error if thread is not running => Bugzilla 8960
951                     if (!atomicLoad(m_isRunning)) return;
952                     throw new ThreadException("Unable to set thread priority");
953                 }
954                 param.sched_priority = val;
955                 if (auto err = pthread_setschedparam(m_addr, policy, &param))
956                 {
957                     // ignore error if thread is not running => Bugzilla 8960
958                     if (!atomicLoad(m_isRunning)) return;
959                     throw new ThreadException("Unable to set thread priority");
960                 }
961             }
962         }
963     }
964 
965 
966     unittest
967     {
968         auto thr = Thread.getThis();
969         immutable prio = thr.priority;
970         scope (exit) thr.priority = prio;
971 
972         assert(prio == PRIORITY_DEFAULT);
973         assert(prio >= PRIORITY_MIN && prio <= PRIORITY_MAX);
974         thr.priority = PRIORITY_MIN;
975         assert(thr.priority == PRIORITY_MIN);
976         thr.priority = PRIORITY_MAX;
977         assert(thr.priority == PRIORITY_MAX);
978     }
979 
980     unittest // Bugzilla 8960
981     {
982         import core.sync.semaphore;
983 
984         auto thr = new Thread({});
985         thr.start();
986         Thread.sleep(1.msecs);       // wait a little so the thread likely has finished
987         thr.priority = PRIORITY_MAX; // setting priority doesn't cause error
988         auto prio = thr.priority;    // getting priority doesn't cause error
989         assert(prio >= PRIORITY_MIN && prio <= PRIORITY_MAX);
990     }
991 
992     /**
993      * Tests whether this thread is running.
994      *
995      * Returns:
996      *  true if the thread is running, false if not.
997      */
998     override final @property bool isRunning() nothrow @nogc
999     {
1000         if (!super.isRunning())
1001             return false;
1002 
1003         version (Windows)
1004         {
1005             uint ecode = 0;
1006             GetExitCodeThread( m_hndl, &ecode );
1007             return ecode == STILL_ACTIVE;
1008         }
1009         else version (Posix)
1010         {
1011             return atomicLoad(m_isRunning);
1012         }
1013     	else version (FreeStanding) { assert(0); }
1014     }
1015 
1016 
1017     ///////////////////////////////////////////////////////////////////////////
1018     // Actions on Calling Thread
1019     ///////////////////////////////////////////////////////////////////////////
1020 
1021 
1022     /**
1023      * Suspends the calling thread for at least the supplied period.  This may
1024      * result in multiple OS calls if period is greater than the maximum sleep
1025      * duration supported by the operating system.
1026      *
1027      * Params:
1028      *  val = The minimum duration the calling thread should be suspended.
1029      *
1030      * In:
1031      *  period must be non-negative.
1032      *
1033      * Example:
1034      * ------------------------------------------------------------------------
1035      *
1036      * Thread.sleep( dur!("msecs")( 50 ) );  // sleep for 50 milliseconds
1037      * Thread.sleep( dur!("seconds")( 5 ) ); // sleep for 5 seconds
1038      *
1039      * ------------------------------------------------------------------------
1040      */
1041     static void sleep( Duration val ) @nogc nothrow @system
1042     in
1043     {
1044         assert( !val.isNegative );
1045     }
1046     do
1047     {
1048         version (Windows)
1049         {
1050             auto maxSleepMillis = dur!("msecs")( uint.max - 1 );
1051 
1052             // avoid a non-zero time to be round down to 0
1053             if ( val > dur!"msecs"( 0 ) && val < dur!"msecs"( 1 ) )
1054                 val = dur!"msecs"( 1 );
1055 
1056             // NOTE: In instances where all other threads in the process have a
1057             //       lower priority than the current thread, the current thread
1058             //       will not yield with a sleep time of zero.  However, unlike
1059             //       yield(), the user is not asking for a yield to occur but
1060             //       only for execution to suspend for the requested interval.
1061             //       Therefore, expected performance may not be met if a yield
1062             //       is forced upon the user.
1063             while ( val > maxSleepMillis )
1064             {
1065                 Sleep( cast(uint)
1066                        maxSleepMillis.total!"msecs" );
1067                 val -= maxSleepMillis;
1068             }
1069             Sleep( cast(uint) val.total!"msecs" );
1070         }
1071         else version (Posix)
1072         {
1073             timespec tin  = void;
1074             timespec tout = void;
1075 
1076             val.split!("seconds", "nsecs")(tin.tv_sec, tin.tv_nsec);
1077             if ( val.total!"seconds" > tin.tv_sec.max )
1078                 tin.tv_sec  = tin.tv_sec.max;
1079             while ( true )
1080             {
1081                 if ( !nanosleep( &tin, &tout ) )
1082                     return;
1083                 if ( errno != EINTR )
1084                     assert(0, "Unable to sleep for the specified duration");
1085                 tin = tout;
1086             }
1087         }
1088     }
1089 
1090 
1091     /**
1092      * Forces a context switch to occur away from the calling thread.
1093      */
1094     static void yield() @nogc nothrow
1095     {
1096         version (Windows)
1097             SwitchToThread();
1098         else version (Posix)
1099             sched_yield();
1100     }
1101 }
1102 
1103 private Thread toThread(return scope ThreadBase t) @trusted nothrow @nogc pure
1104 {
1105     return cast(Thread) cast(void*) t;
1106 }
1107 
1108 private extern(D) static void thread_yield() @nogc nothrow
1109 {
1110     Thread.yield();
1111 }
1112 
1113 ///
1114 unittest
1115 {
1116     class DerivedThread : Thread
1117     {
1118         this()
1119         {
1120             super(&run);
1121         }
1122 
1123     private:
1124         void run()
1125         {
1126             // Derived thread running.
1127         }
1128     }
1129 
1130     void threadFunc()
1131     {
1132         // Composed thread running.
1133     }
1134 
1135     // create and start instances of each type
1136     auto derived = new DerivedThread().start();
1137     auto composed = new Thread(&threadFunc).start();
1138     new Thread({
1139         // Codes to run in the newly created thread.
1140     }).start();
1141 }
1142 
1143 unittest
1144 {
1145     int x = 0;
1146 
1147     new Thread(
1148     {
1149         x++;
1150     }).start().join();
1151     assert( x == 1 );
1152 }
1153 
1154 
1155 unittest
1156 {
1157     enum MSG = "Test message.";
1158     string caughtMsg;
1159 
1160     try
1161     {
1162         new Thread(
1163         function()
1164         {
1165             throw new Exception( MSG );
1166         }).start().join();
1167         assert( false, "Expected rethrown exception." );
1168     }
1169     catch ( Throwable t )
1170     {
1171         assert( t.msg == MSG );
1172     }
1173 }
1174 
1175 
1176 unittest
1177 {
1178     // use >pageSize to avoid stack overflow (e.g. in an syscall)
1179     auto thr = new Thread(function{}, 4096 + 1).start();
1180     thr.join();
1181 }
1182 
1183 
1184 unittest
1185 {
1186     import core.memory : GC;
1187 
1188     auto t1 = new Thread({
1189         foreach (_; 0 .. 20)
1190             ThreadBase.getAll;
1191     }).start;
1192     auto t2 = new Thread({
1193         foreach (_; 0 .. 20)
1194             GC.collect;
1195     }).start;
1196     t1.join();
1197     t2.join();
1198 }
1199 
1200 unittest
1201 {
1202     import core.sync.semaphore;
1203     auto sem = new Semaphore();
1204 
1205     auto t = new Thread(
1206     {
1207         sem.notify();
1208         Thread.sleep(100.msecs);
1209     }).start();
1210 
1211     sem.wait(); // thread cannot be detached while being started
1212     thread_detachInstance(t);
1213     foreach (t2; Thread)
1214         assert(t !is t2);
1215     t.join();
1216 }
1217 
1218 unittest
1219 {
1220     // NOTE: This entire test is based on the assumption that no
1221     //       memory is allocated after the child thread is
1222     //       started. If an allocation happens, a collection could
1223     //       trigger, which would cause the synchronization below
1224     //       to cause a deadlock.
1225     // NOTE: DO NOT USE LOCKS IN CRITICAL REGIONS IN NORMAL CODE.
1226 
1227     import core.sync.semaphore;
1228 
1229     auto sema = new Semaphore(),
1230          semb = new Semaphore();
1231 
1232     auto thr = new Thread(
1233     {
1234         thread_enterCriticalRegion();
1235         assert(thread_inCriticalRegion());
1236         sema.notify();
1237 
1238         semb.wait();
1239         assert(thread_inCriticalRegion());
1240 
1241         thread_exitCriticalRegion();
1242         assert(!thread_inCriticalRegion());
1243         sema.notify();
1244 
1245         semb.wait();
1246         assert(!thread_inCriticalRegion());
1247     });
1248 
1249     thr.start();
1250 
1251     sema.wait();
1252     synchronized (ThreadBase.criticalRegionLock)
1253         assert(thr.m_isInCriticalRegion);
1254     semb.notify();
1255 
1256     sema.wait();
1257     synchronized (ThreadBase.criticalRegionLock)
1258         assert(!thr.m_isInCriticalRegion);
1259     semb.notify();
1260 
1261     thr.join();
1262 }
1263 
1264 // https://issues.dlang.org/show_bug.cgi?id=22124
1265 unittest
1266 {
1267     Thread thread = new Thread({});
1268     auto fun(Thread t, int x)
1269     {
1270         t.__ctor({x = 3;});
1271         return t;
1272     }
1273     static assert(!__traits(compiles, () @nogc => fun(thread, 3) ));
1274 }
1275 
1276 unittest
1277 {
1278     import core.sync.semaphore;
1279 
1280     shared bool inCriticalRegion;
1281     auto sema = new Semaphore(),
1282          semb = new Semaphore();
1283 
1284     auto thr = new Thread(
1285     {
1286         thread_enterCriticalRegion();
1287         inCriticalRegion = true;
1288         sema.notify();
1289         semb.wait();
1290 
1291         Thread.sleep(dur!"msecs"(1));
1292         inCriticalRegion = false;
1293         thread_exitCriticalRegion();
1294     });
1295     thr.start();
1296 
1297     sema.wait();
1298     assert(inCriticalRegion);
1299     semb.notify();
1300 
1301     thread_suspendAll();
1302     assert(!inCriticalRegion);
1303     thread_resumeAll();
1304 }
1305 
1306 ///////////////////////////////////////////////////////////////////////////////
1307 // GC Support Routines
1308 ///////////////////////////////////////////////////////////////////////////////
1309 
1310 version (CoreDdoc)
1311 {
1312     /**
1313      * Instruct the thread module, when initialized, to use a different set of
1314      * signals besides SIGRTMIN and SIGRTMIN + 1 for suspension and resumption of threads.
1315      * This function should be called at most once, prior to thread_init().
1316      * This function is Posix-only.
1317      */
1318     extern (C) void thread_setGCSignals(int suspendSignalNo, int resumeSignalNo) nothrow @nogc
1319     {
1320     }
1321 }
1322 else version (Posix)
1323 {
1324     extern (C) void thread_setGCSignals(int suspendSignalNo, int resumeSignalNo) nothrow @nogc
1325     in
1326     {
1327         assert(suspendSignalNo != 0);
1328         assert(resumeSignalNo  != 0);
1329     }
1330     out
1331     {
1332         assert(suspendSignalNumber != 0);
1333         assert(resumeSignalNumber  != 0);
1334     }
1335     do
1336     {
1337         suspendSignalNumber = suspendSignalNo;
1338         resumeSignalNumber  = resumeSignalNo;
1339     }
1340 }
1341 
1342 version (Posix)
1343 {
1344     private __gshared int suspendSignalNumber;
1345     private __gshared int resumeSignalNumber;
1346 }
1347 
1348 private extern (D) ThreadBase attachThread(ThreadBase _thisThread) @nogc nothrow
1349 {
1350     Thread thisThread = _thisThread.toThread();
1351 
1352     StackContext* thisContext = &thisThread.m_main;
1353     assert( thisContext == thisThread.m_curr );
1354 
1355     version (SupportSanitizers)
1356     {
1357         // Save this thread's fake stack handler, to be stored in each StackContext belonging to this thread.
1358         thisThread.asan_fakestack  = asanGetCurrentFakeStack();
1359         thisContext.asan_fakestack = thisThread.asan_fakestack;
1360     }
1361 
1362     version (Windows)
1363     {
1364         thisThread.m_addr  = GetCurrentThreadId();
1365         thisThread.m_hndl  = GetCurrentThreadHandle();
1366         thisContext.bstack = getStackBottom();
1367         thisContext.tstack = thisContext.bstack;
1368     }
1369     else version (Posix)
1370     {
1371         thisThread.m_addr  = pthread_self();
1372         thisContext.bstack = getStackBottom();
1373         thisContext.tstack = thisContext.bstack;
1374 
1375         atomicStore!(MemoryOrder.raw)(thisThread.toThread.m_isRunning, true);
1376     }
1377     thisThread.m_isDaemon = true;
1378     thisThread.tlsGCdataInit();
1379     Thread.setThis( thisThread );
1380 
1381     version (Darwin)
1382     {
1383         thisThread.m_tmach = pthread_mach_thread_np( thisThread.m_addr );
1384         assert( thisThread.m_tmach != thisThread.m_tmach.init );
1385     }
1386 
1387     Thread.add( thisThread, false );
1388     Thread.add( thisContext );
1389     if ( Thread.sm_main !is null )
1390         multiThreadedFlag = true;
1391     return thisThread;
1392 }
1393 
1394 /**
1395  * Registers the calling thread for use with the D Runtime.  If this routine
1396  * is called for a thread which is already registered, no action is performed.
1397  *
1398  * NOTE: This routine does not run thread-local static constructors when called.
1399  *       If full functionality as a D thread is desired, the following function
1400  *       must be called after thread_attachThis:
1401  *
1402  *       extern (C) void rt_moduleTlsCtor();
1403  *
1404  * See_Also:
1405  *     $(REF thread_detachThis, core,thread,threadbase)
1406  */
1407 extern(C) Thread thread_attachThis()
1408 {
1409     return thread_attachThis_tpl!Thread();
1410 }
1411 
1412 
1413 version (Windows)
1414 {
1415     // NOTE: These calls are not safe on Posix systems that use signals to
1416     //       perform garbage collection.  The suspendHandler uses getThis()
1417     //       to get the thread handle so getThis() must be a simple call.
1418     //       Mutexes can't safely be acquired inside signal handlers, and
1419     //       even if they could, the mutex needed (Thread.slock) is held by
1420     //       thread_suspendAll().  So in short, these routines will remain
1421     //       Windows-specific.  If they are truly needed elsewhere, the
1422     //       suspendHandler will need a way to call a version of getThis()
1423     //       that only does the TLS lookup without the fancy fallback stuff.
1424 
1425     /// ditto
1426     extern (C) Thread thread_attachByAddr( ThreadID addr )
1427     {
1428         return thread_attachByAddrB( addr, getThreadStackBottom( addr ) );
1429     }
1430 
1431 
1432     /// ditto
1433     extern (C) Thread thread_attachByAddrB( ThreadID addr, void* bstack )
1434     {
1435         GC.disable(); scope(exit) GC.enable();
1436 
1437         if (auto t = thread_findByAddr(addr).toThread)
1438             return t;
1439 
1440         Thread        thisThread  = new Thread();
1441         StackContext* thisContext = &thisThread.m_main;
1442         assert( thisContext == thisThread.m_curr );
1443 
1444         thisThread.m_addr  = addr;
1445         thisContext.bstack = bstack;
1446         thisContext.tstack = thisContext.bstack;
1447 
1448         thisThread.m_isDaemon = true;
1449 
1450         if ( addr == GetCurrentThreadId() )
1451         {
1452             thisThread.m_hndl = GetCurrentThreadHandle();
1453             thisThread.tlsGCdataInit();
1454             Thread.setThis( thisThread );
1455 
1456             version (SupportSanitizers)
1457             {
1458                 // Save this thread's fake stack handler, to be stored in each StackContext belonging to this thread.
1459                 thisThread.asan_fakestack  = asanGetCurrentFakeStack();
1460             }
1461         }
1462         else
1463         {
1464             thisThread.m_hndl = OpenThreadHandle( addr );
1465             impersonate_thread(addr,
1466             {
1467                 thisThread.tlsGCdataInit();
1468                 Thread.setThis( thisThread );
1469 
1470                 version (SupportSanitizers)
1471                 {
1472                     // Save this thread's fake stack handler, to be stored in each StackContext belonging to this thread.
1473                     thisThread.asan_fakestack  = asanGetCurrentFakeStack();
1474                 }
1475             });
1476         }
1477 
1478         version (SupportSanitizers)
1479         {
1480             thisContext.asan_fakestack = thisThread.asan_fakestack;
1481         }
1482 
1483         Thread.add( thisThread, false );
1484         Thread.add( thisContext );
1485         if ( Thread.sm_main !is null )
1486             multiThreadedFlag = true;
1487         return thisThread;
1488     }
1489 }
1490 
1491 
1492 // Calls the given delegate, passing the current thread's stack pointer to it.
1493 package extern(D) void callWithStackShell(scope callWithStackShellDg fn) nothrow @system
1494 in (fn)
1495 {
1496     // The purpose of the 'shell' is to ensure all the registers get
1497     // put on the stack so they'll be scanned. We only need to push
1498     // the callee-save registers.
1499     void *sp = void;
1500     version (GNU)
1501     {
1502         __builtin_unwind_init();
1503         sp = &sp;
1504     }
1505     else version (AsmX86_Posix)
1506     {
1507         size_t[3] regs = void;
1508         asm pure nothrow @nogc
1509         {
1510             mov [regs + 0 * 4], EBX;
1511             mov [regs + 1 * 4], ESI;
1512             mov [regs + 2 * 4], EDI;
1513 
1514             mov sp[EBP], ESP;
1515         }
1516     }
1517     else version (AsmX86_Windows)
1518     {
1519         size_t[3] regs = void;
1520         asm pure nothrow @nogc
1521         {
1522             mov [regs + 0 * 4], EBX;
1523             mov [regs + 1 * 4], ESI;
1524             mov [regs + 2 * 4], EDI;
1525 
1526             mov sp[EBP], ESP;
1527         }
1528     }
1529     else version (AsmX86_64_Posix)
1530     {
1531         size_t[5] regs = void;
1532         asm pure nothrow @nogc
1533         {
1534             mov [regs + 0 * 8], RBX;
1535             mov [regs + 1 * 8], R12;
1536             mov [regs + 2 * 8], R13;
1537             mov [regs + 3 * 8], R14;
1538             mov [regs + 4 * 8], R15;
1539 
1540             mov sp[RBP], RSP;
1541         }
1542     }
1543     else version (AsmX86_64_Windows)
1544     {
1545         size_t[7] regs = void;
1546         asm pure nothrow @nogc
1547         {
1548             mov [regs + 0 * 8], RBX;
1549             mov [regs + 1 * 8], RSI;
1550             mov [regs + 2 * 8], RDI;
1551             mov [regs + 3 * 8], R12;
1552             mov [regs + 4 * 8], R13;
1553             mov [regs + 5 * 8], R14;
1554             mov [regs + 6 * 8], R15;
1555 
1556             mov sp[RBP], RSP;
1557         }
1558     }
1559     else version (LDC)
1560     {
1561         version (PPC_Any)
1562         {
1563             // Nonvolatile registers, according to:
1564             // System V Application Binary Interface
1565             // PowerPC Processor Supplement, September 1995
1566             // ELFv1: 64-bit PowerPC ELF ABI Supplement 1.9, July 2004
1567             // ELFv2: Power Architecture, 64-Bit ELV V2 ABI Specification,
1568             //        OpenPOWER ABI for Linux Supplement, July 2014
1569             size_t[18] regs = void;
1570             static foreach (i; 0 .. regs.length)
1571             {{
1572                 enum int j = 14 + i; // source register
1573                 static if (j == 21)
1574                 {
1575                     // Work around LLVM bug 21443 (http://llvm.org/bugs/show_bug.cgi?id=21443)
1576                     // Because we clobber r0 a different register is chosen
1577                     asm pure nothrow @nogc { ("std "~j.stringof~", %0") : "=m" (regs[i]) : : "r0"; }
1578                 }
1579                 else
1580                     asm pure nothrow @nogc { ("std "~j.stringof~", %0") : "=m" (regs[i]); }
1581             }}
1582 
1583             asm pure nothrow @nogc { "std 1, %0" : "=m" (sp); }
1584         }
1585         else version (AArch64)
1586         {
1587             // Callee-save registers, x19-x28 according to AAPCS64, section
1588             // 5.1.1.  Include x29 fp because it optionally can be a callee
1589             // saved reg
1590             size_t[11] regs = void;
1591             // store the registers in pairs
1592             asm pure nothrow @nogc
1593             {
1594                 "stp x19, x20, %0" : "=m" (regs[ 0]), "=m" (regs[1]);
1595                 "stp x21, x22, %0" : "=m" (regs[ 2]), "=m" (regs[3]);
1596                 "stp x23, x24, %0" : "=m" (regs[ 4]), "=m" (regs[5]);
1597                 "stp x25, x26, %0" : "=m" (regs[ 6]), "=m" (regs[7]);
1598                 "stp x27, x28, %0" : "=m" (regs[ 8]), "=m" (regs[9]);
1599                 "str x29, %0"      : "=m" (regs[10]);
1600                 "mov %0, sp"       : "=r" (sp);
1601             }
1602         }
1603         else version (ARM)
1604         {
1605             // Callee-save registers, according to AAPCS, section 5.1.1.
1606             // arm and thumb2 instructions
1607             size_t[8] regs = void;
1608             asm pure nothrow @nogc
1609             {
1610                 "stm %0, {r4-r11}" : : "r" (regs.ptr) : "memory";
1611                 "mov %0, sp"       : "=r" (sp);
1612             }
1613         }
1614         else version (MIPS_Any)
1615         {
1616             version (MIPS32)      enum store = "sw";
1617             else version (MIPS64) enum store = "sd";
1618             else static assert(0);
1619 
1620             // Callee-save registers, according to MIPS Calling Convention
1621             // and MIPSpro N32 ABI Handbook, chapter 2, table 2-1.
1622             // FIXME: Should $28 (gp) and $30 (s8) be saved, too?
1623             size_t[8] regs = void;
1624             asm pure nothrow @nogc { ".set noat"; }
1625             static foreach (i; 0 .. regs.length)
1626             {{
1627                 enum int j = 16 + i; // source register
1628                 asm pure nothrow @nogc { (store ~ " $"~j.stringof~", %0") : "=m" (regs[i]); }
1629             }}
1630             asm pure nothrow @nogc { (store ~ " $29, %0") : "=m" (sp); }
1631             asm pure nothrow @nogc { ".set at"; }
1632         }
1633         else version (RISCV_Any)
1634         {
1635             version (RISCV32)      enum store = "sw";
1636             else version (RISCV64) enum store = "sd";
1637             else static assert(0);
1638 
1639             // Callee-save registers, according to RISCV Calling Convention
1640             // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc
1641             size_t[24] regs = void;
1642             static foreach (i; 0 .. 12)
1643             {{
1644                 enum int j = i;
1645                 asm pure nothrow @nogc { (store ~ " s"~j.stringof~", %0") : "=m" (regs[i]); }
1646             }}
1647             static foreach (i; 0 .. 12)
1648             {{
1649                 enum int j = i;
1650                 asm pure nothrow @nogc { ("f" ~ store ~ " fs"~j.stringof~", %0") : "=m" (regs[i + 12]); }
1651             }}
1652             asm pure nothrow @nogc { (store ~ " sp, %0") : "=m" (sp); }
1653         }
1654         else version (LoongArch64)
1655         {
1656             // Callee-save registers, according to LoongArch Calling Convention
1657             // https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html
1658             size_t[18] regs = void;
1659             static foreach (i; 0 .. 8)
1660             {{
1661                 enum int j = i;
1662                 // save $fs0 - $fs7
1663                 asm pure nothrow @nogc { ( "fst.d $fs"~j.stringof~", %0") : "=m" (regs[i]); }
1664             }}
1665             static foreach (i; 0 .. 9)
1666             {{
1667                 enum int j = i;
1668                 // save $s0 - $s8
1669                 asm pure nothrow @nogc { ( "st.d $s"~j.stringof~", %0") : "=m" (regs[i + 8]); }
1670             }}
1671             // save $fp (or $s9) and $sp
1672             asm pure nothrow @nogc { ( "st.d $fp, %0") : "=m" (regs[17]); }
1673             asm pure nothrow @nogc { ( "st.d $sp, %0") : "=m" (sp); }
1674         }
1675         else version (Emscripten) {
1676             sp = emscripten_stack_get_current();
1677         }
1678 	else version (FreeStanding) {
1679             assert(0);
1680 	}
1681         else
1682         {
1683             static assert(false, "Architecture not supported.");
1684         }
1685     }
1686     else
1687     {
1688         static assert(false, "Architecture not supported.");
1689     }
1690 
1691     fn(sp);
1692 }
1693 
1694 version (Windows)
1695 private extern (D) void scanWindowsOnly(scope ScanAllThreadsTypeFn scan, ThreadBase _t) nothrow @system
1696 {
1697     auto t = _t.toThread;
1698 
1699     scan( ScanType.stack, t.m_reg.ptr, t.m_reg.ptr + t.m_reg.length );
1700 }
1701 
1702 
1703 /**
1704  * Returns the process ID of the calling process, which is guaranteed to be
1705  * unique on the system. This call is always successful.
1706  *
1707  * Example:
1708  * ---
1709  * writefln("Current process id: %s", getpid());
1710  * ---
1711  */
1712 version (Posix)
1713 {
1714     import core.sys.posix.unistd;
1715 
1716     alias getpid = core.sys.posix.unistd.getpid;
1717 }
1718 else version (Windows)
1719 {
1720     alias getpid = core.sys.windows.winbase.GetCurrentProcessId;
1721 }
1722 
1723 extern (C) @nogc nothrow
1724 {
1725     version (CRuntime_Glibc)  version = PThread_Getattr_NP;
1726     version (CRuntime_Bionic) version = PThread_Getattr_NP;
1727     version (CRuntime_Musl)   version = PThread_Getattr_NP;
1728     version (CRuntime_UClibc) version = PThread_Getattr_NP;
1729 
1730     version (FreeBSD)         version = PThread_Attr_Get_NP;
1731     version (NetBSD)          version = PThread_Attr_Get_NP;
1732     version (DragonFlyBSD)    version = PThread_Attr_Get_NP;
1733 
1734     version (PThread_Getattr_NP)  int pthread_getattr_np(pthread_t thread, pthread_attr_t* attr);
1735     version (PThread_Attr_Get_NP) int pthread_attr_get_np(pthread_t thread, pthread_attr_t* attr);
1736     version (Solaris) int thr_stksegment(stack_t* stk);
1737     version (OpenBSD) int pthread_stackseg_np(pthread_t thread, stack_t* sinfo);
1738 }
1739 
1740 
1741 version (LDC)
1742 {
1743     version (X86)      version = LDC_stackTopAsm;
1744     version (X86_64)   version = LDC_stackTopAsm;
1745     version (ARM_Any)  version = LDC_stackTopAsm;
1746     version (PPC_Any)  version = LDC_stackTopAsm;
1747     version (MIPS_Any) version = LDC_stackTopAsm;
1748 
1749     version (LDC_stackTopAsm)
1750     {
1751         /* The inline assembler is written in a style that the code can be inlined.
1752          * If it isn't, the function is still naked, so the caller's stack pointer
1753          * is used nevertheless.
1754          */
1755         package extern(D) void* getStackTop() nothrow @nogc @naked
1756         {
1757             version (X86)
1758                 return __asm!(void*)("movl %esp, $0", "=r");
1759             else version (X86_64)
1760                 return __asm!(void*)("movq %rsp, $0", "=r");
1761             else version (ARM_Any)
1762                 return __asm!(void*)("mov $0, sp", "=r");
1763             else version (PPC_Any)
1764                 return __asm!(void*)("mr $0, 1", "=r");
1765             else version (MIPS_Any)
1766                 return __asm!(void*)("move $0, $$sp", "=r");
1767             else
1768                 static assert(0);
1769         }
1770     }
1771     else
1772     {
1773         /* The use of intrinsic llvm_frameaddress is a reasonable default for
1774          * cpu architectures without assembler support from LLVM. Because of
1775          * the slightly different meaning the function must neither be inlined
1776          * nor naked.
1777          */
1778         package extern(D) void* getStackTop() nothrow @nogc
1779         {
1780             import ldc.intrinsics;
1781             pragma(LDC_never_inline);
1782             return llvm_frameaddress(0);
1783         }
1784     }
1785 }
1786 else
1787 package extern(D) void* getStackTop() nothrow @nogc
1788 {
1789     version (D_InlineAsm_X86)
1790         asm pure nothrow @nogc { naked; mov EAX, ESP; ret; }
1791     else version (D_InlineAsm_X86_64)
1792         asm pure nothrow @nogc { naked; mov RAX, RSP; ret; }
1793     else version (GNU)
1794         return __builtin_frame_address(0);
1795     else
1796         static assert(false, "Architecture not supported.");
1797 }
1798 
1799 
1800 version (LDC_Windows)
1801 {
1802     package extern(D) void* getStackBottom() nothrow @nogc @naked
1803     {
1804         version (X86)
1805             return __asm!(void*)("mov %fs:(4), $0", "=r");
1806         else version (X86_64)
1807             return __asm!(void*)("mov %gs:0($1), $0", "=r,r", 8);
1808         else
1809             static assert(false, "Architecture not supported.");
1810     }
1811 }
1812 else
1813 package extern(D) void* getStackBottom() nothrow @nogc @system
1814 {
1815     version (Windows)
1816     {
1817         version (D_InlineAsm_X86)
1818             asm pure nothrow @nogc { naked; mov EAX, FS:4; ret; }
1819         else version (D_InlineAsm_X86_64)
1820             asm pure nothrow @nogc
1821             {    naked;
1822                  mov RAX, 8;
1823                  mov RAX, GS:[RAX];
1824                  ret;
1825             }
1826         else
1827             static assert(false, "Architecture not supported.");
1828     }
1829     else version (Darwin)
1830     {
1831         import core.sys.darwin.pthread;
1832         return pthread_get_stackaddr_np(pthread_self());
1833     }
1834     else version (PThread_Getattr_NP)
1835     {
1836         pthread_attr_t attr;
1837         void* addr; size_t size;
1838 
1839         pthread_attr_init(&attr);
1840         pthread_getattr_np(pthread_self(), &attr);
1841         pthread_attr_getstack(&attr, &addr, &size);
1842         pthread_attr_destroy(&attr);
1843         static if (isStackGrowingDown)
1844             addr += size;
1845         return addr;
1846     }
1847     else version (PThread_Attr_Get_NP)
1848     {
1849         pthread_attr_t attr;
1850         void* addr; size_t size;
1851 
1852         pthread_attr_init(&attr);
1853         pthread_attr_get_np(pthread_self(), &attr);
1854         pthread_attr_getstack(&attr, &addr, &size);
1855         pthread_attr_destroy(&attr);
1856         static if (isStackGrowingDown)
1857             addr += size;
1858         return addr;
1859     }
1860     else version (OpenBSD)
1861     {
1862         stack_t stk;
1863 
1864         pthread_stackseg_np(pthread_self(), &stk);
1865         return stk.ss_sp;
1866     }
1867     else version (Solaris)
1868     {
1869         stack_t stk;
1870 
1871         thr_stksegment(&stk);
1872         return stk.ss_sp;
1873     }
1874     else version (FreeStanding) { assert(0); }
1875     else
1876         static assert(false, "Platform not supported.");
1877 }
1878 
1879 /**
1880  * Suspend the specified thread and load stack and register information for
1881  * use by thread_scanAll.  If the supplied thread is the calling thread,
1882  * stack and register information will be loaded but the thread will not
1883  * be suspended.  If the suspend operation fails and the thread is not
1884  * running then it will be removed from the global thread list, otherwise
1885  * an exception will be thrown.
1886  *
1887  * Params:
1888  *  t = The thread to suspend.
1889  *
1890  * Throws:
1891  *  ThreadError if the suspend operation fails for a running thread.
1892  * Returns:
1893  *  Whether the thread is now suspended (true) or terminated (false).
1894  */
1895 private extern (D) bool suspend( Thread t ) nothrow @nogc
1896 {
1897     Duration waittime = dur!"usecs"(10);
1898  Lagain:
1899     if (!t.isRunning)
1900     {
1901         Thread.remove(t);
1902         return false;
1903     }
1904     else if (t.m_isInCriticalRegion)
1905     {
1906         Thread.criticalRegionLock.unlock_nothrow();
1907         Thread.sleep(waittime);
1908         if (waittime < dur!"msecs"(10)) waittime *= 2;
1909         Thread.criticalRegionLock.lock_nothrow();
1910         goto Lagain;
1911     }
1912 
1913     version (Windows)
1914     {
1915         if ( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF )
1916         {
1917             if ( !t.isRunning )
1918             {
1919                 Thread.remove( t );
1920                 return false;
1921             }
1922             onThreadError( "Unable to suspend thread" );
1923         }
1924 
1925         CONTEXT context = void;
1926         context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
1927 
1928         if ( !GetThreadContext( t.m_hndl, &context ) )
1929             onThreadError( "Unable to load thread context" );
1930         version (X86)
1931         {
1932             if ( !t.m_lock )
1933                 t.m_curr.tstack = cast(void*) context.Esp;
1934             // eax,ebx,ecx,edx,edi,esi,ebp,esp
1935             t.m_reg[0] = context.Eax;
1936             t.m_reg[1] = context.Ebx;
1937             t.m_reg[2] = context.Ecx;
1938             t.m_reg[3] = context.Edx;
1939             t.m_reg[4] = context.Edi;
1940             t.m_reg[5] = context.Esi;
1941             t.m_reg[6] = context.Ebp;
1942             t.m_reg[7] = context.Esp;
1943         }
1944         else version (X86_64)
1945         {
1946             if ( !t.m_lock )
1947                 t.m_curr.tstack = cast(void*) context.Rsp;
1948             // rax,rbx,rcx,rdx,rdi,rsi,rbp,rsp
1949             t.m_reg[0] = context.Rax;
1950             t.m_reg[1] = context.Rbx;
1951             t.m_reg[2] = context.Rcx;
1952             t.m_reg[3] = context.Rdx;
1953             t.m_reg[4] = context.Rdi;
1954             t.m_reg[5] = context.Rsi;
1955             t.m_reg[6] = context.Rbp;
1956             t.m_reg[7] = context.Rsp;
1957             // r8,r9,r10,r11,r12,r13,r14,r15
1958             t.m_reg[8]  = context.R8;
1959             t.m_reg[9]  = context.R9;
1960             t.m_reg[10] = context.R10;
1961             t.m_reg[11] = context.R11;
1962             t.m_reg[12] = context.R12;
1963             t.m_reg[13] = context.R13;
1964             t.m_reg[14] = context.R14;
1965             t.m_reg[15] = context.R15;
1966         }
1967         else
1968         {
1969             static assert(false, "Architecture not supported." );
1970         }
1971     }
1972     else version (Darwin)
1973     {
1974         if ( t.m_addr != pthread_self() && thread_suspend( t.m_tmach ) != KERN_SUCCESS )
1975         {
1976             if ( !t.isRunning )
1977             {
1978                 Thread.remove( t );
1979                 return false;
1980             }
1981             onThreadError( "Unable to suspend thread" );
1982         }
1983 
1984         version (X86)
1985         {
1986             x86_thread_state32_t    state = void;
1987             mach_msg_type_number_t  count = x86_THREAD_STATE32_COUNT;
1988 
1989             if ( thread_get_state( t.m_tmach, x86_THREAD_STATE32, &state, &count ) != KERN_SUCCESS )
1990                 onThreadError( "Unable to load thread state" );
1991             if ( !t.m_lock )
1992                 t.m_curr.tstack = cast(void*) state.esp;
1993             // eax,ebx,ecx,edx,edi,esi,ebp,esp
1994             t.m_reg[0] = state.eax;
1995             t.m_reg[1] = state.ebx;
1996             t.m_reg[2] = state.ecx;
1997             t.m_reg[3] = state.edx;
1998             t.m_reg[4] = state.edi;
1999             t.m_reg[5] = state.esi;
2000             t.m_reg[6] = state.ebp;
2001             t.m_reg[7] = state.esp;
2002         }
2003         else version (X86_64)
2004         {
2005             x86_thread_state64_t    state = void;
2006             mach_msg_type_number_t  count = x86_THREAD_STATE64_COUNT;
2007 
2008             if ( thread_get_state( t.m_tmach, x86_THREAD_STATE64, &state, &count ) != KERN_SUCCESS )
2009                 onThreadError( "Unable to load thread state" );
2010             if ( !t.m_lock )
2011                 t.m_curr.tstack = cast(void*) state.rsp;
2012             // rax,rbx,rcx,rdx,rdi,rsi,rbp,rsp
2013             t.m_reg[0] = state.rax;
2014             t.m_reg[1] = state.rbx;
2015             t.m_reg[2] = state.rcx;
2016             t.m_reg[3] = state.rdx;
2017             t.m_reg[4] = state.rdi;
2018             t.m_reg[5] = state.rsi;
2019             t.m_reg[6] = state.rbp;
2020             t.m_reg[7] = state.rsp;
2021             // r8,r9,r10,r11,r12,r13,r14,r15
2022             t.m_reg[8]  = state.r8;
2023             t.m_reg[9]  = state.r9;
2024             t.m_reg[10] = state.r10;
2025             t.m_reg[11] = state.r11;
2026             t.m_reg[12] = state.r12;
2027             t.m_reg[13] = state.r13;
2028             t.m_reg[14] = state.r14;
2029             t.m_reg[15] = state.r15;
2030         }
2031         else version (AArch64)
2032         {
2033             arm_thread_state64_t state = void;
2034             mach_msg_type_number_t count = ARM_THREAD_STATE64_COUNT;
2035 
2036             if (thread_get_state(t.m_tmach, ARM_THREAD_STATE64, &state, &count) != KERN_SUCCESS)
2037                 onThreadError("Unable to load thread state");
2038             // TODO: ThreadException here recurses forever!  Does it
2039             //still using onThreadError?
2040             //printf("state count %d (expect %d)\n", count ,ARM_THREAD_STATE64_COUNT);
2041             if (!t.m_lock)
2042                 t.m_curr.tstack = cast(void*) state.sp;
2043 
2044             t.m_reg[0..29] = state.x;  // x0-x28
2045             t.m_reg[29] = state.fp;    // x29
2046             t.m_reg[30] = state.lr;    // x30
2047             t.m_reg[31] = state.sp;    // x31
2048             t.m_reg[32] = state.pc;
2049         }
2050         else version (ARM)
2051         {
2052             arm_thread_state32_t state = void;
2053             mach_msg_type_number_t count = ARM_THREAD_STATE32_COUNT;
2054 
2055             // Thought this would be ARM_THREAD_STATE32, but that fails.
2056             // Mystery
2057             if (thread_get_state(t.m_tmach, ARM_THREAD_STATE, &state, &count) != KERN_SUCCESS)
2058                 onThreadError("Unable to load thread state");
2059             // TODO: in past, ThreadException here recurses forever!  Does it
2060             //still using onThreadError?
2061             //printf("state count %d (expect %d)\n", count ,ARM_THREAD_STATE32_COUNT);
2062             if (!t.m_lock)
2063                 t.m_curr.tstack = cast(void*) state.sp;
2064 
2065             t.m_reg[0..13] = state.r;  // r0 - r13
2066             t.m_reg[13] = state.sp;
2067             t.m_reg[14] = state.lr;
2068             t.m_reg[15] = state.pc;
2069         }
2070         else version (PPC)
2071         {
2072             ppc_thread_state_t state = void;
2073             mach_msg_type_number_t count = PPC_THREAD_STATE_COUNT;
2074 
2075             if (thread_get_state(t.m_tmach, PPC_THREAD_STATE, &state, &count) != KERN_SUCCESS)
2076                 onThreadError("Unable to load thread state");
2077             if (!t.m_lock)
2078                 t.m_curr.tstack = cast(void*) state.r[1];
2079             t.m_reg[] = state.r[];
2080         }
2081         else version (PPC64)
2082         {
2083             ppc_thread_state64_t state = void;
2084             mach_msg_type_number_t count = PPC_THREAD_STATE64_COUNT;
2085 
2086             if (thread_get_state(t.m_tmach, PPC_THREAD_STATE64, &state, &count) != KERN_SUCCESS)
2087                 onThreadError("Unable to load thread state");
2088             if (!t.m_lock)
2089                 t.m_curr.tstack = cast(void*) state.r[1];
2090             t.m_reg[] = state.r[];
2091         }
2092         else
2093         {
2094             static assert(false, "Architecture not supported." );
2095         }
2096     }
2097     else version (Posix)
2098     {
2099         if ( t.m_addr != pthread_self() )
2100         {
2101             if ( pthread_kill( t.m_addr, suspendSignalNumber ) != 0 )
2102             {
2103                 if ( !t.isRunning )
2104                 {
2105                     Thread.remove( t );
2106                     return false;
2107                 }
2108                 onThreadError( "Unable to suspend thread" );
2109             }
2110         }
2111         else if ( !t.m_lock )
2112         {
2113             t.m_curr.tstack = getStackTop();
2114         }
2115     }
2116     return true;
2117 }
2118 
2119 /**
2120  * Runs the necessary operations required before stopping the world.
2121  */
2122 extern (C) void thread_preStopTheWorld() nothrow {
2123     Thread.slock.lock_nothrow();
2124 }
2125 
2126 /**
2127  * Suspend all threads but the calling thread for "stop the world" garbage
2128  * collection runs.  This function may be called multiple times, and must
2129  * be followed by a matching number of calls to thread_resumeAll before
2130  * processing is resumed.
2131  *
2132  * Throws:
2133  *  ThreadError if the suspend operation fails for a running thread.
2134  */
2135 extern (C) void thread_suspendAll() nothrow
2136 {
2137     // NOTE: We've got an odd chicken & egg problem here, because while the GC
2138     //       is required to call thread_init before calling any other thread
2139     //       routines, thread_init may allocate memory which could in turn
2140     //       trigger a collection.  Thus, thread_suspendAll, thread_scanAll,
2141     //       and thread_resumeAll must be callable before thread_init
2142     //       completes, with the assumption that no other GC memory has yet
2143     //       been allocated by the system, and thus there is no risk of losing
2144     //       data if the global thread list is empty.  The check of
2145     //       Thread.sm_tbeg below is done to ensure thread_init has completed,
2146     //       and therefore that calling Thread.getThis will not result in an
2147     //       error.  For the short time when Thread.sm_tbeg is null, there is
2148     //       no reason not to simply call the multithreaded code below, with
2149     //       the expectation that the foreach loop will never be entered.
2150     if ( !multiThreadedFlag && Thread.sm_tbeg )
2151     {
2152         if ( ++suspendDepth == 1 )
2153             suspend( Thread.getThis() );
2154 
2155         return;
2156     }
2157 
2158     thread_preStopTheWorld();
2159     {
2160         if ( ++suspendDepth > 1 )
2161             return;
2162 
2163         Thread.criticalRegionLock.lock_nothrow();
2164         scope (exit) Thread.criticalRegionLock.unlock_nothrow();
2165         size_t cnt;
2166         bool suspendedSelf;
2167         Thread t = ThreadBase.sm_tbeg.toThread;
2168         while (t)
2169         {
2170             auto tn = t.next.toThread;
2171             if (suspend(t))
2172             {
2173                 if (t is ThreadBase.getThis())
2174                     suspendedSelf = true;
2175                 ++cnt;
2176             }
2177             t = tn;
2178         }
2179 
2180         version (Darwin)
2181         {}
2182         else version (Posix)
2183         {
2184             // Subtract own thread if we called suspend() on ourselves.
2185             // For example, suspendedSelf would be false if the current
2186             // thread ran thread_detachThis().
2187             assert(cnt >= 1);
2188             if (suspendedSelf)
2189                 --cnt;
2190             // wait for semaphore notifications
2191             for (; cnt; --cnt)
2192             {
2193                 while (sem_wait(&suspendCount) != 0)
2194                 {
2195                     if (errno != EINTR)
2196                         onThreadError("Unable to wait for semaphore");
2197                     errno = 0;
2198                 }
2199             }
2200         }
2201     }
2202 }
2203 
2204 /**
2205  * Resume the specified thread and unload stack and register information.
2206  * If the supplied thread is the calling thread, stack and register
2207  * information will be unloaded but the thread will not be resumed.  If
2208  * the resume operation fails and the thread is not running then it will
2209  * be removed from the global thread list, otherwise an exception will be
2210  * thrown.
2211  *
2212  * Params:
2213  *  t = The thread to resume.
2214  *
2215  * Throws:
2216  *  ThreadError if the resume fails for a running thread.
2217  */
2218 private extern (D) void resume(ThreadBase _t) nothrow @nogc
2219 {
2220     Thread t = _t.toThread;
2221 
2222     version (Windows)
2223     {
2224         if ( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF )
2225         {
2226             if ( !t.isRunning )
2227             {
2228                 Thread.remove( t );
2229                 return;
2230             }
2231             onThreadError( "Unable to resume thread" );
2232         }
2233 
2234         if ( !t.m_lock )
2235             t.m_curr.tstack = t.m_curr.bstack;
2236         t.m_reg[0 .. $] = 0;
2237     }
2238     else version (Darwin)
2239     {
2240         if ( t.m_addr != pthread_self() && thread_resume( t.m_tmach ) != KERN_SUCCESS )
2241         {
2242             if ( !t.isRunning )
2243             {
2244                 Thread.remove( t );
2245                 return;
2246             }
2247             onThreadError( "Unable to resume thread" );
2248         }
2249 
2250         if ( !t.m_lock )
2251             t.m_curr.tstack = t.m_curr.bstack;
2252         t.m_reg[0 .. $] = 0;
2253     }
2254     else version (Posix)
2255     {
2256         if ( t.m_addr != pthread_self() )
2257         {
2258             if ( pthread_kill( t.m_addr, resumeSignalNumber ) != 0 )
2259             {
2260                 if ( !t.isRunning )
2261                 {
2262                     Thread.remove( t );
2263                     return;
2264                 }
2265                 onThreadError( "Unable to resume thread" );
2266             }
2267         }
2268         else if ( !t.m_lock )
2269         {
2270             t.m_curr.tstack = t.m_curr.bstack;
2271         }
2272     }
2273 }
2274 
2275 
2276 /**
2277  * Initializes the thread module.  This function must be called by the
2278  * garbage collector on startup and before any other thread routines
2279  * are called.
2280  */
2281 extern (C) void thread_init() @nogc nothrow @system
2282 {
2283     // NOTE: If thread_init itself performs any allocations then the thread
2284     //       routines reserved for garbage collector use may be called while
2285     //       thread_init is being processed.  However, since no memory should
2286     //       exist to be scanned at this point, it is sufficient for these
2287     //       functions to detect the condition and return immediately.
2288 
2289     initLowlevelThreads();
2290     Thread.initLocks();
2291 
2292     version (Darwin)
2293     {
2294         // thread id different in forked child process
2295         static extern(C) void initChildAfterFork()
2296         {
2297             auto thisThread = Thread.getThis();
2298             thisThread.m_addr = pthread_self();
2299             assert( thisThread.m_addr != thisThread.m_addr.init );
2300             thisThread.m_tmach = pthread_mach_thread_np( thisThread.m_addr );
2301             assert( thisThread.m_tmach != thisThread.m_tmach.init );
2302        }
2303         pthread_atfork(null, null, &initChildAfterFork);
2304     }
2305     else version (Posix)
2306     {
2307         version (OpenBSD)
2308         {
2309             // OpenBSD does not support SIGRTMIN or SIGRTMAX
2310             // Use SIGUSR1 for SIGRTMIN, SIGUSR2 for SIGRTMIN + 1
2311             // And use 32 for SIGRTMAX (32 is the max signal number on OpenBSD)
2312             enum SIGRTMIN = SIGUSR1;
2313             enum SIGRTMAX = 32;
2314         }
2315 
2316         if ( suspendSignalNumber == 0 )
2317         {
2318             suspendSignalNumber = SIGRTMIN;
2319         }
2320 
2321         if ( resumeSignalNumber == 0 )
2322         {
2323             resumeSignalNumber = SIGRTMIN + 1;
2324             assert(resumeSignalNumber <= SIGRTMAX);
2325         }
2326         int         status;
2327         sigaction_t suspend = void;
2328         sigaction_t resume = void;
2329 
2330         // This is a quick way to zero-initialize the structs without using
2331         // memset or creating a link dependency on their static initializer.
2332         (cast(byte*) &suspend)[0 .. sigaction_t.sizeof] = 0;
2333         (cast(byte*)  &resume)[0 .. sigaction_t.sizeof] = 0;
2334 
2335         // NOTE: SA_RESTART indicates that system calls should restart if they
2336         //       are interrupted by a signal, but this is not available on all
2337         //       Posix systems, even those that support multithreading.
2338         static if ( __traits( compiles, SA_RESTART ) )
2339             suspend.sa_flags = SA_RESTART;
2340 
2341         suspend.sa_handler = &thread_suspendHandler;
2342         // NOTE: We want to ignore all signals while in this handler, so fill
2343         //       sa_mask to indicate this.
2344         status = sigfillset( &suspend.sa_mask );
2345         assert( status == 0 );
2346 
2347         // NOTE: Since resumeSignalNumber should only be issued for threads within the
2348         //       suspend handler, we don't want this signal to trigger a
2349         //       restart.
2350         resume.sa_flags   = 0;
2351         resume.sa_handler = &thread_resumeHandler;
2352         // NOTE: We want to ignore all signals while in this handler, so fill
2353         //       sa_mask to indicate this.
2354         status = sigfillset( &resume.sa_mask );
2355         assert( status == 0 );
2356 
2357         status = sigaction( suspendSignalNumber, &suspend, null );
2358         assert( status == 0 );
2359 
2360         status = sigaction( resumeSignalNumber, &resume, null );
2361         assert( status == 0 );
2362 
2363         status = sem_init( &suspendCount, 0, 0 );
2364         assert( status == 0 );
2365     }
2366     _mainThreadStore[] = __traits(initSymbol, Thread)[];
2367     Thread.sm_main = attachThread((cast(Thread)_mainThreadStore.ptr).__ctor());
2368 }
2369 
2370 private alias MainThreadStore = void[__traits(classInstanceSize, Thread)];
2371 package __gshared align(__traits(classInstanceAlignment, Thread)) MainThreadStore _mainThreadStore;
2372 
2373 /**
2374  * Terminates the thread module. No other thread routine may be called
2375  * afterwards.
2376  */
2377 extern (C) void thread_term() @nogc nothrow
2378 {
2379     thread_term_tpl!(Thread)(_mainThreadStore);
2380 }
2381 
2382 
2383 ///////////////////////////////////////////////////////////////////////////////
2384 // Thread Entry Point and Signal Handlers
2385 ///////////////////////////////////////////////////////////////////////////////
2386 
2387 
2388 version (Windows)
2389 {
2390     private
2391     {
2392         //
2393         // Entry point for Windows threads
2394         //
2395         extern (Windows) uint thread_entryPoint( void* arg ) nothrow @system
2396         {
2397             version (Shared)
2398             {
2399                 Thread obj = cast(Thread)(cast(void**)arg)[0];
2400                 auto loadedLibraries = (cast(void**)arg)[1];
2401                 .free(arg);
2402             }
2403             else
2404             {
2405                 Thread obj = cast(Thread)arg;
2406             }
2407             assert( obj );
2408 
2409             // loadedLibraries need to be inherited from parent thread
2410             // before initilizing GC for TLS (rt_tlsgc_init)
2411             version (Shared)
2412             {
2413                 externDFunc!("rt.sections_elf_shared.inheritLoadedLibraries",
2414                              void function(void*) @nogc nothrow)(loadedLibraries);
2415             }
2416 
2417             obj.initDataStorage();
2418 
2419             Thread.setThis(obj);
2420             Thread.add(obj);
2421             scope (exit)
2422             {
2423                 Thread.remove(obj);
2424                 obj.destroyDataStorage();
2425             }
2426             Thread.add(&obj.m_main);
2427 
2428             // NOTE: No GC allocations may occur until the stack pointers have
2429             //       been set and Thread.getThis returns a valid reference to
2430             //       this thread object (this latter condition is not strictly
2431             //       necessary on Windows but it should be followed for the
2432             //       sake of consistency).
2433 
2434             // TODO: Consider putting an auto exception object here (using
2435             //       alloca) forOutOfMemoryError plus something to track
2436             //       whether an exception is in-flight?
2437 
2438             void append( Throwable t )
2439             {
2440                 obj.m_unhandled = Throwable.chainTogether(obj.m_unhandled, t);
2441             }
2442 
2443             version (D_InlineAsm_X86)
2444             {
2445                 asm nothrow @nogc { fninit; }
2446             }
2447 
2448             try
2449             {
2450                 rt_moduleTlsCtor();
2451                 try
2452                 {
2453                     obj.run();
2454                 }
2455                 catch ( Throwable t )
2456                 {
2457                     append( t );
2458                 }
2459                 rt_moduleTlsDtor();
2460                 version (Shared)
2461                 {
2462                     externDFunc!("rt.sections_elf_shared.cleanupLoadedLibraries",
2463                                  void function() @nogc nothrow)();
2464                 }
2465             }
2466             catch ( Throwable t )
2467             {
2468                 append( t );
2469             }
2470             return 0;
2471         }
2472 
2473 
2474         HANDLE GetCurrentThreadHandle() nothrow @nogc
2475         {
2476             const uint DUPLICATE_SAME_ACCESS = 0x00000002;
2477 
2478             HANDLE curr = GetCurrentThread(),
2479                    proc = GetCurrentProcess(),
2480                    hndl;
2481 
2482             DuplicateHandle( proc, curr, proc, &hndl, 0, TRUE, DUPLICATE_SAME_ACCESS );
2483             return hndl;
2484         }
2485     }
2486 }
2487 else version (Posix)
2488 {
2489     private
2490     {
2491         import core.stdc.errno;
2492         import core.sys.posix.semaphore;
2493         import core.sys.posix.stdlib; // for malloc, valloc, free, atexit
2494         import core.sys.posix.pthread;
2495         import core.sys.posix.signal;
2496         import core.sys.posix.time;
2497 
2498         version (Darwin)
2499         {
2500             import core.sys.darwin.mach.thread_act;
2501             import core.sys.darwin.pthread : pthread_mach_thread_np;
2502         }
2503 
2504         //
2505         // Entry point for POSIX threads
2506         //
2507         extern (C) void* thread_entryPoint( void* arg ) nothrow @system
2508         {
2509             version (Shared)
2510             {
2511                 Thread obj = cast(Thread)(cast(void**)arg)[0];
2512                 auto loadedLibraries = (cast(void**)arg)[1];
2513                 .free(arg);
2514             }
2515             else
2516             {
2517                 Thread obj = cast(Thread)arg;
2518             }
2519             assert( obj );
2520 
2521             // loadedLibraries need to be inherited from parent thread
2522             // before initilizing GC for TLS (rt_tlsgc_init)
2523             version (Shared)
2524             {
2525                 externDFunc!("rt.sections_elf_shared.inheritLoadedLibraries",
2526                              void function(void*) @nogc nothrow)(loadedLibraries);
2527             }
2528 
2529             obj.initDataStorage();
2530 
2531             atomicStore!(MemoryOrder.raw)(obj.m_isRunning, true);
2532             Thread.setThis(obj); // allocates lazy TLS (see Issue 11981)
2533             Thread.add(obj);     // can only receive signals from here on
2534             scope (exit)
2535             {
2536                 Thread.remove(obj);
2537                 atomicStore!(MemoryOrder.raw)(obj.m_isRunning, false);
2538                 obj.destroyDataStorage();
2539             }
2540             Thread.add(&obj.m_main);
2541 
2542             static extern (C) void thread_cleanupHandler( void* arg ) nothrow @nogc
2543             {
2544                 Thread  obj = cast(Thread) arg;
2545                 assert( obj );
2546 
2547                 // NOTE: If the thread terminated abnormally, just set it as
2548                 //       not running and let thread_suspendAll remove it from
2549                 //       the thread list.  This is safer and is consistent
2550                 //       with the Windows thread code.
2551                 atomicStore!(MemoryOrder.raw)(obj.m_isRunning,false);
2552             }
2553 
2554             // NOTE: Using void to skip the initialization here relies on
2555             //       knowledge of how pthread_cleanup is implemented.  It may
2556             //       not be appropriate for all platforms.  However, it does
2557             //       avoid the need to link the pthread module.  If any
2558             //       implementation actually requires default initialization
2559             //       then pthread_cleanup should be restructured to maintain
2560             //       the current lack of a link dependency.
2561             static if ( __traits( compiles, pthread_cleanup ) )
2562             {
2563                 pthread_cleanup cleanup = void;
2564                 cleanup.push( &thread_cleanupHandler, cast(void*) obj );
2565             }
2566             else static if ( __traits( compiles, pthread_cleanup_push ) )
2567             {
2568                 pthread_cleanup_push( &thread_cleanupHandler, cast(void*) obj );
2569             }
2570             else
2571             {
2572                 static assert( false, "Platform not supported." );
2573             }
2574 
2575             // NOTE: No GC allocations may occur until the stack pointers have
2576             //       been set and Thread.getThis returns a valid reference to
2577             //       this thread object (this latter condition is not strictly
2578             //       necessary on Windows but it should be followed for the
2579             //       sake of consistency).
2580 
2581             // TODO: Consider putting an auto exception object here (using
2582             //       alloca) forOutOfMemoryError plus something to track
2583             //       whether an exception is in-flight?
2584 
2585             void append( Throwable t )
2586             {
2587                 obj.m_unhandled = Throwable.chainTogether(obj.m_unhandled, t);
2588             }
2589             try
2590             {
2591                 rt_moduleTlsCtor();
2592                 try
2593                 {
2594                     obj.run();
2595                 }
2596                 catch ( Throwable t )
2597                 {
2598                     append( t );
2599                 }
2600                 rt_moduleTlsDtor();
2601                 version (Shared)
2602                 {
2603                     externDFunc!("rt.sections_elf_shared.cleanupLoadedLibraries",
2604                                  void function() @nogc nothrow)();
2605                 }
2606             }
2607             catch ( Throwable t )
2608             {
2609                 append( t );
2610             }
2611 
2612             // NOTE: Normal cleanup is handled by scope(exit).
2613 
2614             static if ( __traits( compiles, pthread_cleanup ) )
2615             {
2616                 cleanup.pop( 0 );
2617             }
2618             else static if ( __traits( compiles, pthread_cleanup_push ) )
2619             {
2620                 pthread_cleanup_pop( 0 );
2621             }
2622 
2623             return null;
2624         }
2625 
2626 
2627         //
2628         // Used to track the number of suspended threads
2629         //
2630         __gshared sem_t suspendCount;
2631 
2632 
2633         extern (C) void thread_preSuspend( void* sp ) nothrow {
2634             // NOTE: Since registers are being pushed and popped from the
2635             //       stack, any other stack data used by this function should
2636             //       be gone before the stack cleanup code is called below.
2637             Thread obj = Thread.getThis();
2638             assert(obj !is null);
2639 
2640             if ( !obj.m_lock )
2641             {
2642                 obj.m_curr.tstack = sp;
2643             }
2644         }
2645 
2646         extern (C) void thread_postSuspend() nothrow {
2647             Thread obj = Thread.getThis();
2648             assert(obj !is null);
2649 
2650             if ( !obj.m_lock )
2651             {
2652                 obj.m_curr.tstack = obj.m_curr.bstack;
2653             }
2654         }
2655 
2656         extern (C) void thread_suspendHandler( int sig ) nothrow
2657         in
2658         {
2659             assert( sig == suspendSignalNumber );
2660         }
2661         do
2662         {
2663             void op(void* sp) nothrow
2664             {
2665                 thread_preSuspend(getStackTop());
2666                 scope(exit) thread_postSuspend();
2667 
2668                 sigset_t    sigres = void;
2669                 int         status;
2670 
2671                 status = sigfillset( &sigres );
2672                 assert( status == 0 );
2673 
2674                 status = sigdelset( &sigres, resumeSignalNumber );
2675                 assert( status == 0 );
2676 
2677                 status = sem_post( &suspendCount );
2678                 assert( status == 0 );
2679 
2680                 sigsuspend( &sigres );
2681             }
2682             callWithStackShell(&op);
2683         }
2684 
2685 
2686         extern (C) void thread_resumeHandler( int sig ) nothrow
2687         in
2688         {
2689             assert( sig == resumeSignalNumber );
2690         }
2691         do
2692         {
2693 
2694         }
2695     }
2696 }
2697 else version (FreeStanding)
2698 {
2699 
2700 }
2701 else
2702 {
2703     // NOTE: This is the only place threading versions are checked.  If a new
2704     //       version is added, the module code will need to be searched for
2705     //       places where version-specific code may be required.  This can be
2706     //       easily accomlished by searching for 'Windows' or 'Posix'.
2707     static assert( false, "Unknown threading implementation." );
2708 }
2709 
2710 //
2711 // exposed by compiler runtime
2712 //
2713 extern (C) void  rt_moduleTlsCtor();
2714 extern (C) void  rt_moduleTlsDtor();
2715 
2716 
2717 // regression test for Issue 13416
2718 version (FreeBSD) unittest
2719 {
2720     static void loop()
2721     {
2722         pthread_attr_t attr;
2723         pthread_attr_init(&attr);
2724         auto thr = pthread_self();
2725         foreach (i; 0 .. 50)
2726             pthread_attr_get_np(thr, &attr);
2727         pthread_attr_destroy(&attr);
2728     }
2729 
2730     auto thr = new Thread(&loop).start();
2731     foreach (i; 0 .. 50)
2732     {
2733         thread_suspendAll();
2734         thread_resumeAll();
2735     }
2736     thr.join();
2737 }
2738 
2739 version (DragonFlyBSD) unittest
2740 {
2741     static void loop()
2742     {
2743         pthread_attr_t attr;
2744         pthread_attr_init(&attr);
2745         auto thr = pthread_self();
2746         foreach (i; 0 .. 50)
2747             pthread_attr_get_np(thr, &attr);
2748         pthread_attr_destroy(&attr);
2749     }
2750 
2751     auto thr = new Thread(&loop).start();
2752     foreach (i; 0 .. 50)
2753     {
2754         thread_suspendAll();
2755         thread_resumeAll();
2756     }
2757     thr.join();
2758 }
2759 
2760 
2761 ///////////////////////////////////////////////////////////////////////////////
2762 // lowlovel threading support
2763 ///////////////////////////////////////////////////////////////////////////////
2764 
2765 private
2766 {
2767     version (Windows):
2768     // If the runtime is dynamically loaded as a DLL, there is a problem with
2769     // threads still running when the DLL is supposed to be unloaded:
2770     //
2771     // - with the VC runtime starting with VS2015 (i.e. using the Universal CRT)
2772     //   a thread created with _beginthreadex increments the DLL reference count
2773     //   and decrements it when done, so that the DLL is no longer unloaded unless
2774     //   all the threads have terminated. With the DLL reference count held up
2775     //   by a thread that is only stopped by a signal from a static destructor or
2776     //   the termination of the runtime will cause the DLL to never be unloaded.
2777     //
2778     // - with the DigitalMars runtime and VC runtime up to VS2013, the thread
2779     //   continues to run, but crashes once the DLL is unloaded from memory as
2780     //   the code memory is no longer accessible. Stopping the threads is not possible
2781     //   from within the runtime termination as it is invoked from
2782     //   DllMain(DLL_PROCESS_DETACH) holding a lock that prevents threads from
2783     //   terminating.
2784     //
2785     // Solution: start a watchdog thread that keeps the DLL reference count above 0 and
2786     // checks it periodically. If it is equal to 1 (plus the number of started threads), no
2787     // external references to the DLL exist anymore, threads can be stopped
2788     // and runtime termination and DLL unload can be invoked via FreeLibraryAndExitThread.
2789     // Note: runtime termination is then performed by a different thread than at startup.
2790     //
2791     // Note: if the DLL is never unloaded, process termination kills all threads
2792     // and signals their handles before unconditionally calling DllMain(DLL_PROCESS_DETACH).
2793 
2794     import core.sys.windows.winbase : FreeLibraryAndExitThread, GetModuleHandleExW,
2795         GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
2796     import core.sys.windows.windef : HMODULE;
2797     import core.sys.windows.dll : dll_getRefCount;
2798 
2799     version (CRuntime_Microsoft)
2800         extern(C) extern __gshared ubyte msvcUsesUCRT; // from rt/msvc.d
2801 
2802     /// set during termination of a DLL on Windows, i.e. while executing DllMain(DLL_PROCESS_DETACH)
2803     public __gshared bool thread_DLLProcessDetaching;
2804 
2805     __gshared HMODULE ll_dllModule;
2806     __gshared ThreadID ll_dllMonitorThread;
2807 
2808     int ll_countLowLevelThreadsWithDLLUnloadCallback() nothrow @system
2809     {
2810         lowlevelLock.lock_nothrow();
2811         scope(exit) lowlevelLock.unlock_nothrow();
2812 
2813         int cnt = 0;
2814         foreach (i; 0 .. ll_nThreads)
2815             if (ll_pThreads[i].cbDllUnload)
2816                 cnt++;
2817         return cnt;
2818     }
2819 
2820     bool ll_dllHasExternalReferences() nothrow
2821     {
2822         version (CRuntime_DigitalMars)
2823             enum internalReferences = 1; // only the watchdog thread
2824         else
2825             int internalReferences =  msvcUsesUCRT ? 1 + ll_countLowLevelThreadsWithDLLUnloadCallback() : 1;
2826 
2827         int refcnt = dll_getRefCount(ll_dllModule);
2828         return refcnt > internalReferences;
2829     }
2830 
2831     private void monitorDLLRefCnt() nothrow @system
2832     {
2833         // this thread keeps the DLL alive until all external references are gone
2834         while (ll_dllHasExternalReferences())
2835         {
2836             Thread.sleep(100.msecs);
2837         }
2838 
2839         // the current thread will be terminated below
2840         ll_removeThread(GetCurrentThreadId());
2841 
2842         for (;;)
2843         {
2844             ThreadID tid;
2845             void delegate() nothrow cbDllUnload;
2846             {
2847                 lowlevelLock.lock_nothrow();
2848                 scope(exit) lowlevelLock.unlock_nothrow();
2849 
2850                 foreach (i; 0 .. ll_nThreads)
2851                     if (ll_pThreads[i].cbDllUnload)
2852                     {
2853                         cbDllUnload = ll_pThreads[i].cbDllUnload;
2854                         tid = ll_pThreads[0].tid;
2855                     }
2856             }
2857             if (!cbDllUnload)
2858                 break;
2859             cbDllUnload();
2860             assert(!findLowLevelThread(tid));
2861         }
2862 
2863         FreeLibraryAndExitThread(ll_dllModule, 0);
2864     }
2865 
2866     int ll_getDLLRefCount() nothrow @nogc
2867     {
2868         if (!ll_dllModule &&
2869             !GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
2870                                 cast(const(wchar)*) &ll_getDLLRefCount, &ll_dllModule))
2871             return -1;
2872         return dll_getRefCount(ll_dllModule);
2873     }
2874 
2875     bool ll_startDLLUnloadThread() nothrow @nogc
2876     {
2877         int refcnt = ll_getDLLRefCount();
2878         if (refcnt < 0)
2879             return false; // not a dynamically loaded DLL
2880 
2881         if (ll_dllMonitorThread !is ThreadID.init)
2882             return true;
2883 
2884         // if a thread is created from a DLL, the MS runtime (starting with VC2015) increments the DLL reference count
2885         // to avoid the DLL being unloaded while the thread is still running. Mimick this behavior here for all
2886         // runtimes not doing this
2887         version (CRuntime_DigitalMars)
2888             enum needRef = true;
2889         else
2890             bool needRef = !msvcUsesUCRT;
2891 
2892         if (needRef)
2893         {
2894             HMODULE hmod;
2895             GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, cast(const(wchar)*) &ll_getDLLRefCount, &hmod);
2896         }
2897 
2898         ll_dllMonitorThread = createLowLevelThread(() { monitorDLLRefCnt(); });
2899         return ll_dllMonitorThread != ThreadID.init;
2900     }
2901 }
2902 
2903 /**
2904  * Create a thread not under control of the runtime, i.e. TLS module constructors are
2905  * not run and the GC does not suspend it during a collection.
2906  *
2907  * Params:
2908  *  dg        = delegate to execute in the created thread.
2909  *  stacksize = size of the stack of the created thread. The default of 0 will select the
2910  *              platform-specific default size.
2911  *  cbDllUnload = Windows only: if running in a dynamically loaded DLL, this delegate will be called
2912  *              if the DLL is supposed to be unloaded, but the thread is still running.
2913  *              The thread must be terminated via `joinLowLevelThread` by the callback.
2914  *
2915  * Returns: the platform specific thread ID of the new thread. If an error occurs, `ThreadID.init`
2916  *  is returned.
2917  */
2918 ThreadID createLowLevelThread(void delegate() nothrow dg, uint stacksize = 0,
2919                               void delegate() nothrow cbDllUnload = null) nothrow @nogc @system
2920 {
2921     void delegate() nothrow* context = cast(void delegate() nothrow*)malloc(dg.sizeof);
2922     *context = dg;
2923 
2924     ThreadID tid;
2925     version (Windows)
2926     {
2927         // the thread won't start until after the DLL is unloaded
2928         if (thread_DLLProcessDetaching)
2929             return ThreadID.init;
2930 
2931         static extern (Windows) uint thread_lowlevelEntry(void* ctx) nothrow
2932         {
2933             auto dg = *cast(void delegate() nothrow*)ctx;
2934             free(ctx);
2935 
2936             dg();
2937             ll_removeThread(GetCurrentThreadId());
2938             return 0;
2939         }
2940 
2941         // see Thread.start() for why thread is created in suspended state
2942         HANDLE hThread = cast(HANDLE) _beginthreadex(null, stacksize, &thread_lowlevelEntry,
2943                                                      context, CREATE_SUSPENDED, &tid);
2944         if (!hThread)
2945             return ThreadID.init;
2946     }
2947 
2948     lowlevelLock.lock_nothrow();
2949     scope(exit) lowlevelLock.unlock_nothrow();
2950 
2951     ll_nThreads++;
2952     ll_pThreads = cast(ll_ThreadData*)realloc(ll_pThreads, ll_ThreadData.sizeof * ll_nThreads);
2953 
2954     version (Windows)
2955     {
2956         ll_pThreads[ll_nThreads - 1].tid = tid;
2957         ll_pThreads[ll_nThreads - 1].cbDllUnload = cbDllUnload;
2958         if (ResumeThread(hThread) == -1)
2959             onThreadError("Error resuming thread");
2960         CloseHandle(hThread);
2961 
2962         if (cbDllUnload)
2963             ll_startDLLUnloadThread();
2964     }
2965     else version (Posix)
2966     {
2967         static extern (C) void* thread_lowlevelEntry(void* ctx) nothrow
2968         {
2969             auto dg = *cast(void delegate() nothrow*)ctx;
2970             free(ctx);
2971 
2972             dg();
2973             ll_removeThread(pthread_self());
2974             return null;
2975         }
2976 
2977         size_t stksz = adjustStackSize(stacksize);
2978 
2979         pthread_attr_t  attr;
2980 
2981         int rc;
2982         if ((rc = pthread_attr_init(&attr)) != 0)
2983             return ThreadID.init;
2984         if (stksz && (rc = pthread_attr_setstacksize(&attr, stksz)) != 0)
2985             return ThreadID.init;
2986         if ((rc = pthread_create(&tid, &attr, &thread_lowlevelEntry, context)) != 0)
2987             return ThreadID.init;
2988         if ((rc = pthread_attr_destroy(&attr)) != 0)
2989             return ThreadID.init;
2990 
2991         ll_pThreads[ll_nThreads - 1].tid = tid;
2992     }
2993     return tid;
2994 }
2995 
2996 /**
2997  * Wait for a thread created with `createLowLevelThread` to terminate.
2998  *
2999  * Note: In a Windows DLL, if this function is called via DllMain with
3000  *       argument DLL_PROCESS_DETACH, the thread is terminated forcefully
3001  *       without proper cleanup as a deadlock would happen otherwise.
3002  *
3003  * Params:
3004  *  tid = the thread ID returned by `createLowLevelThread`.
3005  */
3006 void joinLowLevelThread(ThreadID tid) nothrow @nogc
3007 {
3008     version (Windows)
3009     {
3010         HANDLE handle = OpenThreadHandle(tid);
3011         if (!handle)
3012             return;
3013 
3014         if (thread_DLLProcessDetaching)
3015         {
3016             // When being called from DllMain/DLL_DETACH_PROCESS, threads cannot stop
3017             //  due to the loader lock being held by the current thread.
3018             // On the other hand, the thread must not continue to run as it will crash
3019             //  if the DLL is unloaded. The best guess is to terminate it immediately.
3020             TerminateThread(handle, 1);
3021             WaitForSingleObject(handle, 10); // give it some time to terminate, but don't wait indefinitely
3022         }
3023         else
3024             WaitForSingleObject(handle, INFINITE);
3025         CloseHandle(handle);
3026     }
3027     else version (Posix)
3028     {
3029         if (pthread_join(tid, null) != 0)
3030             onThreadError("Unable to join thread");
3031     }
3032 }
3033 
3034 nothrow @nogc unittest
3035 {
3036     struct TaskWithContect
3037     {
3038         shared int n = 0;
3039         void run() nothrow
3040         {
3041             n.atomicOp!"+="(1);
3042         }
3043     }
3044     TaskWithContect task;
3045 
3046     ThreadID[8] tids;
3047     for (int i = 0; i < tids.length; i++)
3048     {
3049         tids[i] = createLowLevelThread(&task.run);
3050         assert(tids[i] != ThreadID.init);
3051     }
3052 
3053     for (int i = 0; i < tids.length; i++)
3054         joinLowLevelThread(tids[i]);
3055 
3056     assert(task.n == tids.length);
3057 }
3058 
3059 version (Posix)
3060 private size_t adjustStackSize(size_t sz) nothrow @nogc
3061 {
3062     if (sz == 0)
3063         return 0;
3064 
3065     // stack size must be at least PTHREAD_STACK_MIN for most platforms.
3066     if (PTHREAD_STACK_MIN > sz)
3067         sz = PTHREAD_STACK_MIN;
3068 
3069     version (CRuntime_Glibc)
3070     {
3071         // On glibc, TLS uses the top of the stack, so add its size to the requested size
3072         sz += externDFunc!("rt.sections_elf_shared.sizeOfTLS",
3073                            size_t function() @nogc nothrow)();
3074     }
3075 
3076     // stack size must be a multiple of pageSize
3077     sz = ((sz + pageSize - 1) & ~(pageSize - 1));
3078 
3079     return sz;
3080 }