Home | History | Annotate | Line # | Download | only in thread
      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 Rnne 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 
     45 version (D_InlineAsm_X86)
     46 {
     47     version (Windows)
     48         version = AsmX86_Windows;
     49     else version (Posix)
     50         version = AsmX86_Posix;
     51 }
     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 }
     63 else version (X86)
     64 {
     65     version (CET) {} else
     66     {
     67         version = AsmExternal;
     68     }
     69 }
     70 else version (X86_64)
     71 {
     72     version (CET)   {} else
     73     version (D_X32) {} else
     74     {
     75         version = AsmExternal;
     76     }
     77 }
     78 else version (PPC)
     79 {
     80     version (Posix)
     81     {
     82         version = AsmExternal;
     83     }
     84 }
     85 else version (MIPS_O32)
     86 {
     87     version (Posix)
     88     {
     89         version = AsmExternal;
     90     }
     91 }
     92 else version (AArch64)
     93 {
     94     version (Posix)
     95     {
     96         version = AsmExternal;
     97     }
     98 }
     99 else version (ARM)
    100 {
    101     version (Posix)
    102     {
    103         version = AsmExternal;
    104     }
    105 }
    106 
    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 
    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 }
    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 
    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 
    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 
    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 {
    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     //
    252     version (Windows)
    253     {
    254         private HANDLE          m_hndl;
    255     }
    256 
    257     version (Posix)
    258     {
    259         private shared bool     m_isRunning;
    260     }
    261 
    262     version (Darwin)
    263     {
    264         private mach_port_t     m_tmach;
    265     }
    266 
    267     version (Solaris)
    268     {
    269         private __gshared bool m_isRTClass;
    270     }
    271 
    272     //
    273     // Standard types
    274     //
    275     version (Windows)
    276     {
    277         alias TLSKey = uint;
    278     }
    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      */
    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      */
    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      */
    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     //
    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      */
    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 
    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     }
    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      */
    448     final Thread start() nothrow
    449     in
    450     {
    451         assert( !next && !prev );
    452     }
    453     do
    454     {
    455         auto wasThreaded  = multiThreadedFlag;
    456         multiThreadedFlag = true;
    457         scope( failure )
    458         {
    459             if ( !wasThreaded )
    460                 multiThreadedFlag = false;
    461         }
    462 
    463         version (Windows) {} else
    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 
    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;
    499             version (Windows)
    500             {
    501                 if ( ResumeThread( m_hndl ) == -1 )
    502                     onThreadError( "Error resuming thread" );
    503             }
    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             }
    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     {
    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         }
    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 
    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;
    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         */
    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          */
    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          */
    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          */
    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 
    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      */
    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      */
    828     final @property void priority( int val )
    829     in
    830     {
    831         assert(val >= PRIORITY_MIN);
    832         assert(val <= PRIORITY_MAX);
    833     }
    834     do
    835     {
    836         version (Windows)
    837         {
    838             if ( !SetThreadPriority( m_hndl, val ) )
    839                 throw new ThreadException( "Unable to set thread priority" );
    840         }
    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         }
    867         else version (NetBSD)
    868         {
    869            fakePriority = val;
    870         }
    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      */
    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      */
    981     static void sleep( Duration val ) @nogc nothrow
    982     in
    983     {
    984         assert( !val.isNegative );
    985     }
    986     do
    987     {
    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         }
   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      */
   1034     static void yield() @nogc nothrow
   1035     {
   1036         version (Windows)
   1037             SwitchToThread();
   1038         else version (Posix)
   1039             sched_yield();
   1040     }
   1041 }
   1042 
   1043 private Thread toThread(return scope ThreadBase t) @trusted nothrow @nogc pure
   1044 {
   1045     return cast(Thread) cast(void*) t;
   1046 }
   1047 
   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     {
   1058         this()
   1059         {
   1060             super(&run);
   1061         }
   1062 
   1063     private:
   1064         void run()
   1065         {
   1066             // Derived thread running.
   1067         }
   1068     }
   1069 
   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     }
   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({});
   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 
   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 }
   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 
   1282 version (Posix)
   1283 {
   1284     private __gshared int suspendSignalNumber = SIGUSR1;
   1285     private __gshared int resumeSignalNumber  = SIGUSR2;
   1286 }
   1287 
   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  */
   1337 extern(C) Thread thread_attachThis()
   1338 {
   1339     return thread_attachThis_tpl!Thread();
   1340 }
   1341 
   1342 
   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.
   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)
   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  */
   1597 version (Posix)
   1598 {
   1599     import core.sys.posix.unistd;
   1600 
   1601     alias getpid = core.sys.posix.unistd.getpid;
   1602 }
   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 
   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 
   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  */
   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  */
   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  */
   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  */
   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  */
   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 
   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 }
   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
   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 
   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 
   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 
   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 
   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 
   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 
   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  */
   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  */
   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;
   2822         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 
   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