"Fossies" - the Fresh Open Source Software Archive

Member "dmd2/src/druntime/src/core/thread/osthread.d" (20 Nov 2020, 84906 Bytes) of package /linux/misc/dmd.2.094.2.linux.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) D source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

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