PageRenderTime 110ms CodeModel.GetById 44ms app.highlight 57ms RepoModel.GetById 0ms app.codeStats 1ms

/src/core/thread.d

http://github.com/AlexeyProkhin/druntime
D | 4697 lines | 2890 code | 567 blank | 1240 comment | 347 complexity | 672b56f280060a7ede3f5dea172df202 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/**
   2 * The thread module provides support for thread creation and management.
   3 *
   4 * Copyright: Copyright Sean Kelly 2005 - 2012.
   5 * License: Distributed under the
   6 *      $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
   7 *    (See accompanying file LICENSE)
   8 * Authors:   Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak
   9 * Source:    $(DRUNTIMESRC core/_thread.d)
  10 */
  11
  12module core.thread;
  13
  14
  15public import core.time; // for Duration
  16static import rt.tlsgc;
  17
  18// this should be true for most architectures
  19version = StackGrowsDown;
  20
  21/**
  22 * Returns the process ID of the calling process, which is guaranteed to be
  23 * unique on the system. This call is always successful.
  24 *
  25 * Example:
  26 * ---
  27 * writefln("Current process id: %s", getpid());
  28 * ---
  29 */
  30version(Posix)
  31{
  32    alias core.sys.posix.unistd.getpid getpid;
  33}
  34else version (Windows)
  35{
  36    alias core.sys.windows.windows.GetCurrentProcessId getpid;
  37}
  38
  39
  40///////////////////////////////////////////////////////////////////////////////
  41// Thread and Fiber Exceptions
  42///////////////////////////////////////////////////////////////////////////////
  43
  44
  45/**
  46 * Base class for thread exceptions.
  47 */
  48class ThreadException : Exception
  49{
  50    this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
  51    {
  52        super(msg, file, line, next);
  53    }
  54
  55    this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__)
  56    {
  57        super(msg, file, line, next);
  58    }
  59}
  60
  61
  62/**
  63 * Base class for fiber exceptions.
  64 */
  65class FiberException : Exception
  66{
  67    this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
  68    {
  69        super(msg, file, line, next);
  70    }
  71
  72    this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__)
  73    {
  74        super(msg, file, line, next);
  75    }
  76}
  77
  78
  79private
  80{
  81    import core.sync.mutex;
  82    import core.atomic;
  83
  84    //
  85    // from core.memory
  86    //
  87    extern (C) void  gc_enable();
  88    extern (C) void  gc_disable();
  89    extern (C) void* gc_malloc(size_t sz, uint ba = 0);
  90
  91    //
  92    // from core.stdc.string
  93    //
  94    extern (C) void* memcpy(void*, const void*, size_t);
  95
  96    //
  97    // exposed by compiler runtime
  98    //
  99    extern (C) void  rt_moduleTlsCtor();
 100    extern (C) void  rt_moduleTlsDtor();
 101
 102    alias void delegate() gc_atom;
 103    extern (C) void function(scope gc_atom) gc_atomic;
 104}
 105
 106
 107///////////////////////////////////////////////////////////////////////////////
 108// Thread Entry Point and Signal Handlers
 109///////////////////////////////////////////////////////////////////////////////
 110
 111
 112version( Windows )
 113{
 114    private
 115    {
 116        import core.stdc.stdint : uintptr_t; // for _beginthreadex decl below
 117        import core.stdc.stdlib;             // for malloc, atexit
 118        import core.sys.windows.windows;
 119        import core.sys.windows.threadaux;   // for OpenThreadHandle
 120
 121        const DWORD TLS_OUT_OF_INDEXES  = 0xFFFFFFFF;
 122        const CREATE_SUSPENDED = 0x00000004;
 123
 124        extern (Windows) alias uint function(void*) btex_fptr;
 125        extern (C) uintptr_t _beginthreadex(void*, uint, btex_fptr, void*, uint, uint*);
 126
 127        version( DigitalMars )
 128        {
 129            version (Win32)
 130            {
 131                // NOTE: The memory between the addresses of _tlsstart and _tlsend
 132                //       is the storage for thread-local data in D 2.0.  Both of
 133                //       these are defined in dm\src\win32\tlsseg.asm by DMC.
 134                extern (C)
 135                {
 136                    extern int _tlsstart;
 137                    extern int _tlsend;
 138                }
 139            }
 140            version (Win64)
 141            {
 142                // NOTE: The memory between the addresses of _tls_start and _tls_end
 143                //       is the storage for thread-local data in D 2.0.  Both of
 144                //       these are defined in LIBCMT:tlssub.obj
 145                extern (C)
 146                {
 147                    extern int _tls_start;
 148                    extern int _tls_end;
 149                }
 150                alias _tls_start _tlsstart;
 151                alias _tls_end   _tlsend;
 152            }
 153        }
 154        else version (MinGW)
 155        {
 156            extern (C)
 157            {
 158                extern int _tls_start;
 159                extern int _tls_end;
 160            }
 161            alias _tls_start _tlsstart;
 162            alias _tls_end   _tlsend;
 163        }
 164        else
 165        {
 166            __gshared int   _tlsstart;
 167            alias _tlsstart _tlsend;
 168        }
 169
 170
 171        //
 172        // Entry point for Windows threads
 173        //
 174        extern (Windows) uint thread_entryPoint( void* arg )
 175        {
 176            Thread  obj = cast(Thread) arg;
 177            assert( obj );
 178
 179            assert( obj.m_curr is &obj.m_main );
 180            obj.m_main.bstack = getStackBottom();
 181            obj.m_main.tstack = obj.m_main.bstack;
 182
 183            void* pstart = cast(void*) &_tlsstart;
 184            void* pend   = cast(void*) &_tlsend;
 185            obj.m_tls = pstart[0 .. pend - pstart];
 186
 187            Thread.setThis( obj );
 188            //Thread.add( obj );
 189            scope( exit )
 190            {
 191                Thread.remove( obj );
 192            }
 193            Thread.add( &obj.m_main );
 194            obj.m_tlsgcdata = rt.tlsgc.init();
 195
 196            // NOTE: No GC allocations may occur until the stack pointers have
 197            //       been set and Thread.getThis returns a valid reference to
 198            //       this thread object (this latter condition is not strictly
 199            //       necessary on Windows but it should be followed for the
 200            //       sake of consistency).
 201
 202            // TODO: Consider putting an auto exception object here (using
 203            //       alloca) forOutOfMemoryError plus something to track
 204            //       whether an exception is in-flight?
 205
 206            void append( Throwable t )
 207            {
 208                if( obj.m_unhandled is null )
 209                    obj.m_unhandled = t;
 210                else
 211                {
 212                    Throwable last = obj.m_unhandled;
 213                    while( last.next !is null )
 214                        last = last.next;
 215                    last.next = t;
 216                }
 217            }
 218
 219            version( D_InlineAsm_X86 )
 220            {
 221                asm { fninit; }
 222            }
 223
 224            try
 225            {
 226                rt_moduleTlsCtor();
 227                try
 228                {
 229                    obj.run();
 230                }
 231                catch( Throwable t )
 232                {
 233                    append( t );
 234                }
 235                rt_moduleTlsDtor();
 236            }
 237            catch( Throwable t )
 238            {
 239                append( t );
 240            }
 241            return 0;
 242        }
 243
 244
 245        HANDLE GetCurrentThreadHandle()
 246        {
 247            const uint DUPLICATE_SAME_ACCESS = 0x00000002;
 248
 249            HANDLE curr = GetCurrentThread(),
 250                   proc = GetCurrentProcess(),
 251                   hndl;
 252
 253            DuplicateHandle( proc, curr, proc, &hndl, 0, TRUE, DUPLICATE_SAME_ACCESS );
 254            return hndl;
 255        }
 256    }
 257}
 258else version( Posix )
 259{
 260    private
 261    {
 262        import core.stdc.errno;
 263        import core.sys.posix.semaphore;
 264        import core.sys.posix.stdlib; // for malloc, valloc, free, atexit
 265        import core.sys.posix.pthread;
 266        import core.sys.posix.signal;
 267        import core.sys.posix.time;
 268
 269        version( OSX )
 270        {
 271            import core.sys.osx.mach.thread_act;
 272            extern (C) mach_port_t pthread_mach_thread_np(pthread_t);
 273        }
 274
 275        version( GNU )
 276        {
 277            import gcc.builtins;
 278        }
 279
 280        version( DigitalMars )
 281        {
 282            version( linux )
 283            {
 284                extern (C)
 285                {
 286                    extern int _tlsstart;
 287                    extern int _tlsend;
 288                }
 289            }
 290            else version( OSX )
 291            {
 292                extern (C)
 293                {
 294                    __gshared void[][2] _tls_data_array;
 295                }
 296            }
 297            else version( FreeBSD )
 298            {
 299                extern (C)
 300                {
 301                    extern void* _tlsstart;
 302                    extern void* _tlsend;
 303                }
 304            }
 305            else
 306            {
 307                __gshared int   _tlsstart;
 308                alias _tlsstart _tlsend;
 309            }
 310        }
 311        else version (LDC)
 312        {
 313            version = LDC_NoTlsBracketSyms;
 314        }
 315        else
 316        {
 317            __gshared int   _tlsstart;
 318            alias _tlsstart _tlsend;
 319        }
 320
 321
 322        //
 323        // Entry point for POSIX threads
 324        //
 325        extern (C) void* thread_entryPoint( void* arg )
 326        {
 327            Thread  obj = cast(Thread) arg;
 328            assert( obj );
 329
 330            assert( obj.m_curr is &obj.m_main );
 331            obj.m_main.bstack = getStackBottom();
 332            obj.m_main.tstack = obj.m_main.bstack;
 333
 334            version (LDC_NoTlsBracketSyms)
 335            {
 336                version (OSX)
 337                {
 338                    import ldc.memory;
 339                    obj.m_tls = getCurrentTLSRange();
 340                }
 341                else
 342                {
 343                    // Nothing to do here for Linux – glibc allocates the TLS
 344                    // data at the start of the stack area, so we scan it anyway.
 345                }
 346            }
 347            else version(OSX)
 348            {
 349                // NOTE: OSX does not support TLS, so we do it ourselves.  The TLS
 350                //       data output by the compiler is bracketed by _tls_data_array[2],
 351                //       so make a copy of it for each thread.
 352                const sz0 = (_tls_data_array[0].length + 15) & ~cast(size_t)15;
 353                const sz2 = sz0 + _tls_data_array[1].length;
 354                auto p = malloc( sz2 );
 355                assert( p );
 356                obj.m_tls = p[0 .. sz2];
 357                memcpy( p, _tls_data_array[0].ptr, _tls_data_array[0].length );
 358                memcpy( p + sz0, _tls_data_array[1].ptr, _tls_data_array[1].length );
 359                scope (exit) { free( p ); obj.m_tls = null; }
 360            }
 361            else
 362            {
 363                auto pstart = cast(void*) &_tlsstart;
 364                auto pend   = cast(void*) &_tlsend;
 365                obj.m_tls = pstart[0 .. pend - pstart];
 366            }
 367
 368            obj.m_isRunning = true;
 369            Thread.setThis( obj );
 370            //Thread.add( obj );
 371            scope( exit )
 372            {
 373                // NOTE: isRunning should be set to false after the thread is
 374                //       removed or a double-removal could occur between this
 375                //       function and thread_suspendAll.
 376                Thread.remove( obj );
 377                obj.m_isRunning = false;
 378            }
 379            Thread.add( &obj.m_main );
 380            obj.m_tlsgcdata = rt.tlsgc.init();
 381
 382            static extern (C) void thread_cleanupHandler( void* arg ) nothrow
 383            {
 384                Thread  obj = cast(Thread) arg;
 385                assert( obj );
 386
 387                // NOTE: If the thread terminated abnormally, just set it as
 388                //       not running and let thread_suspendAll remove it from
 389                //       the thread list.  This is safer and is consistent
 390                //       with the Windows thread code.
 391                obj.m_isRunning = false;
 392            }
 393
 394            // NOTE: Using void to skip the initialization here relies on
 395            //       knowledge of how pthread_cleanup is implemented.  It may
 396            //       not be appropriate for all platforms.  However, it does
 397            //       avoid the need to link the pthread module.  If any
 398            //       implementation actually requires default initialization
 399            //       then pthread_cleanup should be restructured to maintain
 400            //       the current lack of a link dependency.
 401            static if( __traits( compiles, pthread_cleanup ) )
 402            {
 403                pthread_cleanup cleanup = void;
 404                cleanup.push( &thread_cleanupHandler, cast(void*) obj );
 405            }
 406            else static if( __traits( compiles, pthread_cleanup_push ) )
 407            {
 408                pthread_cleanup_push( &thread_cleanupHandler, cast(void*) obj );
 409            }
 410            else
 411            {
 412                static assert( false, "Platform not supported." );
 413            }
 414
 415            // NOTE: No GC allocations may occur until the stack pointers have
 416            //       been set and Thread.getThis returns a valid reference to
 417            //       this thread object (this latter condition is not strictly
 418            //       necessary on Windows but it should be followed for the
 419            //       sake of consistency).
 420
 421            // TODO: Consider putting an auto exception object here (using
 422            //       alloca) forOutOfMemoryError plus something to track
 423            //       whether an exception is in-flight?
 424
 425            void append( Throwable t )
 426            {
 427                if( obj.m_unhandled is null )
 428                    obj.m_unhandled = t;
 429                else
 430                {
 431                    Throwable last = obj.m_unhandled;
 432                    while( last.next !is null )
 433                        last = last.next;
 434                    last.next = t;
 435                }
 436            }
 437
 438            try
 439            {
 440                rt_moduleTlsCtor();
 441                try
 442                {
 443                    obj.run();
 444                }
 445                catch( Throwable t )
 446                {
 447                    append( t );
 448                }
 449                rt_moduleTlsDtor();
 450            }
 451            catch( Throwable t )
 452            {
 453                append( t );
 454            }
 455
 456            // NOTE: Normal cleanup is handled by scope(exit).
 457
 458            static if( __traits( compiles, pthread_cleanup ) )
 459            {
 460                cleanup.pop( 0 );
 461            }
 462            else static if( __traits( compiles, pthread_cleanup_push ) )
 463            {
 464                pthread_cleanup_pop( 0 );
 465            }
 466
 467            return null;
 468        }
 469
 470
 471        //
 472        // Used to track the number of suspended threads
 473        //
 474        __gshared sem_t suspendCount;
 475
 476
 477        extern (C) void thread_suspendHandler( int sig )
 478        in
 479        {
 480            assert( sig == SIGUSR1 );
 481        }
 482        body
 483        {
 484            void op(void* sp)
 485            {
 486                // NOTE: Since registers are being pushed and popped from the
 487                //       stack, any other stack data used by this function should
 488                //       be gone before the stack cleanup code is called below.
 489                Thread  obj = Thread.getThis();
 490
 491                // NOTE: The thread reference returned by getThis is set within
 492                //       the thread startup code, so it is possible that this
 493                //       handler may be called before the reference is set.  In
 494                //       this case it is safe to simply suspend and not worry
 495                //       about the stack pointers as the thread will not have
 496                //       any references to GC-managed data.
 497                if( obj && !obj.m_lock )
 498                {
 499                    obj.m_curr.tstack = getStackTop();
 500                }
 501
 502                sigset_t    sigres = void;
 503                int         status;
 504
 505                status = sigfillset( &sigres );
 506                assert( status == 0 );
 507
 508                status = sigdelset( &sigres, SIGUSR2 );
 509                assert( status == 0 );
 510
 511                status = sem_post( &suspendCount );
 512                assert( status == 0 );
 513
 514                sigsuspend( &sigres );
 515
 516                if( obj && !obj.m_lock )
 517                {
 518                    obj.m_curr.tstack = obj.m_curr.bstack;
 519                }
 520            }
 521
 522            callWithStackShell(&op);
 523        }
 524
 525
 526        extern (C) void thread_resumeHandler( int sig )
 527        in
 528        {
 529            assert( sig == SIGUSR2 );
 530        }
 531        body
 532        {
 533
 534        }
 535    }
 536}
 537else
 538{
 539    // NOTE: This is the only place threading versions are checked.  If a new
 540    //       version is added, the module code will need to be searched for
 541    //       places where version-specific code may be required.  This can be
 542    //       easily accomlished by searching for 'Windows' or 'Posix'.
 543    static assert( false, "Unknown threading implementation." );
 544}
 545
 546
 547///////////////////////////////////////////////////////////////////////////////
 548// Thread
 549///////////////////////////////////////////////////////////////////////////////
 550
 551
 552/**
 553 * This class encapsulates all threading functionality for the D
 554 * programming language.  As thread manipulation is a required facility
 555 * for garbage collection, all user threads should derive from this
 556 * class, and instances of this class should never be explicitly deleted.
 557 * A new thread may be created using either derivation or composition, as
 558 * in the following example.
 559 *
 560 * Example:
 561 * ----------------------------------------------------------------------------
 562 *
 563 * class DerivedThread : Thread
 564 * {
 565 *     this()
 566 *     {
 567 *         super( &run );
 568 *     }
 569 *
 570 * private :
 571 *     void run()
 572 *     {
 573 *         printf( "Derived thread running.\n" );
 574 *     }
 575 * }
 576 *
 577 * void threadFunc()
 578 * {
 579 *     printf( "Composed thread running.\n" );
 580 * }
 581 *
 582 * // create instances of each type
 583 * Thread derived = new DerivedThread();
 584 * Thread composed = new Thread( &threadFunc );
 585 *
 586 * // start both threads
 587 * derived.start();
 588 * composed.start();
 589 *
 590 * ----------------------------------------------------------------------------
 591 */
 592class Thread
 593{
 594    ///////////////////////////////////////////////////////////////////////////
 595    // Initialization
 596    ///////////////////////////////////////////////////////////////////////////
 597
 598
 599    /**
 600     * Initializes a thread object which is associated with a static
 601     * D function.
 602     *
 603     * Params:
 604     *  fn = The thread function.
 605     *  sz = The stack size for this thread.
 606     *
 607     * In:
 608     *  fn must not be null.
 609     */
 610    this( void function() fn, size_t sz = 0 )
 611    in
 612    {
 613        assert( fn );
 614    }
 615    body
 616    {
 617        this();
 618        m_fn   = fn;
 619        m_sz   = sz;
 620        m_call = Call.FN;
 621        m_curr = &m_main;
 622    }
 623
 624
 625    /**
 626     * Initializes a thread object which is associated with a dynamic
 627     * D function.
 628     *
 629     * Params:
 630     *  dg = The thread function.
 631     *  sz = The stack size for this thread.
 632     *
 633     * In:
 634     *  dg must not be null.
 635     */
 636    this( void delegate() dg, size_t sz = 0 )
 637    in
 638    {
 639        assert( dg );
 640    }
 641    body
 642    {
 643        this();
 644        m_dg   = dg;
 645        m_sz   = sz;
 646        m_call = Call.DG;
 647        m_curr = &m_main;
 648    }
 649
 650
 651    /**
 652     * Cleans up any remaining resources used by this object.
 653     */
 654    ~this()
 655    {
 656        if( m_addr == m_addr.init )
 657        {
 658            return;
 659        }
 660
 661        version( Windows )
 662        {
 663            m_addr = m_addr.init;
 664            CloseHandle( m_hndl );
 665            m_hndl = m_hndl.init;
 666        }
 667        else version( Posix )
 668        {
 669            pthread_detach( m_addr );
 670            m_addr = m_addr.init;
 671        }
 672        version( OSX )
 673        {
 674            m_tmach = m_tmach.init;
 675        }
 676        rt.tlsgc.destroy( m_tlsgcdata );
 677        m_tlsgcdata = null;
 678    }
 679
 680
 681    ///////////////////////////////////////////////////////////////////////////
 682    // General Actions
 683    ///////////////////////////////////////////////////////////////////////////
 684
 685
 686    /**
 687     * Starts the thread and invokes the function or delegate passed upon
 688     * construction.
 689     *
 690     * In:
 691     *  This routine may only be called once per thread instance.
 692     *
 693     * Throws:
 694     *  ThreadException if the thread fails to start.
 695     */
 696    final void start()
 697    in
 698    {
 699        assert( !next && !prev );
 700    }
 701    body
 702    {
 703        auto wasThreaded  = multiThreadedFlag;
 704        multiThreadedFlag = true;
 705        scope( failure )
 706        {
 707            if( !wasThreaded )
 708                multiThreadedFlag = false;
 709        }
 710
 711        version( Windows ) {} else
 712        version( Posix )
 713        {
 714            pthread_attr_t  attr;
 715
 716            if( pthread_attr_init( &attr ) )
 717                throw new ThreadException( "Error initializing thread attributes" );
 718            if( m_sz && pthread_attr_setstacksize( &attr, m_sz ) )
 719                throw new ThreadException( "Error initializing thread stack size" );
 720            if( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) )
 721                throw new ThreadException( "Error setting thread joinable" );
 722        }
 723
 724        version( Windows )
 725        {
 726            // NOTE: If a thread is just executing DllMain()
 727            //       while another thread is started here, it holds an OS internal
 728            //       lock that serializes DllMain with CreateThread. As the code
 729            //       might request a synchronization on slock (e.g. in thread_findByAddr()),
 730            //       we cannot hold that lock while creating the thread without
 731            //       creating a deadlock
 732            //
 733            // Solution: Create the thread in suspended state and then
 734            //       add and resume it with slock acquired
 735            assert(m_sz <= uint.max, "m_sz must be less than or equal to uint.max");
 736            m_hndl = cast(HANDLE) _beginthreadex( null, cast(uint) m_sz, &thread_entryPoint, cast(void*) this, CREATE_SUSPENDED, &m_addr );
 737            if( cast(size_t) m_hndl == 0 )
 738                throw new ThreadException( "Error creating thread" );
 739        }
 740
 741        // NOTE: The starting thread must be added to the global thread list
 742        //       here rather than within thread_entryPoint to prevent a race
 743        //       with the main thread, which could finish and terminat the
 744        //       app without ever knowing that it should have waited for this
 745        //       starting thread.  In effect, not doing the add here risks
 746        //       having thread being treated like a daemon thread.
 747        synchronized( slock )
 748        {
 749            version( Windows )
 750            {
 751                if( ResumeThread( m_hndl ) == -1 )
 752                    throw new ThreadException( "Error resuming thread" );
 753            }
 754            else version( Posix )
 755            {
 756                // NOTE: This is also set to true by thread_entryPoint, but set it
 757                //       here as well so the calling thread will see the isRunning
 758                //       state immediately.
 759                m_isRunning = true;
 760                scope( failure ) m_isRunning = false;
 761
 762                if( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 )
 763                    throw new ThreadException( "Error creating thread" );
 764            }
 765            version( OSX )
 766            {
 767                m_tmach = pthread_mach_thread_np( m_addr );
 768                if( m_tmach == m_tmach.init )
 769                    throw new ThreadException( "Error creating thread" );
 770            }
 771
 772            // NOTE: when creating threads from inside a DLL, DllMain(THREAD_ATTACH)
 773            //       might be called before ResumeThread returns, but the dll
 774            //       helper functions need to know whether the thread is created
 775            //       from the runtime itself or from another DLL or the application
 776            //       to just attach to it
 777            //       as a consequence, the new Thread object is added before actual
 778            //       creation of the thread. There should be no problem with the GC
 779            //       calling thread_suspendAll, because of the slock synchronization
 780            //
 781            // VERIFY: does this actually also apply to other platforms?
 782            add( this );
 783        }
 784    }
 785
 786
 787    /**
 788     * Waits for this thread to complete.  If the thread terminated as the
 789     * result of an unhandled exception, this exception will be rethrown.
 790     *
 791     * Params:
 792     *  rethrow = Rethrow any unhandled exception which may have caused this
 793     *            thread to terminate.
 794     *
 795     * Throws:
 796     *  ThreadException if the operation fails.
 797     *  Any exception not handled by the joined thread.
 798     *
 799     * Returns:
 800     *  Any exception not handled by this thread if rethrow = false, null
 801     *  otherwise.
 802     */
 803    final Throwable join( bool rethrow = true )
 804    {
 805        version( Windows )
 806        {
 807            if( WaitForSingleObject( m_hndl, INFINITE ) != WAIT_OBJECT_0 )
 808                throw new ThreadException( "Unable to join thread" );
 809            // NOTE: m_addr must be cleared before m_hndl is closed to avoid
 810            //       a race condition with isRunning. The operation is done
 811            //       with atomicStore to prevent compiler reordering.
 812            atomicStore!(MemoryOrder.raw)(*cast(shared)&m_addr, m_addr.init);
 813            CloseHandle( m_hndl );
 814            m_hndl = m_hndl.init;
 815        }
 816        else version( Posix )
 817        {
 818            if( pthread_join( m_addr, null ) != 0 )
 819                throw new ThreadException( "Unable to join thread" );
 820            // NOTE: pthread_join acts as a substitute for pthread_detach,
 821            //       which is normally called by the dtor.  Setting m_addr
 822            //       to zero ensures that pthread_detach will not be called
 823            //       on object destruction.
 824            m_addr = m_addr.init;
 825        }
 826        if( m_unhandled )
 827        {
 828            if( rethrow )
 829                throw m_unhandled;
 830            return m_unhandled;
 831        }
 832        return null;
 833    }
 834
 835
 836    ///////////////////////////////////////////////////////////////////////////
 837    // General Properties
 838    ///////////////////////////////////////////////////////////////////////////
 839
 840
 841    /**
 842     * Gets the user-readable label for this thread.
 843     *
 844     * Returns:
 845     *  The name of this thread.
 846     */
 847    final @property string name()
 848    {
 849        synchronized( this )
 850        {
 851            return m_name;
 852        }
 853    }
 854
 855
 856    /**
 857     * Sets the user-readable label for this thread.
 858     *
 859     * Params:
 860     *  val = The new name of this thread.
 861     */
 862    final @property void name( string val )
 863    {
 864        synchronized( this )
 865        {
 866            m_name = val;
 867        }
 868    }
 869
 870
 871    /**
 872     * Gets the daemon status for this thread.  While the runtime will wait for
 873     * all normal threads to complete before tearing down the process, daemon
 874     * threads are effectively ignored and thus will not prevent the process
 875     * from terminating.  In effect, daemon threads will be terminated
 876     * automatically by the OS when the process exits.
 877     *
 878     * Returns:
 879     *  true if this is a daemon thread.
 880     */
 881    final @property bool isDaemon()
 882    {
 883        synchronized( this )
 884        {
 885            return m_isDaemon;
 886        }
 887    }
 888
 889
 890    /**
 891     * Sets the daemon status for this thread.  While the runtime will wait for
 892     * all normal threads to complete before tearing down the process, daemon
 893     * threads are effectively ignored and thus will not prevent the process
 894     * from terminating.  In effect, daemon threads will be terminated
 895     * automatically by the OS when the process exits.
 896     *
 897     * Params:
 898     *  val = The new daemon status for this thread.
 899     */
 900    final @property void isDaemon( bool val )
 901    {
 902        synchronized( this )
 903        {
 904            m_isDaemon = val;
 905        }
 906    }
 907
 908
 909    /**
 910     * Tests whether this thread is running.
 911     *
 912     * Returns:
 913     *  true if the thread is running, false if not.
 914     */
 915    final @property bool isRunning()
 916    {
 917        if( m_addr == m_addr.init )
 918        {
 919            return false;
 920        }
 921
 922        version( Windows )
 923        {
 924            uint ecode = 0;
 925            GetExitCodeThread( m_hndl, &ecode );
 926            return ecode == STILL_ACTIVE;
 927        }
 928        else version( Posix )
 929        {
 930            // NOTE: It should be safe to access this value without
 931            //       memory barriers because word-tearing and such
 932            //       really isn't an issue for boolean values.
 933            return m_isRunning;
 934        }
 935    }
 936
 937
 938    ///////////////////////////////////////////////////////////////////////////
 939    // Thread Priority Actions
 940    ///////////////////////////////////////////////////////////////////////////
 941
 942
 943    /**
 944     * The minimum scheduling priority that may be set for a thread.  On
 945     * systems where multiple scheduling policies are defined, this value
 946     * represents the minimum valid priority for the scheduling policy of
 947     * the process.
 948     */
 949    __gshared const int PRIORITY_MIN;
 950
 951
 952    /**
 953     * The maximum scheduling priority that may be set for a thread.  On
 954     * systems where multiple scheduling policies are defined, this value
 955     * represents the minimum valid priority for the scheduling policy of
 956     * the process.
 957     */
 958    __gshared const int PRIORITY_MAX;
 959
 960
 961    /**
 962     * Gets the scheduling priority for the associated thread.
 963     *
 964     * Returns:
 965     *  The scheduling priority of this thread.
 966     */
 967    final @property int priority()
 968    {
 969        version( Windows )
 970        {
 971            return GetThreadPriority( m_hndl );
 972        }
 973        else version( Posix )
 974        {
 975            int         policy;
 976            sched_param param;
 977
 978            if( pthread_getschedparam( m_addr, &policy, &param ) )
 979                throw new ThreadException( "Unable to get thread priority" );
 980            return param.sched_priority;
 981        }
 982    }
 983
 984
 985    /**
 986     * Sets the scheduling priority for the associated thread.
 987     *
 988     * Params:
 989     *  val = The new scheduling priority of this thread.
 990     */
 991    final @property void priority( int val )
 992    {
 993        version( Windows )
 994        {
 995            if( !SetThreadPriority( m_hndl, val ) )
 996                throw new ThreadException( "Unable to set thread priority" );
 997        }
 998        else version( Posix )
 999        {
1000            // NOTE: pthread_setschedprio is not implemented on linux, so use
1001            //       the more complicated get/set sequence below.
1002            //if( pthread_setschedprio( m_addr, val ) )
1003            //    throw new ThreadException( "Unable to set thread priority" );
1004
1005            int         policy;
1006            sched_param param;
1007
1008            if( pthread_getschedparam( m_addr, &policy, &param ) )
1009                throw new ThreadException( "Unable to set thread priority" );
1010            param.sched_priority = val;
1011            if( pthread_setschedparam( m_addr, policy, &param ) )
1012                throw new ThreadException( "Unable to set thread priority" );
1013        }
1014    }
1015
1016
1017    ///////////////////////////////////////////////////////////////////////////
1018    // Actions on Calling Thread
1019    ///////////////////////////////////////////////////////////////////////////
1020
1021
1022    /**
1023     * Suspends the calling thread for at least the supplied period.  This may
1024     * result in multiple OS calls if period is greater than the maximum sleep
1025     * duration supported by the operating system.
1026     *
1027     * Params:
1028     *  val = The minimum duration the calling thread should be suspended.
1029     *
1030     * In:
1031     *  period must be non-negative.
1032     *
1033     * Example:
1034     * ------------------------------------------------------------------------
1035     *
1036     * Thread.sleep( dur!("msecs")( 50 ) );  // sleep for 50 milliseconds
1037     * Thread.sleep( dur!("seconds")( 5 ) ); // sleep for 5 seconds
1038     *
1039     * ------------------------------------------------------------------------
1040     */
1041    static void sleep( Duration val )
1042    in
1043    {
1044        assert( !val.isNegative );
1045    }
1046    body
1047    {
1048        version( Windows )
1049        {
1050            auto maxSleepMillis = dur!("msecs")( uint.max - 1 );
1051
1052            // NOTE: In instances where all other threads in the process have a
1053            //       lower priority than the current thread, the current thread
1054            //       will not yield with a sleep time of zero.  However, unlike
1055            //       yield(), the user is not asking for a yield to occur but
1056            //       only for execution to suspend for the requested interval.
1057            //       Therefore, expected performance may not be met if a yield
1058            //       is forced upon the user.
1059            while( val > maxSleepMillis )
1060            {
1061                Sleep( cast(uint)
1062                       maxSleepMillis.total!"msecs" );
1063                val -= maxSleepMillis;
1064            }
1065            Sleep( cast(uint) val.total!"msecs" );
1066        }
1067        else version( Posix )
1068        {
1069            timespec tin  = void;
1070            timespec tout = void;
1071
1072            if( val.total!"seconds" > tin.tv_sec.max )
1073            {
1074                tin.tv_sec  = tin.tv_sec.max;
1075                tin.tv_nsec = cast(typeof(tin.tv_nsec)) val.fracSec.nsecs;
1076            }
1077            else
1078            {
1079                tin.tv_sec  = cast(typeof(tin.tv_sec)) val.total!"seconds";
1080                tin.tv_nsec = cast(typeof(tin.tv_nsec)) val.fracSec.nsecs;
1081            }
1082            while( true )
1083            {
1084                if( !nanosleep( &tin, &tout ) )
1085                    return;
1086                if( errno != EINTR )
1087                    throw new ThreadException( "Unable to sleep for the specified duration" );
1088                tin = tout;
1089            }
1090        }
1091    }
1092
1093
1094    /**
1095     * $(RED Deprecated. It will be removed in December 2012. Please use the
1096     *       version which takes a $(D Duration) instead.)
1097     *
1098     * Suspends the calling thread for at least the supplied period.  This may
1099     * result in multiple OS calls if period is greater than the maximum sleep
1100     * duration supported by the operating system.
1101     *
1102     * Params:
1103     *  period = The minimum duration the calling thread should be suspended,
1104     *           in 100 nanosecond intervals.
1105     *
1106     * In:
1107     *  period must be non-negative.
1108     *
1109     * Example:
1110     * ------------------------------------------------------------------------
1111     *
1112     * Thread.sleep( 500_000 );    // sleep for 50 milliseconds
1113     * Thread.sleep( 50_000_000 ); // sleep for 5 seconds
1114     *
1115     * ------------------------------------------------------------------------
1116     */
1117    deprecated("Please use the overload of sleep which takes a Duration.")
1118    static void sleep( long period )
1119    in
1120    {
1121        assert( period >= 0 );
1122    }
1123    body
1124    {
1125        sleep( dur!"hnsecs"( period ) );
1126    }
1127
1128
1129    /**
1130     * Forces a context switch to occur away from the calling thread.
1131     */
1132    static void yield()
1133    {
1134        version( Windows )
1135            SwitchToThread();
1136        else version( Posix )
1137            sched_yield();
1138    }
1139
1140
1141    ///////////////////////////////////////////////////////////////////////////
1142    // Thread Accessors
1143    ///////////////////////////////////////////////////////////////////////////
1144
1145
1146    /**
1147     * Provides a reference to the calling thread.
1148     *
1149     * Returns:
1150     *  The thread object representing the calling thread.  The result of
1151     *  deleting this object is undefined.  If the current thread is not
1152     *  attached to the runtime, a null reference is returned.
1153     */
1154    static Thread getThis()
1155    {
1156        // NOTE: This function may not be called until thread_init has
1157        //       completed.  See thread_suspendAll for more information
1158        //       on why this might occur.
1159        version( Windows )
1160        {
1161            auto t = cast(Thread) TlsGetValue( sm_this );
1162
1163            // NOTE: If this thread was attached via thread_attachByAddr then
1164            //       this TLS lookup won't initially be set, so when the TLS
1165            //       lookup fails, try an exhaustive search.
1166            if( t is null )
1167            {
1168                t = thread_findByAddr( GetCurrentThreadId() );
1169                setThis( t );
1170            }
1171            return t;
1172        }
1173        else version( Posix )
1174        {
1175            auto t = cast(Thread) pthread_getspecific( sm_this );
1176
1177            // NOTE: See the comment near thread_findByAddr() for why the
1178            //       secondary thread_findByAddr lookup can't be done on
1179            //       Posix.  However, because thread_attachByAddr() is for
1180            //       Windows only, the secondary lookup is pointless anyway.
1181            return t;
1182        }
1183    }
1184
1185
1186    /**
1187     * Provides a list of all threads currently being tracked by the system.
1188     *
1189     * Returns:
1190     *  An array containing references to all threads currently being
1191     *  tracked by the system.  The result of deleting any contained
1192     *  objects is undefined.
1193     */
1194    static Thread[] getAll()
1195    {
1196        synchronized( slock )
1197        {
1198            size_t   pos = 0;
1199            Thread[] buf = new Thread[sm_tlen];
1200
1201            foreach( Thread t; Thread )
1202            {
1203                buf[pos++] = t;
1204            }
1205            return buf;
1206        }
1207    }
1208
1209
1210    /**
1211     * Operates on all threads currently being tracked by the system.  The
1212     * result of deleting any Thread object is undefined.
1213     *
1214     * Params:
1215     *  dg = The supplied code as a delegate.
1216     *
1217     * Returns:
1218     *  Zero if all elemented are visited, nonzero if not.
1219     */
1220    static int opApply( scope int delegate( ref Thread ) dg )
1221    {
1222        synchronized( slock )
1223        {
1224            int ret = 0;
1225
1226            for( Thread t = sm_tbeg; t; t = t.next )
1227            {
1228                ret = dg( t );
1229                if( ret )
1230                    break;
1231            }
1232            return ret;
1233        }
1234    }
1235
1236
1237    ///////////////////////////////////////////////////////////////////////////
1238    // Static Initalizer
1239    ///////////////////////////////////////////////////////////////////////////
1240
1241
1242    /**
1243     * This initializer is used to set thread constants.  All functional
1244     * initialization occurs within thread_init().
1245     */
1246    shared static this()
1247    {
1248        version( Windows )
1249        {
1250            PRIORITY_MIN = -15;
1251            PRIORITY_MAX =  15;
1252        }
1253        else version( Posix )
1254        {
1255            int         policy;
1256            sched_param param;
1257            pthread_t   self = pthread_self();
1258
1259            int status = pthread_getschedparam( self, &policy, &param );
1260            assert( status == 0 );
1261
1262            PRIORITY_MIN = sched_get_priority_min( policy );
1263            assert( PRIORITY_MIN != -1 );
1264
1265            PRIORITY_MAX = sched_get_priority_max( policy );
1266            assert( PRIORITY_MAX != -1 );
1267        }
1268    }
1269
1270
1271    ///////////////////////////////////////////////////////////////////////////
1272    // Stuff That Should Go Away
1273    ///////////////////////////////////////////////////////////////////////////
1274
1275
1276private:
1277    //
1278    // Initializes a thread object which has no associated executable function.
1279    // This is used for the main thread initialized in thread_init().
1280    //
1281    this()
1282    {
1283        m_call = Call.NO;
1284        m_curr = &m_main;
1285
1286        version (LDC_NoTlsBracketSyms) {} else
1287        version (OSX)
1288        {
1289            //printf("test2 %p %p\n", _tls_data_array[0].ptr, &_tls_data_array[1][length]);
1290            //printf("test2 %p %p\n", &_tls_beg, &_tls_end);
1291            // NOTE: OSX does not support TLS, so we do it ourselves.  The TLS
1292            //       data output by the compiler is bracketed by _tls_data_array2],
1293            //       so make a copy of it for each thread.
1294            const sz0 = (_tls_data_array[0].length + 15) & ~cast(size_t)15;
1295            const sz2 = sz0 + _tls_data_array[1].length;
1296            auto p = malloc( sz2 );
1297            assert( p );
1298            m_tls = p[0 .. sz2];
1299            memcpy( p, _tls_data_array[0].ptr, _tls_data_array[0].length );
1300            memcpy( p + sz0, _tls_data_array[1].ptr, _tls_data_array[1].length );
1301            // The free must happen at program end, if anywhere.
1302        }
1303        else
1304        {
1305            auto pstart = cast(void*) &_tlsstart;
1306            auto pend   = cast(void*) &_tlsend;
1307            m_tls = pstart[0 .. pend - pstart];
1308        }
1309    }
1310
1311
1312    //
1313    // Thread entry point.  Invokes the function or delegate passed on
1314    // construction (if any).
1315    //
1316    final void run()
1317    {
1318        switch( m_call )
1319        {
1320        case Call.FN:
1321            m_fn();
1322            break;
1323        case Call.DG:
1324            m_dg();
1325            break;
1326        default:
1327            break;
1328        }
1329    }
1330
1331
1332private:
1333    //
1334    // The type of routine passed on thread construction.
1335    //
1336    enum Call
1337    {
1338        NO,
1339        FN,
1340        DG
1341    }
1342
1343
1344    //
1345    // Standard types
1346    //
1347    version( Windows )
1348    {
1349        alias uint TLSKey;
1350        alias uint ThreadAddr;
1351    }
1352    else version( Posix )
1353    {
1354        alias pthread_key_t TLSKey;
1355        alias pthread_t     ThreadAddr;
1356    }
1357
1358
1359    //
1360    // Local storage
1361    //
1362    __gshared TLSKey    sm_this;
1363
1364
1365    //
1366    // Main process thread
1367    //
1368    __gshared Thread    sm_main;
1369
1370
1371    //
1372    // Standard thread data
1373    //
1374    version( Windows )
1375    {
1376        HANDLE          m_hndl;
1377    }
1378    else version( OSX )
1379    {
1380        mach_port_t     m_tmach;
1381    }
1382    ThreadAddr          m_addr;
1383    Call                m_call;
1384    string              m_name;
1385    union
1386    {
1387        void function() m_fn;
1388        void delegate() m_dg;
1389    }
1390    size_t              m_sz;
1391    version( Posix )
1392    {
1393        bool            m_isRunning;
1394    }
1395    bool                m_isDaemon;
1396    bool                m_isInCriticalRegion;
1397    Throwable           m_unhandled;
1398
1399
1400private:
1401    ///////////////////////////////////////////////////////////////////////////
1402    // Storage of Active Thread
1403    ///////////////////////////////////////////////////////////////////////////
1404
1405
1406    //
1407    // Sets a thread-local reference to the current thread object.
1408    //
1409    static void setThis( Thread t )
1410    {
1411        version( Windows )
1412        {
1413            TlsSetValue( sm_this, cast(void*) t );
1414        }
1415        else version( Posix )
1416        {
1417            pthread_setspecific( sm_this, cast(void*) t );
1418        }
1419    }
1420
1421
1422private:
1423    ///////////////////////////////////////////////////////////////////////////
1424    // Thread Context and GC Scanning Support
1425    ///////////////////////////////////////////////////////////////////////////
1426
1427
1428    final void pushContext( Context* c )
1429    in
1430    {
1431        assert( !c.within );
1432    }
1433    body
1434    {
1435        c.within = m_curr;
1436        m_curr = c;
1437    }
1438
1439
1440    final void popContext()
1441    in
1442    {
1443        assert( m_curr && m_curr.within );
1444    }
1445    body
1446    {
1447        Context* c = m_curr;
1448        m_curr = c.within;
1449        c.within = null;
1450    }
1451
1452
1453    final Context* topContext()
1454    in
1455    {
1456        assert( m_curr );
1457    }
1458    body
1459    {
1460        return m_curr;
1461    }
1462
1463
1464    static struct Context
1465    {
1466        void*           bstack,
1467                        tstack;
1468        Context*        within;
1469        Context*        next,
1470                        prev;
1471    }
1472
1473
1474    Context             m_main;
1475    Context*            m_curr;
1476    bool                m_lock;
1477    void[]              m_tls;  // spans implicit thread local storage
1478    rt.tlsgc.Data*      m_tlsgcdata;
1479
1480    version( Windows )
1481    {
1482      version( X86 )
1483      {
1484        uint[8]         m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
1485      }
1486      else version( X86_64 )
1487      {
1488        ulong[16]       m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax
1489                               // r8,r9,r10,r11,r12,r13,r14,r15
1490      }
1491      else
1492      {
1493        static assert(false, "Architecture not supported." );
1494      }
1495    }
1496    else version( OSX )
1497    {
1498      version( X86 )
1499      {
1500        uint[8]         m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
1501      }
1502      else version( X86_64 )
1503      {
1504        ulong[16]       m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax
1505                               // r8,r9,r10,r11,r12,r13,r14,r15
1506      }
1507      else
1508      {
1509        static assert(false, "Architecture not supported." );
1510      }
1511    }
1512
1513
1514private:
1515    ///////////////////////////////////////////////////////////////////////////
1516    // GC Scanning Support
1517    ///////////////////////////////////////////////////////////////////////////
1518
1519
1520    // NOTE: The GC scanning process works like so:
1521    //
1522    //          1. Suspend all threads.
1523    //          2. Scan the stacks of all suspended threads for roots.
1524    //          3. Resume all threads.
1525    //
1526    //       Step 1 and 3 require a list of all threads in the system, while
1527    //       step 2 requires a list of all thread stacks (each represented by
1528    //       a Context struct).  Traditionally, there was one stack per thread
1529    //       and the Context structs were not necessary.  However, Fibers have
1530    //       changed things so that each thread has its own 'main' stack plus
1531    //       an arbitrary number of nested stacks (normally referenced via
1532    //       m_curr).  Also, there may be 'free-floating' stacks in the system,
1533    //       which are Fibers that are not currently executing on any specific
1534    //       thread but are still being processed and still contain valid
1535    //       roots.
1536    //
1537    //       To support all of this, the Context struct has been created to
1538    //       represent a stack range, and a global list of Context structs has
1539    //       been added to enable scanning of these stack ranges.  The lifetime
1540    //       (and presence in the Context list) of a thread's 'main' stack will
1541    //       be equivalent to the thread's lifetime.  So the Ccontext will be
1542    //       added to the list on thread entry, and removed from the list on
1543    //       thread exit (which is essentially the same as the presence of a
1544    //       Thread object in its own global list).  The lifetime of a Fiber's
1545    //       context, however, will be tied to the lifetime of the Fiber object
1546    //       itself, and Fibers are expected to add/remove their Context struct
1547    //       on construction/deletion.
1548
1549
1550    //
1551    // All use of the global lists should synchronize on this lock.
1552    //
1553    @property static Mutex slock()
1554    {
1555        __gshared Mutex m;
1556        __gshared byte[__traits(classInstanceSize, Mutex)] ms;
1557
1558        if (m is null)
1559        {
1560            // Initialization doesn't need to be synchronized because
1561            // creating a thread will lock this mutex.
1562            ms[] = Mutex.classinfo.init[];
1563            m = cast(Mutex)ms.ptr;
1564            m.__ctor();
1565
1566            extern(C) void destroy() { m.__dtor(); }
1567            atexit(&destroy);
1568        }
1569        return m;
1570    }
1571
1572    __gshared Context*  sm_cbeg;
1573    __gshared size_t    sm_clen;
1574
1575    __gshared Thread    sm_tbeg;
1576    __gshared size_t    sm_tlen;
1577
1578    //
1579    // Used for ordering threads in the global thread list.
1580    //
1581    Thread              prev;
1582    Thread              next;
1583
1584
1585    ///////////////////////////////////////////////////////////////////////////
1586    // Global Context List Operations
1587    ///////////////////////////////////////////////////////////////////////////
1588
1589
1590    //
1591    // Add a context to the global context list.
1592    //
1593    static void add( Context* c )
1594    in
1595    {
1596        assert( c );
1597        assert( !c.next && !c.prev );
1598    }
1599    body
1600    {
1601        // NOTE: This loop is necessary to avoid a race between newly created
1602        //       threads and the GC.  If a collection starts between the time
1603        //       Thread.start is called and the new thread calls Thread.add,
1604        //       the thread will have its stack scanned without first having
1605        //       been properly suspended.  Testing has shown this to sometimes
1606        //       cause a deadlock.
1607
1608        while( true )
1609        {
1610            synchronized( slock )
1611            {
1612                if( !suspendDepth )
1613                {
1614                    if( sm_cbeg )
1615                    {
1616                        c.next = sm_cbeg;
1617                        sm_cbeg.prev = c;
1618                    }
1619                    sm_cbeg = c;
1620                    ++sm_clen;
1621                   return;
1622                }
1623            }
1624            yield();
1625        }
1626    }
1627
1628
1629    //
1630    // Remove a context from the global context list.
1631    //
1632    static void remove( Context* c )
1633    in
1634    {
1635        assert( c );
1636        assert( c.next || c.prev );
1637    }
1638    body
1639    {
1640        synchronized( slock )
1641        {
1642            if( c.prev )
1643                c.prev.next = c.next;
1644            if( c.next )
1645                c.next.prev = c.prev;
1646            if( sm_cbeg == c )
1647                sm_cbeg = c.next;
1648            --sm_clen;
1649        }
1650        // NOTE: Don't null out c.next or c.prev because opApply currently
1651        //       follows c.next after removing a node.  This could be easily
1652        //       addressed by simply returning the next node from this
1653        //       function, however, a context should never be re-added to the
1654        //       list anyway and having next and prev be non-null is a good way
1655        //       to ensure that.
1656    }
1657
1658
1659    ///////////////////////////////////////////////////////////////////////////
1660    // Global Thread List Operations
1661    ///////////////////////////////////////////////////////////////////////////
1662
1663
1664    //
1665    // Add a thread to the global thread list.
1666    //
1667    static void add( Thread t )
1668    in
1669    {
1670        assert( t );
1671        assert( !t.next && !t.prev );
1672        //assert( t.isRunning );
1673    }
1674    body
1675    {
1676        // NOTE: This loop is necessary to avoid a race between newly created
1677        //       threads and the GC.  If a collection starts between the time
1678        //       Thread.start is called and the new thread calls Thread.add,
1679        //       the thread could manipulate global state while the collection
1680        //       is running, and by being…

Large files files are truncated, but you can click here to view the full file