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