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