The OpenD Programming Language

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