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 
12 /* NOTE: This file has been patched from the original DMD distribution to
13  * work with the GDC compiler.
14  */
15 module core.thread;
16 
17 
18 public import core.time; // for Duration
19 import core.exception : onOutOfMemoryError;
20 
21 version (OSX)
22     version = Darwin;
23 else version (iOS)
24     version = Darwin;
25 else version (TVOS)
26     version = Darwin;
27 else version (WatchOS)
28     version = Darwin;
29 
30 private
31 {
32     // interface to rt.tlsgc
33     import core.internal.traits : externDFunc;
34 
35     alias rt_tlsgc_init = externDFunc!("rt.tlsgc.init", void* function() nothrow @nogc);
36     alias rt_tlsgc_destroy = externDFunc!("rt.tlsgc.destroy", void function(void*) nothrow @nogc);
37 
38     alias ScanDg = void delegate(void* pstart, void* pend) nothrow;
39     alias rt_tlsgc_scan =
40         externDFunc!("rt.tlsgc.scan", void function(void*, scope ScanDg) nothrow);
41 
42     alias rt_tlsgc_processGCMarks =
43         externDFunc!("rt.tlsgc.processGCMarks", void function(void*, scope IsMarkedDg) nothrow);
44 }
45 
version(Solaris)46 version (Solaris)
47 {
48     import core.sys.solaris.sys.priocntl;
49     import core.sys.solaris.sys.types;
50 }
51 
52 // this should be true for most architectures
53 version (GNU_StackGrowsDown)
54     version = StackGrowsDown;
55 
56 /**
57  * Returns the process ID of the calling process, which is guaranteed to be
58  * unique on the system. This call is always successful.
59  *
60  * Example:
61  * ---
62  * writefln("Current process id: %s", getpid());
63  * ---
64  */
version(Posix)65 version (Posix)
66 {
67     alias getpid = core.sys.posix.unistd.getpid;
68 }
version(Windows)69 else version (Windows)
70 {
71     alias getpid = core.sys.windows.windows.GetCurrentProcessId;
72 }
73 
74 
75 ///////////////////////////////////////////////////////////////////////////////
76 // Thread and Fiber Exceptions
77 ///////////////////////////////////////////////////////////////////////////////
78 
79 
80 /**
81  * Base class for thread exceptions.
82  */
83 class ThreadException : Exception
84 {
85     @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
86     {
87         super(msg, file, line, next);
88     }
89 
90     @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__)
91     {
92         super(msg, file, line, next);
93     }
94 }
95 
96 
97 /**
98 * Base class for thread errors to be used for function inside GC when allocations are unavailable.
99 */
100 class ThreadError : Error
101 {
102     @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
103     {
104         super(msg, file, line, next);
105     }
106 
107     @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__)
108     {
109         super(msg, file, line, next);
110     }
111 }
112 
113 private
114 {
115     import core.atomic, core.memory, core.sync.mutex;
116 
117     // Handling unaligned mutexes are not supported on all platforms, so we must
118     // ensure that the address of all shared data are appropriately aligned.
119     import core.internal.traits : classInstanceAlignment;
120 
121     enum mutexAlign = classInstanceAlignment!Mutex;
122     enum mutexClassInstanceSize = __traits(classInstanceSize, Mutex);
123 
124     //
125     // exposed by compiler runtime
126     //
127     extern (C) void  rt_moduleTlsCtor();
128     extern (C) void  rt_moduleTlsDtor();
129 
130     /**
131      * Hook for whatever EH implementation is used to save/restore some data
132      * per stack.
133      *
134      * Params:
135      *     newContext = The return value of the prior call to this function
136      *         where the stack was last swapped out, or null when a fiber stack
137      *         is switched in for the first time.
138      */
139     extern(C) void* _d_eh_swapContext(void* newContext) nothrow @nogc;
140 
version(DigitalMars)141     version (DigitalMars)
142     {
143         version (Windows)
144             alias swapContext = _d_eh_swapContext;
145         else
146         {
147             extern(C) void* _d_eh_swapContextDwarf(void* newContext) nothrow @nogc;
148 
149             void* swapContext(void* newContext) nothrow @nogc
150             {
151                 /* Detect at runtime which scheme is being used.
152                  * Eventually, determine it statically.
153                  */
154                 static int which = 0;
155                 final switch (which)
156                 {
157                     case 0:
158                     {
159                         assert(newContext == null);
160                         auto p = _d_eh_swapContext(newContext);
161                         auto pdwarf = _d_eh_swapContextDwarf(newContext);
162                         if (p)
163                         {
164                             which = 1;
165                             return p;
166                         }
167                         else if (pdwarf)
168                         {
169                             which = 2;
170                             return pdwarf;
171                         }
172                         return null;
173                     }
174                     case 1:
175                         return _d_eh_swapContext(newContext);
176                     case 2:
177                         return _d_eh_swapContextDwarf(newContext);
178                 }
179             }
180         }
181     }
182     else
183         alias swapContext = _d_eh_swapContext;
184 }
185 
186 
187 ///////////////////////////////////////////////////////////////////////////////
188 // Thread Entry Point and Signal Handlers
189 ///////////////////////////////////////////////////////////////////////////////
190 
191 
version(Windows)192 version (Windows)
193 {
194     private
195     {
196         import core.stdc.stdint : uintptr_t; // for _beginthreadex decl below
197         import core.stdc.stdlib;             // for malloc, atexit
198         import core.sys.windows.windows;
199         import core.sys.windows.threadaux;   // for OpenThreadHandle
200 
201         extern (Windows) alias btex_fptr = uint function(void*);
202         extern (C) uintptr_t _beginthreadex(void*, uint, btex_fptr, void*, uint, uint*) nothrow;
203 
204         //
205         // Entry point for Windows threads
206         //
207         extern (Windows) uint thread_entryPoint( void* arg ) nothrow
208         {
209             Thread  obj = cast(Thread) arg;
210             assert( obj );
211 
212             assert( obj.m_curr is &obj.m_main );
213             obj.m_main.bstack = getStackBottom();
214             obj.m_main.tstack = obj.m_main.bstack;
215             obj.m_tlsgcdata = rt_tlsgc_init();
216 
217             Thread.setThis(obj);
218             Thread.add(obj);
219             scope (exit)
220             {
221                 Thread.remove(obj);
222             }
223             Thread.add(&obj.m_main);
224 
225             // NOTE: No GC allocations may occur until the stack pointers have
226             //       been set and Thread.getThis returns a valid reference to
227             //       this thread object (this latter condition is not strictly
228             //       necessary on Windows but it should be followed for the
229             //       sake of consistency).
230 
231             // TODO: Consider putting an auto exception object here (using
232             //       alloca) forOutOfMemoryError plus something to track
233             //       whether an exception is in-flight?
234 
235             void append( Throwable t )
236             {
237                 if ( obj.m_unhandled is null )
238                     obj.m_unhandled = t;
239                 else
240                 {
241                     Throwable last = obj.m_unhandled;
242                     while ( last.next !is null )
243                         last = last.next;
244                     last.next = t;
245                 }
246             }
247 
248             version (D_InlineAsm_X86)
249             {
250                 asm nothrow @nogc { fninit; }
251             }
252 
253             try
254             {
255                 rt_moduleTlsCtor();
256                 try
257                 {
258                     obj.run();
259                 }
260                 catch ( Throwable t )
261                 {
262                     append( t );
263                 }
264                 rt_moduleTlsDtor();
265             }
266             catch ( Throwable t )
267             {
268                 append( t );
269             }
270             return 0;
271         }
272 
273 
274         HANDLE GetCurrentThreadHandle() nothrow @nogc
275         {
276             const uint DUPLICATE_SAME_ACCESS = 0x00000002;
277 
278             HANDLE curr = GetCurrentThread(),
279                    proc = GetCurrentProcess(),
280                    hndl;
281 
282             DuplicateHandle( proc, curr, proc, &hndl, 0, TRUE, DUPLICATE_SAME_ACCESS );
283             return hndl;
284         }
285     }
286 }
version(Posix)287 else version (Posix)
288 {
289     private
290     {
291         import core.stdc.errno;
292         import core.sys.posix.semaphore;
293         import core.sys.posix.stdlib; // for malloc, valloc, free, atexit
294         import core.sys.posix.pthread;
295         import core.sys.posix.signal;
296         import core.sys.posix.time;
297 
298         version (Darwin)
299         {
300             import core.sys.darwin.mach.thread_act;
301             import core.sys.darwin.pthread : pthread_mach_thread_np;
302         }
303 
304         version (GNU)
305         {
306             import gcc.builtins;
307         }
308 
309         //
310         // Entry point for POSIX threads
311         //
312         extern (C) void* thread_entryPoint( void* arg ) nothrow
313         {
314             version (Shared)
315             {
316                 import rt.sections;
317                 Thread obj = cast(Thread)(cast(void**)arg)[0];
318                 auto loadedLibraries = (cast(void**)arg)[1];
319                 .free(arg);
320             }
321             else
322             {
323                 Thread obj = cast(Thread)arg;
324             }
325             assert( obj );
326 
327             // loadedLibraries need to be inherited from parent thread
328             // before initilizing GC for TLS (rt_tlsgc_init)
329             version (Shared) inheritLoadedLibraries(loadedLibraries);
330 
331             assert( obj.m_curr is &obj.m_main );
332             obj.m_main.bstack = getStackBottom();
333             obj.m_main.tstack = obj.m_main.bstack;
334             obj.m_tlsgcdata = rt_tlsgc_init();
335 
336             atomicStore!(MemoryOrder.raw)(obj.m_isRunning, true);
337             Thread.setThis(obj); // allocates lazy TLS (see Issue 11981)
338             Thread.add(obj);     // can only receive signals from here on
339             scope (exit)
340             {
341                 Thread.remove(obj);
342                 atomicStore!(MemoryOrder.raw)(obj.m_isRunning, false);
343             }
344             Thread.add(&obj.m_main);
345 
346             static extern (C) void thread_cleanupHandler( void* arg ) nothrow @nogc
347             {
348                 Thread  obj = cast(Thread) arg;
349                 assert( obj );
350 
351                 // NOTE: If the thread terminated abnormally, just set it as
352                 //       not running and let thread_suspendAll remove it from
353                 //       the thread list.  This is safer and is consistent
354                 //       with the Windows thread code.
355                 atomicStore!(MemoryOrder.raw)(obj.m_isRunning,false);
356             }
357 
358             // NOTE: Using void to skip the initialization here relies on
359             //       knowledge of how pthread_cleanup is implemented.  It may
360             //       not be appropriate for all platforms.  However, it does
361             //       avoid the need to link the pthread module.  If any
362             //       implementation actually requires default initialization
363             //       then pthread_cleanup should be restructured to maintain
364             //       the current lack of a link dependency.
365             static if ( __traits( compiles, pthread_cleanup ) )
366             {
367                 pthread_cleanup cleanup = void;
368                 cleanup.push( &thread_cleanupHandler, cast(void*) obj );
369             }
370             else static if ( __traits( compiles, pthread_cleanup_push ) )
371             {
372                 pthread_cleanup_push( &thread_cleanupHandler, cast(void*) obj );
373             }
374             else
375             {
376                 static assert( false, "Platform not supported." );
377             }
378 
379             // NOTE: No GC allocations may occur until the stack pointers have
380             //       been set and Thread.getThis returns a valid reference to
381             //       this thread object (this latter condition is not strictly
382             //       necessary on Windows but it should be followed for the
383             //       sake of consistency).
384 
385             // TODO: Consider putting an auto exception object here (using
386             //       alloca) forOutOfMemoryError plus something to track
387             //       whether an exception is in-flight?
388 
389             void append( Throwable t )
390             {
391                 if ( obj.m_unhandled is null )
392                     obj.m_unhandled = t;
393                 else
394                 {
395                     Throwable last = obj.m_unhandled;
396                     while ( last.next !is null )
397                         last = last.next;
398                     last.next = t;
399                 }
400             }
401 
402             try
403             {
404                 rt_moduleTlsCtor();
405                 try
406                 {
407                     obj.run();
408                 }
409                 catch ( Throwable t )
410                 {
411                     append( t );
412                 }
413                 rt_moduleTlsDtor();
414                 version (Shared) cleanupLoadedLibraries();
415             }
416             catch ( Throwable t )
417             {
418                 append( t );
419             }
420 
421             // NOTE: Normal cleanup is handled by scope(exit).
422 
423             static if ( __traits( compiles, pthread_cleanup ) )
424             {
425                 cleanup.pop( 0 );
426             }
427             else static if ( __traits( compiles, pthread_cleanup_push ) )
428             {
429                 pthread_cleanup_pop( 0 );
430             }
431 
432             return null;
433         }
434 
435 
436         //
437         // Used to track the number of suspended threads
438         //
439         __gshared sem_t suspendCount;
440 
441 
442         extern (C) void thread_suspendHandler( int sig ) nothrow
443         in
444         {
445             assert( sig == suspendSignalNumber );
446         }
447         body
448         {
449             void op(void* sp) nothrow
450             {
451                 // NOTE: Since registers are being pushed and popped from the
452                 //       stack, any other stack data used by this function should
453                 //       be gone before the stack cleanup code is called below.
454                 Thread obj = Thread.getThis();
455                 assert(obj !is null);
456 
457                 if ( !obj.m_lock )
458                 {
459                     obj.m_curr.tstack = getStackTop();
460                 }
461 
462                 sigset_t    sigres = void;
463                 int         status;
464 
465                 status = sigfillset( &sigres );
466                 assert( status == 0 );
467 
468                 status = sigdelset( &sigres, resumeSignalNumber );
469                 assert( status == 0 );
470 
471                 version (FreeBSD) obj.m_suspendagain = false;
472                 status = sem_post( &suspendCount );
473                 assert( status == 0 );
474 
475                 sigsuspend( &sigres );
476 
477                 if ( !obj.m_lock )
478                 {
479                     obj.m_curr.tstack = obj.m_curr.bstack;
480                 }
481             }
482 
483             // avoid deadlocks on FreeBSD, see Issue 13416
484             version (FreeBSD)
485             {
486                 auto obj = Thread.getThis();
487                 if (THR_IN_CRITICAL(obj.m_addr))
488                 {
489                     obj.m_suspendagain = true;
490                     if (sem_post(&suspendCount)) assert(0);
491                     return;
492                 }
493             }
494 
495             callWithStackShell(&op);
496         }
497 
498 
499         extern (C) void thread_resumeHandler( int sig ) nothrow
500         in
501         {
502             assert( sig == resumeSignalNumber );
503         }
504         body
505         {
506 
507         }
508 
509         // HACK libthr internal (thr_private.h) macro, used to
510         // avoid deadlocks in signal handler, see Issue 13416
511         version (FreeBSD) bool THR_IN_CRITICAL(pthread_t p) nothrow @nogc
512         {
513             import core.sys.posix.config : c_long;
514             import core.sys.posix.sys.types : lwpid_t;
515 
516             // If the begin of pthread would be changed in libthr (unlikely)
517             // we'll run into undefined behavior, compare with thr_private.h.
518             static struct pthread
519             {
520                 c_long tid;
521                 static struct umutex { lwpid_t owner; uint flags; uint[2] ceilings; uint[4] spare; }
522                 umutex lock;
523                 uint cycle;
524                 int locklevel;
525                 int critical_count;
526                 // ...
527             }
528             auto priv = cast(pthread*)p;
529             return priv.locklevel > 0 || priv.critical_count > 0;
530         }
531     }
532 }
533 else
534 {
535     // NOTE: This is the only place threading versions are checked.  If a new
536     //       version is added, the module code will need to be searched for
537     //       places where version-specific code may be required.  This can be
538     //       easily accomlished by searching for 'Windows' or 'Posix'.
539     static assert( false, "Unknown threading implementation." );
540 }
541 
542 
543 ///////////////////////////////////////////////////////////////////////////////
544 // Thread
545 ///////////////////////////////////////////////////////////////////////////////
546 
547 
548 /**
549  * This class encapsulates all threading functionality for the D
550  * programming language.  As thread manipulation is a required facility
551  * for garbage collection, all user threads should derive from this
552  * class, and instances of this class should never be explicitly deleted.
553  * A new thread may be created using either derivation or composition, as
554  * in the following example.
555  */
556 class Thread
557 {
558     ///////////////////////////////////////////////////////////////////////////
559     // Initialization
560     ///////////////////////////////////////////////////////////////////////////
561 
562 
563     /**
564      * Initializes a thread object which is associated with a static
565      * D function.
566      *
567      * Params:
568      *  fn = The thread function.
569      *  sz = The stack size for this thread.
570      *
571      * In:
572      *  fn must not be null.
573      */
function()574     this( void function() fn, size_t sz = 0 ) @safe pure nothrow @nogc
575     in
576     {
577         assert( fn );
578     }
579     body
580     {
581         this(sz);
582         () @trusted { m_fn   = fn; }();
583         m_call = Call.FN;
584         m_curr = &m_main;
585     }
586 
587 
588     /**
589      * Initializes a thread object which is associated with a dynamic
590      * D function.
591      *
592      * Params:
593      *  dg = The thread function.
594      *  sz = The stack size for this thread.
595      *
596      * In:
597      *  dg must not be null.
598      */
delegate()599     this( void delegate() dg, size_t sz = 0 ) @safe pure nothrow @nogc
600     in
601     {
602         assert( dg );
603     }
604     body
605     {
606         this(sz);
607         () @trusted { m_dg   = dg; }();
608         m_call = Call.DG;
609         m_curr = &m_main;
610     }
611 
612 
613     /**
614      * Cleans up any remaining resources used by this object.
615      */
~this()616     ~this() nothrow @nogc
617     {
618         if ( m_addr == m_addr.init )
619         {
620             return;
621         }
622 
623         version (Windows)
624         {
625             m_addr = m_addr.init;
626             CloseHandle( m_hndl );
627             m_hndl = m_hndl.init;
628         }
629         else version (Posix)
630         {
631             pthread_detach( m_addr );
632             m_addr = m_addr.init;
633         }
634         version (Darwin)
635         {
636             m_tmach = m_tmach.init;
637         }
638         rt_tlsgc_destroy( m_tlsgcdata );
639         m_tlsgcdata = null;
640     }
641 
642 
643     ///////////////////////////////////////////////////////////////////////////
644     // General Actions
645     ///////////////////////////////////////////////////////////////////////////
646 
647 
648     /**
649      * Starts the thread and invokes the function or delegate passed upon
650      * construction.
651      *
652      * In:
653      *  This routine may only be called once per thread instance.
654      *
655      * Throws:
656      *  ThreadException if the thread fails to start.
657      */
start()658     final Thread start() nothrow
659     in
660     {
661         assert( !next && !prev );
662     }
663     body
664     {
665         auto wasThreaded  = multiThreadedFlag;
666         multiThreadedFlag = true;
scope(failure)667         scope( failure )
668         {
669             if ( !wasThreaded )
670                 multiThreadedFlag = false;
671         }
672 
version(Windows)673         version (Windows) {} else
version(Posix)674         version (Posix)
675         {
676             pthread_attr_t  attr;
677 
678             if ( pthread_attr_init( &attr ) )
679                 onThreadError( "Error initializing thread attributes" );
680             if ( m_sz && pthread_attr_setstacksize( &attr, m_sz ) )
681                 onThreadError( "Error initializing thread stack size" );
682         }
683 
version(Windows)684         version (Windows)
685         {
686             // NOTE: If a thread is just executing DllMain()
687             //       while another thread is started here, it holds an OS internal
688             //       lock that serializes DllMain with CreateThread. As the code
689             //       might request a synchronization on slock (e.g. in thread_findByAddr()),
690             //       we cannot hold that lock while creating the thread without
691             //       creating a deadlock
692             //
693             // Solution: Create the thread in suspended state and then
694             //       add and resume it with slock acquired
695             assert(m_sz <= uint.max, "m_sz must be less than or equal to uint.max");
696             m_hndl = cast(HANDLE) _beginthreadex( null, cast(uint) m_sz, &thread_entryPoint, cast(void*) this, CREATE_SUSPENDED, &m_addr );
697             if ( cast(size_t) m_hndl == 0 )
698                 onThreadError( "Error creating thread" );
699         }
700 
701         slock.lock_nothrow();
702         scope(exit) slock.unlock_nothrow();
703         {
704             ++nAboutToStart;
705             pAboutToStart = cast(Thread*)realloc(pAboutToStart, Thread.sizeof * nAboutToStart);
706             pAboutToStart[nAboutToStart - 1] = this;
version(Windows)707             version (Windows)
708             {
709                 if ( ResumeThread( m_hndl ) == -1 )
710                     onThreadError( "Error resuming thread" );
711             }
version(Posix)712             else version (Posix)
713             {
714                 // NOTE: This is also set to true by thread_entryPoint, but set it
715                 //       here as well so the calling thread will see the isRunning
716                 //       state immediately.
717                 atomicStore!(MemoryOrder.raw)(m_isRunning, true);
718                 scope( failure ) atomicStore!(MemoryOrder.raw)(m_isRunning, false);
719 
720                 version (Shared)
721                 {
722                     import rt.sections;
723                     auto libs = pinLoadedLibraries();
724                     auto ps = cast(void**).malloc(2 * size_t.sizeof);
725                     if (ps is null) onOutOfMemoryError();
726                     ps[0] = cast(void*)this;
727                     ps[1] = cast(void*)libs;
728                     if ( pthread_create( &m_addr, &attr, &thread_entryPoint, ps ) != 0 )
729                     {
730                         unpinLoadedLibraries(libs);
731                         .free(ps);
732                         onThreadError( "Error creating thread" );
733                     }
734                 }
735                 else
736                 {
737                     if ( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 )
738                         onThreadError( "Error creating thread" );
739                 }
740             }
version(Darwin)741             version (Darwin)
742             {
743                 m_tmach = pthread_mach_thread_np( m_addr );
744                 if ( m_tmach == m_tmach.init )
745                     onThreadError( "Error creating thread" );
746             }
747 
748             return this;
749         }
750     }
751 
752     /**
753      * Waits for this thread to complete.  If the thread terminated as the
754      * result of an unhandled exception, this exception will be rethrown.
755      *
756      * Params:
757      *  rethrow = Rethrow any unhandled exception which may have caused this
758      *            thread to terminate.
759      *
760      * Throws:
761      *  ThreadException if the operation fails.
762      *  Any exception not handled by the joined thread.
763      *
764      * Returns:
765      *  Any exception not handled by this thread if rethrow = false, null
766      *  otherwise.
767      */
768     final Throwable join( bool rethrow = true )
769     {
version(Windows)770         version (Windows)
771         {
772             if ( WaitForSingleObject( m_hndl, INFINITE ) != WAIT_OBJECT_0 )
773                 throw new ThreadException( "Unable to join thread" );
774             // NOTE: m_addr must be cleared before m_hndl is closed to avoid
775             //       a race condition with isRunning. The operation is done
776             //       with atomicStore to prevent compiler reordering.
777             atomicStore!(MemoryOrder.raw)(*cast(shared)&m_addr, m_addr.init);
778             CloseHandle( m_hndl );
779             m_hndl = m_hndl.init;
780         }
version(Posix)781         else version (Posix)
782         {
783             if ( pthread_join( m_addr, null ) != 0 )
784                 throw new ThreadException( "Unable to join thread" );
785             // NOTE: pthread_join acts as a substitute for pthread_detach,
786             //       which is normally called by the dtor.  Setting m_addr
787             //       to zero ensures that pthread_detach will not be called
788             //       on object destruction.
789             m_addr = m_addr.init;
790         }
791         if ( m_unhandled )
792         {
793             if ( rethrow )
794                 throw m_unhandled;
795             return m_unhandled;
796         }
797         return null;
798     }
799 
800 
801     ///////////////////////////////////////////////////////////////////////////
802     // General Properties
803     ///////////////////////////////////////////////////////////////////////////
804 
805 
806     /**
807      * Gets the OS identifier for this thread.
808      *
809      * Returns:
810      *  If the thread hasn't been started yet, returns $(LREF ThreadID)$(D.init).
811      *  Otherwise, returns the result of $(D GetCurrentThreadId) on Windows,
812      *  and $(D pthread_self) on POSIX.
813      *
814      *  The value is unique for the current process.
815      */
id()816     final @property ThreadID id() @safe @nogc
817     {
818         synchronized( this )
819         {
820             return m_addr;
821         }
822     }
823 
824 
825     /**
826      * Gets the user-readable label for this thread.
827      *
828      * Returns:
829      *  The name of this thread.
830      */
name()831     final @property string name() @safe @nogc
832     {
833         synchronized( this )
834         {
835             return m_name;
836         }
837     }
838 
839 
840     /**
841      * Sets the user-readable label for this thread.
842      *
843      * Params:
844      *  val = The new name of this thread.
845      */
name(string val)846     final @property void name( string val ) @safe @nogc
847     {
848         synchronized( this )
849         {
850             m_name = val;
851         }
852     }
853 
854 
855     /**
856      * Gets the daemon status for this thread.  While the runtime will wait for
857      * all normal threads to complete before tearing down the process, daemon
858      * threads are effectively ignored and thus will not prevent the process
859      * from terminating.  In effect, daemon threads will be terminated
860      * automatically by the OS when the process exits.
861      *
862      * Returns:
863      *  true if this is a daemon thread.
864      */
isDaemon()865     final @property bool isDaemon() @safe @nogc
866     {
867         synchronized( this )
868         {
869             return m_isDaemon;
870         }
871     }
872 
873 
874     /**
875      * Sets the daemon status for this thread.  While the runtime will wait for
876      * all normal threads to complete before tearing down the process, daemon
877      * threads are effectively ignored and thus will not prevent the process
878      * from terminating.  In effect, daemon threads will be terminated
879      * automatically by the OS when the process exits.
880      *
881      * Params:
882      *  val = The new daemon status for this thread.
883      */
isDaemon(bool val)884     final @property void isDaemon( bool val ) @safe @nogc
885     {
886         synchronized( this )
887         {
888             m_isDaemon = val;
889         }
890     }
891 
892 
893     /**
894      * Tests whether this thread is running.
895      *
896      * Returns:
897      *  true if the thread is running, false if not.
898      */
isRunning()899     final @property bool isRunning() nothrow @nogc
900     {
901         if ( m_addr == m_addr.init )
902         {
903             return false;
904         }
905 
906         version (Windows)
907         {
908             uint ecode = 0;
909             GetExitCodeThread( m_hndl, &ecode );
910             return ecode == STILL_ACTIVE;
911         }
912         else version (Posix)
913         {
914             return atomicLoad(m_isRunning);
915         }
916     }
917 
918 
919     ///////////////////////////////////////////////////////////////////////////
920     // Thread Priority Actions
921     ///////////////////////////////////////////////////////////////////////////
922 
version(Windows)923     version (Windows)
924     {
925         @property static int PRIORITY_MIN() @nogc nothrow pure @safe
926         {
927             return THREAD_PRIORITY_IDLE;
928         }
929 
930         @property static const(int) PRIORITY_MAX() @nogc nothrow pure @safe
931         {
932             return THREAD_PRIORITY_TIME_CRITICAL;
933         }
934 
935         @property static int PRIORITY_DEFAULT() @nogc nothrow pure @safe
936         {
937             return THREAD_PRIORITY_NORMAL;
938         }
939     }
940     else
941     {
942         private struct Priority
943         {
944             int PRIORITY_MIN = int.min;
945             int PRIORITY_DEFAULT = int.min;
946             int PRIORITY_MAX = int.min;
947         }
948 
949         /*
950         Lazily loads one of the members stored in a hidden global variable of
951         type `Priority`. Upon the first access of either member, the entire
952         `Priority` structure is initialized. Multiple initializations from
953         different threads calling this function are tolerated.
954 
955         `which` must be one of `PRIORITY_MIN`, `PRIORITY_DEFAULT`,
956         `PRIORITY_MAX`.
957         */
loadGlobal(string which)958         private static int loadGlobal(string which)()
959         {
960             static shared Priority cache;
961             auto local = atomicLoad(mixin("cache." ~ which));
962             if (local != local.min) return local;
963             // There will be benign races
964             cache = loadPriorities;
965             return atomicLoad(mixin("cache." ~ which));
966         }
967 
968         /*
969         Loads all priorities and returns them as a `Priority` structure. This
970         function is thread-neutral.
971         */
loadPriorities()972         private static Priority loadPriorities() @nogc nothrow @trusted
973         {
974             Priority result;
975             version (Solaris)
976             {
977                 pcparms_t pcParms;
978                 pcinfo_t pcInfo;
979 
980                 pcParms.pc_cid = PC_CLNULL;
981                 if (priocntl(idtype_t.P_PID, P_MYID, PC_GETPARMS, &pcParms) == -1)
982                     assert( 0, "Unable to get scheduling class" );
983 
984                 pcInfo.pc_cid = pcParms.pc_cid;
985                 // PC_GETCLINFO ignores the first two args, use dummy values
986                 if (priocntl(idtype_t.P_PID, 0, PC_GETCLINFO, &pcInfo) == -1)
987                     assert( 0, "Unable to get scheduling class info" );
988 
989                 pri_t* clparms = cast(pri_t*)&pcParms.pc_clparms;
990                 pri_t* clinfo = cast(pri_t*)&pcInfo.pc_clinfo;
991 
992                 result.PRIORITY_MAX = clparms[0];
993 
994                 if (pcInfo.pc_clname == "RT")
995                 {
996                     m_isRTClass = true;
997 
998                     // For RT class, just assume it can't be changed
999                     result.PRIORITY_MIN = clparms[0];
1000                     result.PRIORITY_DEFAULT = clparms[0];
1001                 }
1002                 else
1003                 {
1004                     m_isRTClass = false;
1005 
1006                     // For all other scheduling classes, there are
1007                     // two key values -- uprilim and maxupri.
1008                     // maxupri is the maximum possible priority defined
1009                     // for the scheduling class, and valid priorities
1010                     // range are in [-maxupri, maxupri].
1011                     //
1012                     // However, uprilim is an upper limit that the
1013                     // current thread can set for the current scheduling
1014                     // class, which can be less than maxupri.  As such,
1015                     // use this value for priorityMax since this is
1016                     // the effective maximum.
1017 
1018                     // maxupri
1019                     result.PRIORITY_MIN = -clinfo[0];
1020                     // by definition
1021                     result.PRIORITY_DEFAULT = 0;
1022                 }
1023             }
1024             else version (Posix)
1025             {
1026                 int         policy;
1027                 sched_param param;
1028                 pthread_getschedparam( pthread_self(), &policy, &param ) == 0
1029                     || assert(0, "Internal error in pthread_getschedparam");
1030 
1031                 result.PRIORITY_MIN = sched_get_priority_min( policy );
1032                 result.PRIORITY_MIN != -1
1033                     || assert(0, "Internal error in sched_get_priority_min");
1034                 result.PRIORITY_DEFAULT = param.sched_priority;
1035                 result.PRIORITY_MAX = sched_get_priority_max( policy );
1036                 result.PRIORITY_MAX != -1 ||
1037                     assert(0, "Internal error in sched_get_priority_max");
1038             }
1039             else
1040             {
1041                 static assert(0, "Your code here.");
1042             }
1043             return result;
1044         }
1045 
1046         /**
1047          * The minimum scheduling priority that may be set for a thread.  On
1048          * systems where multiple scheduling policies are defined, this value
1049          * represents the minimum valid priority for the scheduling policy of
1050          * the process.
1051          */
PRIORITY_MIN()1052         @property static int PRIORITY_MIN() @nogc nothrow pure @trusted
1053         {
1054             return (cast(int function() @nogc nothrow pure @safe)
1055                 &loadGlobal!"PRIORITY_MIN")();
1056         }
1057 
1058         /**
1059          * The maximum scheduling priority that may be set for a thread.  On
1060          * systems where multiple scheduling policies are defined, this value
1061          * represents the maximum valid priority for the scheduling policy of
1062          * the process.
1063          */
PRIORITY_MAX()1064         @property static const(int) PRIORITY_MAX() @nogc nothrow pure @trusted
1065         {
1066             return (cast(int function() @nogc nothrow pure @safe)
1067                 &loadGlobal!"PRIORITY_MAX")();
1068         }
1069 
1070         /**
1071          * The default scheduling priority that is set for a thread.  On
1072          * systems where multiple scheduling policies are defined, this value
1073          * represents the default priority for the scheduling policy of
1074          * the process.
1075          */
PRIORITY_DEFAULT()1076         @property static int PRIORITY_DEFAULT() @nogc nothrow pure @trusted
1077         {
1078             return (cast(int function() @nogc nothrow pure @safe)
1079                 &loadGlobal!"PRIORITY_DEFAULT")();
1080         }
1081     }
1082 
version(NetBSD)1083     version (NetBSD)
1084     {
1085         //NetBSD does not support priority for default policy
1086         // and it is not possible change policy without root access
1087         int fakePriority = int.max;
1088     }
1089 
1090     /**
1091      * Gets the scheduling priority for the associated thread.
1092      *
1093      * Note: Getting the priority of a thread that already terminated
1094      * might return the default priority.
1095      *
1096      * Returns:
1097      *  The scheduling priority of this thread.
1098      */
priority()1099     final @property int priority()
1100     {
1101         version (Windows)
1102         {
1103             return GetThreadPriority( m_hndl );
1104         }
1105         else version (NetBSD)
1106         {
1107            return fakePriority==int.max? PRIORITY_DEFAULT : fakePriority;
1108         }
1109         else version (Posix)
1110         {
1111             int         policy;
1112             sched_param param;
1113 
1114             if (auto err = pthread_getschedparam(m_addr, &policy, &param))
1115             {
1116                 // ignore error if thread is not running => Bugzilla 8960
1117                 if (!atomicLoad(m_isRunning)) return PRIORITY_DEFAULT;
1118                 throw new ThreadException("Unable to get thread priority");
1119             }
1120             return param.sched_priority;
1121         }
1122     }
1123 
1124 
1125     /**
1126      * Sets the scheduling priority for the associated thread.
1127      *
1128      * Note: Setting the priority of a thread that already terminated
1129      * might have no effect.
1130      *
1131      * Params:
1132      *  val = The new scheduling priority of this thread.
1133      */
priority(int val)1134     final @property void priority( int val )
1135     in
1136     {
1137         assert(val >= PRIORITY_MIN);
1138         assert(val <= PRIORITY_MAX);
1139     }
1140     body
1141     {
version(Windows)1142         version (Windows)
1143         {
1144             if ( !SetThreadPriority( m_hndl, val ) )
1145                 throw new ThreadException( "Unable to set thread priority" );
1146         }
version(Solaris)1147         else version (Solaris)
1148         {
1149             // the pthread_setschedprio(3c) and pthread_setschedparam functions
1150             // are broken for the default (TS / time sharing) scheduling class.
1151             // instead, we use priocntl(2) which gives us the desired behavior.
1152 
1153             // We hardcode the min and max priorities to the current value
1154             // so this is a no-op for RT threads.
1155             if (m_isRTClass)
1156                 return;
1157 
1158             pcparms_t   pcparm;
1159 
1160             pcparm.pc_cid = PC_CLNULL;
1161             if (priocntl(idtype_t.P_LWPID, P_MYID, PC_GETPARMS, &pcparm) == -1)
1162                 throw new ThreadException( "Unable to get scheduling class" );
1163 
1164             pri_t* clparms = cast(pri_t*)&pcparm.pc_clparms;
1165 
1166             // clparms is filled in by the PC_GETPARMS call, only necessary
1167             // to adjust the element that contains the thread priority
1168             clparms[1] = cast(pri_t) val;
1169 
1170             if (priocntl(idtype_t.P_LWPID, P_MYID, PC_SETPARMS, &pcparm) == -1)
1171                 throw new ThreadException( "Unable to set scheduling class" );
1172         }
version(NetBSD)1173         else version (NetBSD)
1174         {
1175            fakePriority = val;
1176         }
version(Posix)1177         else version (Posix)
1178         {
1179             static if (__traits(compiles, pthread_setschedprio))
1180             {
1181                 if (auto err = pthread_setschedprio(m_addr, val))
1182                 {
1183                     // ignore error if thread is not running => Bugzilla 8960
1184                     if (!atomicLoad(m_isRunning)) return;
1185                     throw new ThreadException("Unable to set thread priority");
1186                 }
1187             }
1188             else
1189             {
1190                 // NOTE: pthread_setschedprio is not implemented on Darwin, FreeBSD or DragonFlyBSD, so use
1191                 //       the more complicated get/set sequence below.
1192                 int         policy;
1193                 sched_param param;
1194 
1195                 if (auto err = pthread_getschedparam(m_addr, &policy, &param))
1196                 {
1197                     // ignore error if thread is not running => Bugzilla 8960
1198                     if (!atomicLoad(m_isRunning)) return;
1199                     throw new ThreadException("Unable to set thread priority");
1200                 }
1201                 param.sched_priority = val;
1202                 if (auto err = pthread_setschedparam(m_addr, policy, &param))
1203                 {
1204                     // ignore error if thread is not running => Bugzilla 8960
1205                     if (!atomicLoad(m_isRunning)) return;
1206                     throw new ThreadException("Unable to set thread priority");
1207                 }
1208             }
1209         }
1210     }
1211 
1212 
1213     unittest
1214     {
1215         auto thr = Thread.getThis();
1216         immutable prio = thr.priority;
1217         scope (exit) thr.priority = prio;
1218 
1219         assert(prio == PRIORITY_DEFAULT);
1220         assert(prio >= PRIORITY_MIN && prio <= PRIORITY_MAX);
1221         thr.priority = PRIORITY_MIN;
1222         assert(thr.priority == PRIORITY_MIN);
1223         thr.priority = PRIORITY_MAX;
1224         assert(thr.priority == PRIORITY_MAX);
1225     }
1226 
1227     unittest // Bugzilla 8960
1228     {
1229         import core.sync.semaphore;
1230 
1231         auto thr = new Thread({});
1232         thr.start();
1233         Thread.sleep(1.msecs);       // wait a little so the thread likely has finished
1234         thr.priority = PRIORITY_MAX; // setting priority doesn't cause error
1235         auto prio = thr.priority;    // getting priority doesn't cause error
1236         assert(prio >= PRIORITY_MIN && prio <= PRIORITY_MAX);
1237     }
1238 
1239     ///////////////////////////////////////////////////////////////////////////
1240     // Actions on Calling Thread
1241     ///////////////////////////////////////////////////////////////////////////
1242 
1243 
1244     /**
1245      * Suspends the calling thread for at least the supplied period.  This may
1246      * result in multiple OS calls if period is greater than the maximum sleep
1247      * duration supported by the operating system.
1248      *
1249      * Params:
1250      *  val = The minimum duration the calling thread should be suspended.
1251      *
1252      * In:
1253      *  period must be non-negative.
1254      *
1255      * Example:
1256      * ------------------------------------------------------------------------
1257      *
1258      * Thread.sleep( dur!("msecs")( 50 ) );  // sleep for 50 milliseconds
1259      * Thread.sleep( dur!("seconds")( 5 ) ); // sleep for 5 seconds
1260      *
1261      * ------------------------------------------------------------------------
1262      */
sleep(Duration val)1263     static void sleep( Duration val ) @nogc nothrow
1264     in
1265     {
1266         assert( !val.isNegative );
1267     }
1268     body
1269     {
version(Windows)1270         version (Windows)
1271         {
1272             auto maxSleepMillis = dur!("msecs")( uint.max - 1 );
1273 
1274             // avoid a non-zero time to be round down to 0
1275             if ( val > dur!"msecs"( 0 ) && val < dur!"msecs"( 1 ) )
1276                 val = dur!"msecs"( 1 );
1277 
1278             // NOTE: In instances where all other threads in the process have a
1279             //       lower priority than the current thread, the current thread
1280             //       will not yield with a sleep time of zero.  However, unlike
1281             //       yield(), the user is not asking for a yield to occur but
1282             //       only for execution to suspend for the requested interval.
1283             //       Therefore, expected performance may not be met if a yield
1284             //       is forced upon the user.
1285             while ( val > maxSleepMillis )
1286             {
1287                 Sleep( cast(uint)
1288                        maxSleepMillis.total!"msecs" );
1289                 val -= maxSleepMillis;
1290             }
1291             Sleep( cast(uint) val.total!"msecs" );
1292         }
version(Posix)1293         else version (Posix)
1294         {
1295             timespec tin  = void;
1296             timespec tout = void;
1297 
1298             val.split!("seconds", "nsecs")(tin.tv_sec, tin.tv_nsec);
1299             if ( val.total!"seconds" > tin.tv_sec.max )
1300                 tin.tv_sec  = tin.tv_sec.max;
1301             while ( true )
1302             {
1303                 if ( !nanosleep( &tin, &tout ) )
1304                     return;
1305                 if ( errno != EINTR )
1306                     assert(0, "Unable to sleep for the specified duration");
1307                 tin = tout;
1308             }
1309         }
1310     }
1311 
1312 
1313     /**
1314      * Forces a context switch to occur away from the calling thread.
1315      */
yield()1316     static void yield() @nogc nothrow
1317     {
1318         version (Windows)
1319             SwitchToThread();
1320         else version (Posix)
1321             sched_yield();
1322     }
1323 
1324 
1325     ///////////////////////////////////////////////////////////////////////////
1326     // Thread Accessors
1327     ///////////////////////////////////////////////////////////////////////////
1328 
1329     /**
1330      * Provides a reference to the calling thread.
1331      *
1332      * Returns:
1333      *  The thread object representing the calling thread.  The result of
1334      *  deleting this object is undefined.  If the current thread is not
1335      *  attached to the runtime, a null reference is returned.
1336      */
getThis()1337     static Thread getThis() @safe nothrow @nogc
1338     {
1339         // NOTE: This function may not be called until thread_init has
1340         //       completed.  See thread_suspendAll for more information
1341         //       on why this might occur.
1342         return sm_this;
1343     }
1344 
1345 
1346     /**
1347      * Provides a list of all threads currently being tracked by the system.
1348      * Note that threads in the returned array might no longer run (see
1349      * $(D Thread.)$(LREF isRunning)).
1350      *
1351      * Returns:
1352      *  An array containing references to all threads currently being
1353      *  tracked by the system.  The result of deleting any contained
1354      *  objects is undefined.
1355      */
getAll()1356     static Thread[] getAll()
1357     {
1358         static void resize(ref Thread[] buf, size_t nlen)
1359         {
1360             buf.length = nlen;
1361         }
1362         return getAllImpl!resize();
1363     }
1364 
1365 
1366     /**
1367      * Operates on all threads currently being tracked by the system.  The
1368      * result of deleting any Thread object is undefined.
1369      * Note that threads passed to the callback might no longer run (see
1370      * $(D Thread.)$(LREF isRunning)).
1371      *
1372      * Params:
1373      *  dg = The supplied code as a delegate.
1374      *
1375      * Returns:
1376      *  Zero if all elemented are visited, nonzero if not.
1377      */
opApply(scope int delegate (ref Thread)dg)1378     static int opApply(scope int delegate(ref Thread) dg)
1379     {
1380         import core.stdc.stdlib : free, realloc;
1381 
1382         static void resize(ref Thread[] buf, size_t nlen)
1383         {
1384             buf = (cast(Thread*)realloc(buf.ptr, nlen * Thread.sizeof))[0 .. nlen];
1385         }
1386         auto buf = getAllImpl!resize;
1387         scope(exit) if (buf.ptr) free(buf.ptr);
1388 
1389         foreach (t; buf)
1390         {
1391             if (auto res = dg(t))
1392                 return res;
1393         }
1394         return 0;
1395     }
1396 
1397     unittest
1398     {
1399         auto t1 = new Thread({
1400             foreach (_; 0 .. 20)
1401                 Thread.getAll;
1402         }).start;
1403         auto t2 = new Thread({
1404             foreach (_; 0 .. 20)
1405                 GC.collect;
1406         }).start;
1407         t1.join();
1408         t2.join();
1409     }
1410 
getAllImpl(alias resize)1411     private static Thread[] getAllImpl(alias resize)()
1412     {
1413         import core.atomic;
1414 
1415         Thread[] buf;
1416         while (true)
1417         {
1418             immutable len = atomicLoad!(MemoryOrder.raw)(*cast(shared)&sm_tlen);
1419             resize(buf, len);
1420             assert(buf.length == len);
1421             synchronized (slock)
1422             {
1423                 if (len == sm_tlen)
1424                 {
1425                     size_t pos;
1426                     for (Thread t = sm_tbeg; t; t = t.next)
1427                         buf[pos++] = t;
1428                     return buf;
1429                 }
1430             }
1431         }
1432     }
1433 
1434     ///////////////////////////////////////////////////////////////////////////
1435     // Stuff That Should Go Away
1436     ///////////////////////////////////////////////////////////////////////////
1437 
1438 
1439 private:
1440     //
1441     // Initializes a thread object which has no associated executable function.
1442     // This is used for the main thread initialized in thread_init().
1443     //
1444     this(size_t sz = 0) @safe pure nothrow @nogc
1445     {
1446         if (sz)
1447         {
version(Posix)1448             version (Posix)
1449             {
1450                 // stack size must be a multiple of PAGESIZE
1451                 sz += PAGESIZE - 1;
1452                 sz -= sz % PAGESIZE;
1453                 // and at least PTHREAD_STACK_MIN
1454                 if (PTHREAD_STACK_MIN > sz)
1455                     sz = PTHREAD_STACK_MIN;
1456             }
1457             m_sz = sz;
1458         }
1459         m_call = Call.NO;
1460         m_curr = &m_main;
1461     }
1462 
1463 
1464     //
1465     // Thread entry point.  Invokes the function or delegate passed on
1466     // construction (if any).
1467     //
run()1468     final void run()
1469     {
1470         switch ( m_call )
1471         {
1472         case Call.FN:
1473             m_fn();
1474             break;
1475         case Call.DG:
1476             m_dg();
1477             break;
1478         default:
1479             break;
1480         }
1481     }
1482 
1483 
1484 private:
1485     //
1486     // The type of routine passed on thread construction.
1487     //
1488     enum Call
1489     {
1490         NO,
1491         FN,
1492         DG
1493     }
1494 
1495 
1496     //
1497     // Standard types
1498     //
version(Windows)1499     version (Windows)
1500     {
1501         alias TLSKey = uint;
1502     }
version(Posix)1503     else version (Posix)
1504     {
1505         alias TLSKey = pthread_key_t;
1506     }
1507 
1508 
1509     //
1510     // Local storage
1511     //
1512     static Thread       sm_this;
1513 
1514 
1515     //
1516     // Main process thread
1517     //
1518     __gshared Thread    sm_main;
1519 
version(FreeBSD)1520     version (FreeBSD)
1521     {
1522         // set when suspend failed and should be retried, see Issue 13416
1523         shared bool m_suspendagain;
1524     }
1525 
1526 
1527     //
1528     // Standard thread data
1529     //
version(Windows)1530     version (Windows)
1531     {
1532         HANDLE          m_hndl;
1533     }
version(Darwin)1534     else version (Darwin)
1535     {
1536         mach_port_t     m_tmach;
1537     }
1538     ThreadID            m_addr;
1539     Call                m_call;
1540     string              m_name;
1541     union
1542     {
1543         void function() m_fn;
1544         void delegate() m_dg;
1545     }
1546     size_t              m_sz;
version(Posix)1547     version (Posix)
1548     {
1549         shared bool     m_isRunning;
1550     }
1551     bool                m_isDaemon;
1552     bool                m_isInCriticalRegion;
1553     Throwable           m_unhandled;
1554 
version(Solaris)1555     version (Solaris)
1556     {
1557         __gshared bool m_isRTClass;
1558     }
1559 
1560 private:
1561     ///////////////////////////////////////////////////////////////////////////
1562     // Storage of Active Thread
1563     ///////////////////////////////////////////////////////////////////////////
1564 
1565 
1566     //
1567     // Sets a thread-local reference to the current thread object.
1568     //
setThis(Thread t)1569     static void setThis( Thread t ) nothrow @nogc
1570     {
1571         sm_this = t;
1572     }
1573 
1574 
1575 private:
1576     ///////////////////////////////////////////////////////////////////////////
1577     // Thread Context and GC Scanning Support
1578     ///////////////////////////////////////////////////////////////////////////
1579 
1580 
pushContext(Context * c)1581     final void pushContext( Context* c ) nothrow @nogc
1582     in
1583     {
1584         assert( !c.within );
1585     }
1586     body
1587     {
1588         m_curr.ehContext = swapContext(c.ehContext);
1589         c.within = m_curr;
1590         m_curr = c;
1591     }
1592 
1593 
popContext()1594     final void popContext() nothrow @nogc
1595     in
1596     {
1597         assert( m_curr && m_curr.within );
1598     }
1599     body
1600     {
1601         Context* c = m_curr;
1602         m_curr = c.within;
1603         c.ehContext = swapContext(m_curr.ehContext);
1604         c.within = null;
1605     }
1606 
1607 
topContext()1608     final Context* topContext() nothrow @nogc
1609     in
1610     {
1611         assert( m_curr );
1612     }
1613     body
1614     {
1615         return m_curr;
1616     }
1617 
1618 
1619     static struct Context
1620     {
1621         void*           bstack,
1622                         tstack;
1623 
1624         /// Slot for the EH implementation to keep some state for each stack
1625         /// (will be necessary for exception chaining, etc.). Opaque as far as
1626         /// we are concerned here.
1627         void*           ehContext;
1628 
1629         Context*        within;
1630         Context*        next,
1631                         prev;
1632     }
1633 
1634 
1635     Context             m_main;
1636     Context*            m_curr;
1637     bool                m_lock;
1638     void*               m_tlsgcdata;
1639 
version(Windows)1640     version (Windows)
1641     {
1642       version (X86)
1643       {
1644         uint[8]         m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
1645       }
1646       else version (X86_64)
1647       {
1648         ulong[16]       m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax
1649                                // r8,r9,r10,r11,r12,r13,r14,r15
1650       }
1651       else
1652       {
1653         static assert(false, "Architecture not supported." );
1654       }
1655     }
version(Darwin)1656     else version (Darwin)
1657     {
1658       version (X86)
1659       {
1660         uint[8]         m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
1661       }
1662       else version (X86_64)
1663       {
1664         ulong[16]       m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax
1665                                // r8,r9,r10,r11,r12,r13,r14,r15
1666       }
1667       else
1668       {
1669         static assert(false, "Architecture not supported." );
1670       }
1671     }
1672 
1673 
1674 private:
1675     ///////////////////////////////////////////////////////////////////////////
1676     // GC Scanning Support
1677     ///////////////////////////////////////////////////////////////////////////
1678 
1679 
1680     // NOTE: The GC scanning process works like so:
1681     //
1682     //          1. Suspend all threads.
1683     //          2. Scan the stacks of all suspended threads for roots.
1684     //          3. Resume all threads.
1685     //
1686     //       Step 1 and 3 require a list of all threads in the system, while
1687     //       step 2 requires a list of all thread stacks (each represented by
1688     //       a Context struct).  Traditionally, there was one stack per thread
1689     //       and the Context structs were not necessary.  However, Fibers have
1690     //       changed things so that each thread has its own 'main' stack plus
1691     //       an arbitrary number of nested stacks (normally referenced via
1692     //       m_curr).  Also, there may be 'free-floating' stacks in the system,
1693     //       which are Fibers that are not currently executing on any specific
1694     //       thread but are still being processed and still contain valid
1695     //       roots.
1696     //
1697     //       To support all of this, the Context struct has been created to
1698     //       represent a stack range, and a global list of Context structs has
1699     //       been added to enable scanning of these stack ranges.  The lifetime
1700     //       (and presence in the Context list) of a thread's 'main' stack will
1701     //       be equivalent to the thread's lifetime.  So the Ccontext will be
1702     //       added to the list on thread entry, and removed from the list on
1703     //       thread exit (which is essentially the same as the presence of a
1704     //       Thread object in its own global list).  The lifetime of a Fiber's
1705     //       context, however, will be tied to the lifetime of the Fiber object
1706     //       itself, and Fibers are expected to add/remove their Context struct
1707     //       on construction/deletion.
1708 
1709 
1710     //
1711     // All use of the global thread lists/array should synchronize on this lock.
1712     //
1713     // Careful as the GC acquires this lock after the GC lock to suspend all
1714     // threads any GC usage with slock held can result in a deadlock through
1715     // lock order inversion.
slock()1716     @property static Mutex slock() nothrow @nogc
1717     {
1718         return cast(Mutex)_slock.ptr;
1719     }
1720 
criticalRegionLock()1721     @property static Mutex criticalRegionLock() nothrow @nogc
1722     {
1723         return cast(Mutex)_criticalRegionLock.ptr;
1724     }
1725 
1726     __gshared align(mutexAlign) void[mutexClassInstanceSize] _slock;
1727     __gshared align(mutexAlign) void[mutexClassInstanceSize] _criticalRegionLock;
1728 
initLocks()1729     static void initLocks()
1730     {
1731         _slock[] = typeid(Mutex).initializer[];
1732         (cast(Mutex)_slock.ptr).__ctor();
1733 
1734         _criticalRegionLock[] = typeid(Mutex).initializer[];
1735         (cast(Mutex)_criticalRegionLock.ptr).__ctor();
1736     }
1737 
termLocks()1738     static void termLocks()
1739     {
1740         (cast(Mutex)_slock.ptr).__dtor();
1741         (cast(Mutex)_criticalRegionLock.ptr).__dtor();
1742     }
1743 
1744     __gshared Context*  sm_cbeg;
1745 
1746     __gshared Thread    sm_tbeg;
1747     __gshared size_t    sm_tlen;
1748 
1749     // can't use rt.util.array in public code
1750     __gshared Thread* pAboutToStart;
1751     __gshared size_t nAboutToStart;
1752 
1753     //
1754     // Used for ordering threads in the global thread list.
1755     //
1756     Thread              prev;
1757     Thread              next;
1758 
1759 
1760     ///////////////////////////////////////////////////////////////////////////
1761     // Global Context List Operations
1762     ///////////////////////////////////////////////////////////////////////////
1763 
1764 
1765     //
1766     // Add a context to the global context list.
1767     //
add(Context * c)1768     static void add( Context* c ) nothrow @nogc
1769     in
1770     {
1771         assert( c );
1772         assert( !c.next && !c.prev );
1773     }
1774     body
1775     {
1776         slock.lock_nothrow();
1777         scope(exit) slock.unlock_nothrow();
1778         assert(!suspendDepth); // must be 0 b/c it's only set with slock held
1779 
1780         if (sm_cbeg)
1781         {
1782             c.next = sm_cbeg;
1783             sm_cbeg.prev = c;
1784         }
1785         sm_cbeg = c;
1786     }
1787 
1788 
1789     //
1790     // Remove a context from the global context list.
1791     //
1792     // This assumes slock being acquired. This isn't done here to
1793     // avoid double locking when called from remove(Thread)
remove(Context * c)1794     static void remove( Context* c ) nothrow @nogc
1795     in
1796     {
1797         assert( c );
1798         assert( c.next || c.prev );
1799     }
1800     body
1801     {
1802         if ( c.prev )
1803             c.prev.next = c.next;
1804         if ( c.next )
1805             c.next.prev = c.prev;
1806         if ( sm_cbeg == c )
1807             sm_cbeg = c.next;
1808         // NOTE: Don't null out c.next or c.prev because opApply currently
1809         //       follows c.next after removing a node.  This could be easily
1810         //       addressed by simply returning the next node from this
1811         //       function, however, a context should never be re-added to the
1812         //       list anyway and having next and prev be non-null is a good way
1813         //       to ensure that.
1814     }
1815 
1816 
1817     ///////////////////////////////////////////////////////////////////////////
1818     // Global Thread List Operations
1819     ///////////////////////////////////////////////////////////////////////////
1820 
1821 
1822     //
1823     // Add a thread to the global thread list.
1824     //
1825     static void add( Thread t, bool rmAboutToStart = true ) nothrow @nogc
1826     in
1827     {
1828         assert( t );
1829         assert( !t.next && !t.prev );
1830     }
1831     body
1832     {
1833         slock.lock_nothrow();
1834         scope(exit) slock.unlock_nothrow();
1835         assert(t.isRunning); // check this with slock to ensure pthread_create already returned
1836         assert(!suspendDepth); // must be 0 b/c it's only set with slock held
1837 
1838         if (rmAboutToStart)
1839         {
1840             size_t idx = -1;
foreach(i,thr;pAboutToStart[0..nAboutToStart])1841             foreach (i, thr; pAboutToStart[0 .. nAboutToStart])
1842             {
1843                 if (thr is t)
1844                 {
1845                     idx = i;
1846                     break;
1847                 }
1848             }
1849             assert(idx != -1);
1850             import core.stdc.string : memmove;
1851             memmove(pAboutToStart + idx, pAboutToStart + idx + 1, Thread.sizeof * (nAboutToStart - idx - 1));
1852             pAboutToStart =
1853                 cast(Thread*)realloc(pAboutToStart, Thread.sizeof * --nAboutToStart);
1854         }
1855 
1856         if (sm_tbeg)
1857         {
1858             t.next = sm_tbeg;
1859             sm_tbeg.prev = t;
1860         }
1861         sm_tbeg = t;
1862         ++sm_tlen;
1863     }
1864 
1865 
1866     //
1867     // Remove a thread from the global thread list.
1868     //
remove(Thread t)1869     static void remove( Thread t ) nothrow @nogc
1870     in
1871     {
1872         assert( t );
1873     }
1874     body
1875     {
1876         // Thread was already removed earlier, might happen b/c of thread_detachInstance
1877         if (!t.next && !t.prev)
1878             return;
1879         slock.lock_nothrow();
1880         {
1881             // NOTE: When a thread is removed from the global thread list its
1882             //       main context is invalid and should be removed as well.
1883             //       It is possible that t.m_curr could reference more
1884             //       than just the main context if the thread exited abnormally
1885             //       (if it was terminated), but we must assume that the user
1886             //       retains a reference to them and that they may be re-used
1887             //       elsewhere.  Therefore, it is the responsibility of any
1888             //       object that creates contexts to clean them up properly
1889             //       when it is done with them.
1890             remove( &t.m_main );
1891 
1892             if ( t.prev )
1893                 t.prev.next = t.next;
1894             if ( t.next )
1895                 t.next.prev = t.prev;
1896             if ( sm_tbeg is t )
1897                 sm_tbeg = t.next;
1898             t.prev = t.next = null;
1899             --sm_tlen;
1900         }
1901         // NOTE: Don't null out t.next or t.prev because opApply currently
1902         //       follows t.next after removing a node.  This could be easily
1903         //       addressed by simply returning the next node from this
1904         //       function, however, a thread should never be re-added to the
1905         //       list anyway and having next and prev be non-null is a good way
1906         //       to ensure that.
1907         slock.unlock_nothrow();
1908     }
1909 }
1910 
1911 ///
1912 unittest
1913 {
1914     class DerivedThread : Thread
1915     {
this()1916         this()
1917         {
1918             super(&run);
1919         }
1920 
1921     private:
run()1922         void run()
1923         {
1924             // Derived thread running.
1925         }
1926     }
1927 
threadFunc()1928     void threadFunc()
1929     {
1930         // Composed thread running.
1931     }
1932 
1933     // create and start instances of each type
1934     auto derived = new DerivedThread().start();
1935     auto composed = new Thread(&threadFunc).start();
1936     new Thread({
1937         // Codes to run in the newly created thread.
1938     }).start();
1939 }
1940 
1941 unittest
1942 {
1943     int x = 0;
1944 
1945     new Thread(
1946     {
1947         x++;
1948     }).start().join();
1949     assert( x == 1 );
1950 }
1951 
1952 
1953 unittest
1954 {
1955     enum MSG = "Test message.";
1956     string caughtMsg;
1957 
1958     try
1959     {
1960         new Thread(
1961         {
1962             throw new Exception( MSG );
1963         }).start().join();
1964         assert( false, "Expected rethrown exception." );
1965     }
catch(Throwable t)1966     catch ( Throwable t )
1967     {
1968         assert( t.msg == MSG );
1969     }
1970 }
1971 
1972 
1973 ///////////////////////////////////////////////////////////////////////////////
1974 // GC Support Routines
1975 ///////////////////////////////////////////////////////////////////////////////
1976 
version(CoreDdoc)1977 version (CoreDdoc)
1978 {
1979     /**
1980      * Instruct the thread module, when initialized, to use a different set of
1981      * signals besides SIGUSR1 and SIGUSR2 for suspension and resumption of threads.
1982      * This function should be called at most once, prior to thread_init().
1983      * This function is Posix-only.
1984      */
1985     extern (C) void thread_setGCSignals(int suspendSignalNo, int resumeSignalNo) nothrow @nogc
1986     {
1987     }
1988 }
version(Posix)1989 else version (Posix)
1990 {
1991     extern (C) void thread_setGCSignals(int suspendSignalNo, int resumeSignalNo) nothrow @nogc
1992     in
1993     {
1994         assert(suspendSignalNumber == 0);
1995         assert(resumeSignalNumber  == 0);
1996         assert(suspendSignalNo != 0);
1997         assert(resumeSignalNo  != 0);
1998     }
1999     out
2000     {
2001         assert(suspendSignalNumber != 0);
2002         assert(resumeSignalNumber  != 0);
2003     }
2004     body
2005     {
2006         suspendSignalNumber = suspendSignalNo;
2007         resumeSignalNumber  = resumeSignalNo;
2008     }
2009 }
2010 
version(Posix)2011 version (Posix)
2012 {
2013     __gshared int suspendSignalNumber;
2014     __gshared int resumeSignalNumber;
2015 }
2016 
2017 /**
2018  * Initializes the thread module.  This function must be called by the
2019  * garbage collector on startup and before any other thread routines
2020  * are called.
2021  */
thread_init()2022 extern (C) void thread_init()
2023 {
2024     // NOTE: If thread_init itself performs any allocations then the thread
2025     //       routines reserved for garbage collector use may be called while
2026     //       thread_init is being processed.  However, since no memory should
2027     //       exist to be scanned at this point, it is sufficient for these
2028     //       functions to detect the condition and return immediately.
2029 
2030     Thread.initLocks();
2031     // The Android VM runtime intercepts SIGUSR1 and apparently doesn't allow
2032     // its signal handler to run, so swap the two signals on Android, since
2033     // thread_resumeHandler does nothing.
2034     version (Android) thread_setGCSignals(SIGUSR2, SIGUSR1);
2035 
2036     version (Darwin)
2037     {
2038     }
2039     else version (Posix)
2040     {
2041         if ( suspendSignalNumber == 0 )
2042         {
2043             suspendSignalNumber = SIGUSR1;
2044         }
2045 
2046         if ( resumeSignalNumber == 0 )
2047         {
2048             resumeSignalNumber = SIGUSR2;
2049         }
2050 
2051         int         status;
2052         sigaction_t sigusr1 = void;
2053         sigaction_t sigusr2 = void;
2054 
2055         // This is a quick way to zero-initialize the structs without using
2056         // memset or creating a link dependency on their static initializer.
2057         (cast(byte*) &sigusr1)[0 .. sigaction_t.sizeof] = 0;
2058         (cast(byte*) &sigusr2)[0 .. sigaction_t.sizeof] = 0;
2059 
2060         // NOTE: SA_RESTART indicates that system calls should restart if they
2061         //       are interrupted by a signal, but this is not available on all
2062         //       Posix systems, even those that support multithreading.
2063         static if ( __traits( compiles, SA_RESTART ) )
2064             sigusr1.sa_flags = SA_RESTART;
2065         else
2066             sigusr1.sa_flags   = 0;
2067         sigusr1.sa_handler = &thread_suspendHandler;
2068         // NOTE: We want to ignore all signals while in this handler, so fill
2069         //       sa_mask to indicate this.
2070         status = sigfillset( &sigusr1.sa_mask );
2071         assert( status == 0 );
2072 
2073         // NOTE: Since resumeSignalNumber should only be issued for threads within the
2074         //       suspend handler, we don't want this signal to trigger a
2075         //       restart.
2076         sigusr2.sa_flags   = 0;
2077         sigusr2.sa_handler = &thread_resumeHandler;
2078         // NOTE: We want to ignore all signals while in this handler, so fill
2079         //       sa_mask to indicate this.
2080         status = sigfillset( &sigusr2.sa_mask );
2081         assert( status == 0 );
2082 
2083         status = sigaction( suspendSignalNumber, &sigusr1, null );
2084         assert( status == 0 );
2085 
2086         status = sigaction( resumeSignalNumber, &sigusr2, null );
2087         assert( status == 0 );
2088 
2089         status = sem_init( &suspendCount, 0, 0 );
2090         assert( status == 0 );
2091     }
2092     Thread.sm_main = thread_attachThis();
2093 }
2094 
2095 
2096 /**
2097  * Terminates the thread module. No other thread routine may be called
2098  * afterwards.
2099  */
thread_term()2100 extern (C) void thread_term()
2101 {
2102     assert(Thread.sm_tbeg && Thread.sm_tlen == 1);
2103     assert(!Thread.nAboutToStart);
2104     if (Thread.pAboutToStart) // in case realloc(p, 0) doesn't return null
2105     {
2106         free(Thread.pAboutToStart);
2107         Thread.pAboutToStart = null;
2108     }
2109     Thread.termLocks();
2110 }
2111 
2112 
2113 /**
2114  *
2115  */
thread_isMainThread()2116 extern (C) bool thread_isMainThread() nothrow @nogc
2117 {
2118     return Thread.getThis() is Thread.sm_main;
2119 }
2120 
2121 
2122 /**
2123  * Registers the calling thread for use with the D Runtime.  If this routine
2124  * is called for a thread which is already registered, no action is performed.
2125  *
2126  * NOTE: This routine does not run thread-local static constructors when called.
2127  *       If full functionality as a D thread is desired, the following function
2128  *       must be called after thread_attachThis:
2129  *
2130  *       extern (C) void rt_moduleTlsCtor();
2131  */
thread_attachThis()2132 extern (C) Thread thread_attachThis()
2133 {
2134     GC.disable(); scope(exit) GC.enable();
2135 
2136     if (auto t = Thread.getThis())
2137         return t;
2138 
2139     Thread          thisThread  = new Thread();
2140     Thread.Context* thisContext = &thisThread.m_main;
2141     assert( thisContext == thisThread.m_curr );
2142 
2143     version (Windows)
2144     {
2145         thisThread.m_addr  = GetCurrentThreadId();
2146         thisThread.m_hndl  = GetCurrentThreadHandle();
2147         thisContext.bstack = getStackBottom();
2148         thisContext.tstack = thisContext.bstack;
2149     }
2150     else version (Posix)
2151     {
2152         thisThread.m_addr  = pthread_self();
2153         thisContext.bstack = getStackBottom();
2154         thisContext.tstack = thisContext.bstack;
2155 
2156         atomicStore!(MemoryOrder.raw)(thisThread.m_isRunning, true);
2157     }
2158     thisThread.m_isDaemon = true;
2159     thisThread.m_tlsgcdata = rt_tlsgc_init();
2160     Thread.setThis( thisThread );
2161 
2162     version (Darwin)
2163     {
2164         thisThread.m_tmach = pthread_mach_thread_np( thisThread.m_addr );
2165         assert( thisThread.m_tmach != thisThread.m_tmach.init );
2166     }
2167 
2168     Thread.add( thisThread, false );
2169     Thread.add( thisContext );
2170     if ( Thread.sm_main !is null )
2171         multiThreadedFlag = true;
2172     return thisThread;
2173 }
2174 
2175 
version(Windows)2176 version (Windows)
2177 {
2178     // NOTE: These calls are not safe on Posix systems that use signals to
2179     //       perform garbage collection.  The suspendHandler uses getThis()
2180     //       to get the thread handle so getThis() must be a simple call.
2181     //       Mutexes can't safely be acquired inside signal handlers, and
2182     //       even if they could, the mutex needed (Thread.slock) is held by
2183     //       thread_suspendAll().  So in short, these routines will remain
2184     //       Windows-specific.  If they are truly needed elsewhere, the
2185     //       suspendHandler will need a way to call a version of getThis()
2186     //       that only does the TLS lookup without the fancy fallback stuff.
2187 
2188     /// ditto
2189     extern (C) Thread thread_attachByAddr( ThreadID addr )
2190     {
2191         return thread_attachByAddrB( addr, getThreadStackBottom( addr ) );
2192     }
2193 
2194 
2195     /// ditto
2196     extern (C) Thread thread_attachByAddrB( ThreadID addr, void* bstack )
2197     {
2198         GC.disable(); scope(exit) GC.enable();
2199 
2200         if (auto t = thread_findByAddr(addr))
2201             return t;
2202 
2203         Thread          thisThread  = new Thread();
2204         Thread.Context* thisContext = &thisThread.m_main;
2205         assert( thisContext == thisThread.m_curr );
2206 
2207         thisThread.m_addr  = addr;
2208         thisContext.bstack = bstack;
2209         thisContext.tstack = thisContext.bstack;
2210 
2211         thisThread.m_isDaemon = true;
2212 
2213         if ( addr == GetCurrentThreadId() )
2214         {
2215             thisThread.m_hndl = GetCurrentThreadHandle();
2216             thisThread.m_tlsgcdata = rt_tlsgc_init();
2217             Thread.setThis( thisThread );
2218         }
2219         else
2220         {
2221             thisThread.m_hndl = OpenThreadHandle( addr );
2222             impersonate_thread(addr,
2223             {
2224                 thisThread.m_tlsgcdata = rt_tlsgc_init();
2225                 Thread.setThis( thisThread );
2226             });
2227         }
2228 
2229         Thread.add( thisThread, false );
2230         Thread.add( thisContext );
2231         if ( Thread.sm_main !is null )
2232             multiThreadedFlag = true;
2233         return thisThread;
2234     }
2235 }
2236 
2237 
2238 /**
2239  * Deregisters the calling thread from use with the runtime.  If this routine
2240  * is called for a thread which is not registered, the result is undefined.
2241  *
2242  * NOTE: This routine does not run thread-local static destructors when called.
2243  *       If full functionality as a D thread is desired, the following function
2244  *       must be called after thread_detachThis, particularly if the thread is
2245  *       being detached at some indeterminate time before program termination:
2246  *
2247  *       $(D extern(C) void rt_moduleTlsDtor();)
2248  */
thread_detachThis()2249 extern (C) void thread_detachThis() nothrow @nogc
2250 {
2251     if (auto t = Thread.getThis())
2252         Thread.remove(t);
2253 }
2254 
2255 
2256 /**
2257  * Deregisters the given thread from use with the runtime.  If this routine
2258  * is called for a thread which is not registered, the result is undefined.
2259  *
2260  * NOTE: This routine does not run thread-local static destructors when called.
2261  *       If full functionality as a D thread is desired, the following function
2262  *       must be called by the detached thread, particularly if the thread is
2263  *       being detached at some indeterminate time before program termination:
2264  *
2265  *       $(D extern(C) void rt_moduleTlsDtor();)
2266  */
thread_detachByAddr(ThreadID addr)2267 extern (C) void thread_detachByAddr( ThreadID addr )
2268 {
2269     if ( auto t = thread_findByAddr( addr ) )
2270         Thread.remove( t );
2271 }
2272 
2273 
2274 /// ditto
thread_detachInstance(Thread t)2275 extern (C) void thread_detachInstance( Thread t ) nothrow @nogc
2276 {
2277     Thread.remove( t );
2278 }
2279 
2280 
2281 unittest
2282 {
2283     import core.sync.semaphore;
2284     auto sem = new Semaphore();
2285 
2286     auto t = new Thread(
2287     {
2288         sem.notify();
2289         Thread.sleep(100.msecs);
2290     }).start();
2291 
2292     sem.wait(); // thread cannot be detached while being started
2293     thread_detachInstance(t);
2294     foreach (t2; Thread)
2295         assert(t !is t2);
2296     t.join();
2297 }
2298 
2299 
2300 /**
2301  * Search the list of all threads for a thread with the given thread identifier.
2302  *
2303  * Params:
2304  *  addr = The thread identifier to search for.
2305  * Returns:
2306  *  The thread object associated with the thread identifier, null if not found.
2307  */
thread_findByAddr(ThreadID addr)2308 static Thread thread_findByAddr( ThreadID addr )
2309 {
2310     Thread.slock.lock_nothrow();
2311     scope(exit) Thread.slock.unlock_nothrow();
2312 
2313     // also return just spawned thread so that
2314     // DLL_THREAD_ATTACH knows it's a D thread
2315     foreach (t; Thread.pAboutToStart[0 .. Thread.nAboutToStart])
2316         if (t.m_addr == addr)
2317             return t;
2318 
2319     foreach (t; Thread)
2320         if (t.m_addr == addr)
2321             return t;
2322 
2323     return null;
2324 }
2325 
2326 
2327 /**
2328  * Sets the current thread to a specific reference. Only to be used
2329  * when dealing with externally-created threads (in e.g. C code).
2330  * The primary use of this function is when Thread.getThis() must
2331  * return a sensible value in, for example, TLS destructors. In
2332  * other words, don't touch this unless you know what you're doing.
2333  *
2334  * Params:
2335  *  t = A reference to the current thread. May be null.
2336  */
thread_setThis(Thread t)2337 extern (C) void thread_setThis(Thread t) nothrow @nogc
2338 {
2339     Thread.setThis(t);
2340 }
2341 
2342 
2343 /**
2344  * Joins all non-daemon threads that are currently running.  This is done by
2345  * performing successive scans through the thread list until a scan consists
2346  * of only daemon threads.
2347  */
thread_joinAll()2348 extern (C) void thread_joinAll()
2349 {
2350  Lagain:
2351     Thread.slock.lock_nothrow();
2352     // wait for just spawned threads
2353     if (Thread.nAboutToStart)
2354     {
2355         Thread.slock.unlock_nothrow();
2356         Thread.yield();
2357         goto Lagain;
2358     }
2359 
2360     // join all non-daemon threads, the main thread is also a daemon
2361     auto t = Thread.sm_tbeg;
2362     while (t)
2363     {
2364         if (!t.isRunning)
2365         {
2366             auto tn = t.next;
2367             Thread.remove(t);
2368             t = tn;
2369         }
2370         else if (t.isDaemon)
2371         {
2372             t = t.next;
2373         }
2374         else
2375         {
2376             Thread.slock.unlock_nothrow();
2377             t.join(); // might rethrow
2378             goto Lagain; // must restart iteration b/c of unlock
2379         }
2380     }
2381     Thread.slock.unlock_nothrow();
2382 }
2383 
2384 
2385 /**
2386  * Performs intermediate shutdown of the thread module.
2387  */
~this()2388 shared static ~this()
2389 {
2390     // NOTE: The functionality related to garbage collection must be minimally
2391     //       operable after this dtor completes.  Therefore, only minimal
2392     //       cleanup may occur.
2393     auto t = Thread.sm_tbeg;
2394     while (t)
2395     {
2396         auto tn = t.next;
2397         if (!t.isRunning)
2398             Thread.remove(t);
2399         t = tn;
2400     }
2401 }
2402 
2403 
2404 // Used for needLock below.
2405 private __gshared bool multiThreadedFlag = false;
2406 
2407 version (PPC64) version = ExternStackShell;
2408 
version(ExternStackShell)2409 version (ExternStackShell)
2410 {
2411     extern(D) public void callWithStackShell(scope void delegate(void* sp) nothrow fn) nothrow;
2412 }
2413 else
2414 {
2415     // Calls the given delegate, passing the current thread's stack pointer to it.
callWithStackShell(scope void delegate (void * sp)nothrow fn)2416     private void callWithStackShell(scope void delegate(void* sp) nothrow fn) nothrow
2417     in
2418     {
2419         assert(fn);
2420     }
2421     body
2422     {
2423         // The purpose of the 'shell' is to ensure all the registers get
2424         // put on the stack so they'll be scanned. We only need to push
2425         // the callee-save registers.
2426         void *sp = void;
2427 
version(GNU)2428         version (GNU)
2429         {
2430             __builtin_unwind_init();
2431             sp = &sp;
2432         }
version(AsmX86_Posix)2433         else version (AsmX86_Posix)
2434         {
2435             size_t[3] regs = void;
2436             asm pure nothrow @nogc
2437             {
2438                 mov [regs + 0 * 4], EBX;
2439                 mov [regs + 1 * 4], ESI;
2440                 mov [regs + 2 * 4], EDI;
2441 
2442                 mov sp[EBP], ESP;
2443             }
2444         }
version(AsmX86_Windows)2445         else version (AsmX86_Windows)
2446         {
2447             size_t[3] regs = void;
2448             asm pure nothrow @nogc
2449             {
2450                 mov [regs + 0 * 4], EBX;
2451                 mov [regs + 1 * 4], ESI;
2452                 mov [regs + 2 * 4], EDI;
2453 
2454                 mov sp[EBP], ESP;
2455             }
2456         }
version(AsmX86_64_Posix)2457         else version (AsmX86_64_Posix)
2458         {
2459             size_t[5] regs = void;
2460             asm pure nothrow @nogc
2461             {
2462                 mov [regs + 0 * 8], RBX;
2463                 mov [regs + 1 * 8], R12;
2464                 mov [regs + 2 * 8], R13;
2465                 mov [regs + 3 * 8], R14;
2466                 mov [regs + 4 * 8], R15;
2467 
2468                 mov sp[RBP], RSP;
2469             }
2470         }
version(AsmX86_64_Windows)2471         else version (AsmX86_64_Windows)
2472         {
2473             size_t[7] regs = void;
2474             asm pure nothrow @nogc
2475             {
2476                 mov [regs + 0 * 8], RBX;
2477                 mov [regs + 1 * 8], RSI;
2478                 mov [regs + 2 * 8], RDI;
2479                 mov [regs + 3 * 8], R12;
2480                 mov [regs + 4 * 8], R13;
2481                 mov [regs + 5 * 8], R14;
2482                 mov [regs + 6 * 8], R15;
2483 
2484                 mov sp[RBP], RSP;
2485             }
2486         }
2487         else
2488         {
2489             static assert(false, "Architecture not supported.");
2490         }
2491 
2492         fn(sp);
2493     }
2494 }
2495 
2496 // Used for suspendAll/resumeAll below.
2497 private __gshared uint suspendDepth = 0;
2498 
2499 /**
2500  * Suspend the specified thread and load stack and register information for
2501  * use by thread_scanAll.  If the supplied thread is the calling thread,
2502  * stack and register information will be loaded but the thread will not
2503  * be suspended.  If the suspend operation fails and the thread is not
2504  * running then it will be removed from the global thread list, otherwise
2505  * an exception will be thrown.
2506  *
2507  * Params:
2508  *  t = The thread to suspend.
2509  *
2510  * Throws:
2511  *  ThreadError if the suspend operation fails for a running thread.
2512  * Returns:
2513  *  Whether the thread is now suspended (true) or terminated (false).
2514  */
suspend(Thread t)2515 private bool suspend( Thread t ) nothrow
2516 {
2517     Duration waittime = dur!"usecs"(10);
2518  Lagain:
2519     if (!t.isRunning)
2520     {
2521         Thread.remove(t);
2522         return false;
2523     }
2524     else if (t.m_isInCriticalRegion)
2525     {
2526         Thread.criticalRegionLock.unlock_nothrow();
2527         Thread.sleep(waittime);
2528         if (waittime < dur!"msecs"(10)) waittime *= 2;
2529         Thread.criticalRegionLock.lock_nothrow();
2530         goto Lagain;
2531     }
2532 
2533     version (Windows)
2534     {
2535         if ( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF )
2536         {
2537             if ( !t.isRunning )
2538             {
2539                 Thread.remove( t );
2540                 return false;
2541             }
2542             onThreadError( "Unable to suspend thread" );
2543         }
2544 
2545         CONTEXT context = void;
2546         context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
2547 
2548         if ( !GetThreadContext( t.m_hndl, &context ) )
2549             onThreadError( "Unable to load thread context" );
2550         version (X86)
2551         {
2552             if ( !t.m_lock )
2553                 t.m_curr.tstack = cast(void*) context.Esp;
2554             // eax,ebx,ecx,edx,edi,esi,ebp,esp
2555             t.m_reg[0] = context.Eax;
2556             t.m_reg[1] = context.Ebx;
2557             t.m_reg[2] = context.Ecx;
2558             t.m_reg[3] = context.Edx;
2559             t.m_reg[4] = context.Edi;
2560             t.m_reg[5] = context.Esi;
2561             t.m_reg[6] = context.Ebp;
2562             t.m_reg[7] = context.Esp;
2563         }
2564         else version (X86_64)
2565         {
2566             if ( !t.m_lock )
2567                 t.m_curr.tstack = cast(void*) context.Rsp;
2568             // rax,rbx,rcx,rdx,rdi,rsi,rbp,rsp
2569             t.m_reg[0] = context.Rax;
2570             t.m_reg[1] = context.Rbx;
2571             t.m_reg[2] = context.Rcx;
2572             t.m_reg[3] = context.Rdx;
2573             t.m_reg[4] = context.Rdi;
2574             t.m_reg[5] = context.Rsi;
2575             t.m_reg[6] = context.Rbp;
2576             t.m_reg[7] = context.Rsp;
2577             // r8,r9,r10,r11,r12,r13,r14,r15
2578             t.m_reg[8]  = context.R8;
2579             t.m_reg[9]  = context.R9;
2580             t.m_reg[10] = context.R10;
2581             t.m_reg[11] = context.R11;
2582             t.m_reg[12] = context.R12;
2583             t.m_reg[13] = context.R13;
2584             t.m_reg[14] = context.R14;
2585             t.m_reg[15] = context.R15;
2586         }
2587         else
2588         {
2589             static assert(false, "Architecture not supported." );
2590         }
2591     }
2592     else version (Darwin)
2593     {
2594         if ( t.m_addr != pthread_self() && thread_suspend( t.m_tmach ) != KERN_SUCCESS )
2595         {
2596             if ( !t.isRunning )
2597             {
2598                 Thread.remove( t );
2599                 return false;
2600             }
2601             onThreadError( "Unable to suspend thread" );
2602         }
2603 
2604         version (X86)
2605         {
2606             x86_thread_state32_t    state = void;
2607             mach_msg_type_number_t  count = x86_THREAD_STATE32_COUNT;
2608 
2609             if ( thread_get_state( t.m_tmach, x86_THREAD_STATE32, &state, &count ) != KERN_SUCCESS )
2610                 onThreadError( "Unable to load thread state" );
2611             if ( !t.m_lock )
2612                 t.m_curr.tstack = cast(void*) state.esp;
2613             // eax,ebx,ecx,edx,edi,esi,ebp,esp
2614             t.m_reg[0] = state.eax;
2615             t.m_reg[1] = state.ebx;
2616             t.m_reg[2] = state.ecx;
2617             t.m_reg[3] = state.edx;
2618             t.m_reg[4] = state.edi;
2619             t.m_reg[5] = state.esi;
2620             t.m_reg[6] = state.ebp;
2621             t.m_reg[7] = state.esp;
2622         }
2623         else version (X86_64)
2624         {
2625             x86_thread_state64_t    state = void;
2626             mach_msg_type_number_t  count = x86_THREAD_STATE64_COUNT;
2627 
2628             if ( thread_get_state( t.m_tmach, x86_THREAD_STATE64, &state, &count ) != KERN_SUCCESS )
2629                 onThreadError( "Unable to load thread state" );
2630             if ( !t.m_lock )
2631                 t.m_curr.tstack = cast(void*) state.rsp;
2632             // rax,rbx,rcx,rdx,rdi,rsi,rbp,rsp
2633             t.m_reg[0] = state.rax;
2634             t.m_reg[1] = state.rbx;
2635             t.m_reg[2] = state.rcx;
2636             t.m_reg[3] = state.rdx;
2637             t.m_reg[4] = state.rdi;
2638             t.m_reg[5] = state.rsi;
2639             t.m_reg[6] = state.rbp;
2640             t.m_reg[7] = state.rsp;
2641             // r8,r9,r10,r11,r12,r13,r14,r15
2642             t.m_reg[8]  = state.r8;
2643             t.m_reg[9]  = state.r9;
2644             t.m_reg[10] = state.r10;
2645             t.m_reg[11] = state.r11;
2646             t.m_reg[12] = state.r12;
2647             t.m_reg[13] = state.r13;
2648             t.m_reg[14] = state.r14;
2649             t.m_reg[15] = state.r15;
2650         }
2651         else
2652         {
2653             static assert(false, "Architecture not supported." );
2654         }
2655     }
2656     else version (Posix)
2657     {
2658         if ( t.m_addr != pthread_self() )
2659         {
2660             if ( pthread_kill( t.m_addr, suspendSignalNumber ) != 0 )
2661             {
2662                 if ( !t.isRunning )
2663                 {
2664                     Thread.remove( t );
2665                     return false;
2666                 }
2667                 onThreadError( "Unable to suspend thread" );
2668             }
2669         }
2670         else if ( !t.m_lock )
2671         {
2672             t.m_curr.tstack = getStackTop();
2673         }
2674     }
2675     return true;
2676 }
2677 
2678 /**
2679  * Suspend all threads but the calling thread for "stop the world" garbage
2680  * collection runs.  This function may be called multiple times, and must
2681  * be followed by a matching number of calls to thread_resumeAll before
2682  * processing is resumed.
2683  *
2684  * Throws:
2685  *  ThreadError if the suspend operation fails for a running thread.
2686  */
thread_suspendAll()2687 extern (C) void thread_suspendAll() nothrow
2688 {
2689     // NOTE: We've got an odd chicken & egg problem here, because while the GC
2690     //       is required to call thread_init before calling any other thread
2691     //       routines, thread_init may allocate memory which could in turn
2692     //       trigger a collection.  Thus, thread_suspendAll, thread_scanAll,
2693     //       and thread_resumeAll must be callable before thread_init
2694     //       completes, with the assumption that no other GC memory has yet
2695     //       been allocated by the system, and thus there is no risk of losing
2696     //       data if the global thread list is empty.  The check of
2697     //       Thread.sm_tbeg below is done to ensure thread_init has completed,
2698     //       and therefore that calling Thread.getThis will not result in an
2699     //       error.  For the short time when Thread.sm_tbeg is null, there is
2700     //       no reason not to simply call the multithreaded code below, with
2701     //       the expectation that the foreach loop will never be entered.
2702     if ( !multiThreadedFlag && Thread.sm_tbeg )
2703     {
2704         if ( ++suspendDepth == 1 )
2705             suspend( Thread.getThis() );
2706 
2707         return;
2708     }
2709 
2710     Thread.slock.lock_nothrow();
2711     {
2712         if ( ++suspendDepth > 1 )
2713             return;
2714 
2715         Thread.criticalRegionLock.lock_nothrow();
2716         scope (exit) Thread.criticalRegionLock.unlock_nothrow();
2717         size_t cnt;
2718         auto t = Thread.sm_tbeg;
2719         while (t)
2720         {
2721             auto tn = t.next;
2722             if (suspend(t))
2723                 ++cnt;
2724             t = tn;
2725         }
2726 
2727         version (Darwin)
2728         {}
2729         else version (Posix)
2730         {
2731             // subtract own thread
2732             assert(cnt >= 1);
2733             --cnt;
2734         Lagain:
2735             // wait for semaphore notifications
2736             for (; cnt; --cnt)
2737             {
2738                 while (sem_wait(&suspendCount) != 0)
2739                 {
2740                     if (errno != EINTR)
2741                         onThreadError("Unable to wait for semaphore");
2742                     errno = 0;
2743                 }
2744             }
2745             version (FreeBSD)
2746             {
2747                 // avoid deadlocks, see Issue 13416
2748                 t = Thread.sm_tbeg;
2749                 while (t)
2750                 {
2751                     auto tn = t.next;
2752                     if (t.m_suspendagain && suspend(t))
2753                         ++cnt;
2754                     t = tn;
2755                 }
2756                 if (cnt)
2757                     goto Lagain;
2758              }
2759         }
2760     }
2761 }
2762 
2763 /**
2764  * Resume the specified thread and unload stack and register information.
2765  * If the supplied thread is the calling thread, stack and register
2766  * information will be unloaded but the thread will not be resumed.  If
2767  * the resume operation fails and the thread is not running then it will
2768  * be removed from the global thread list, otherwise an exception will be
2769  * thrown.
2770  *
2771  * Params:
2772  *  t = The thread to resume.
2773  *
2774  * Throws:
2775  *  ThreadError if the resume fails for a running thread.
2776  */
resume(Thread t)2777 private void resume( Thread t ) nothrow
2778 {
2779     version (Windows)
2780     {
2781         if ( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF )
2782         {
2783             if ( !t.isRunning )
2784             {
2785                 Thread.remove( t );
2786                 return;
2787             }
2788             onThreadError( "Unable to resume thread" );
2789         }
2790 
2791         if ( !t.m_lock )
2792             t.m_curr.tstack = t.m_curr.bstack;
2793         t.m_reg[0 .. $] = 0;
2794     }
2795     else version (Darwin)
2796     {
2797         if ( t.m_addr != pthread_self() && thread_resume( t.m_tmach ) != KERN_SUCCESS )
2798         {
2799             if ( !t.isRunning )
2800             {
2801                 Thread.remove( t );
2802                 return;
2803             }
2804             onThreadError( "Unable to resume thread" );
2805         }
2806 
2807         if ( !t.m_lock )
2808             t.m_curr.tstack = t.m_curr.bstack;
2809         t.m_reg[0 .. $] = 0;
2810     }
2811     else version (Posix)
2812     {
2813         if ( t.m_addr != pthread_self() )
2814         {
2815             if ( pthread_kill( t.m_addr, resumeSignalNumber ) != 0 )
2816             {
2817                 if ( !t.isRunning )
2818                 {
2819                     Thread.remove( t );
2820                     return;
2821                 }
2822                 onThreadError( "Unable to resume thread" );
2823             }
2824         }
2825         else if ( !t.m_lock )
2826         {
2827             t.m_curr.tstack = t.m_curr.bstack;
2828         }
2829     }
2830 }
2831 
2832 /**
2833  * Resume all threads but the calling thread for "stop the world" garbage
2834  * collection runs.  This function must be called once for each preceding
2835  * call to thread_suspendAll before the threads are actually resumed.
2836  *
2837  * In:
2838  *  This routine must be preceded by a call to thread_suspendAll.
2839  *
2840  * Throws:
2841  *  ThreadError if the resume operation fails for a running thread.
2842  */
thread_resumeAll()2843 extern (C) void thread_resumeAll() nothrow
2844 in
2845 {
2846     assert( suspendDepth > 0 );
2847 }
2848 body
2849 {
2850     // NOTE: See thread_suspendAll for the logic behind this.
2851     if ( !multiThreadedFlag && Thread.sm_tbeg )
2852     {
2853         if ( --suspendDepth == 0 )
2854             resume( Thread.getThis() );
2855         return;
2856     }
2857 
2858     scope(exit) Thread.slock.unlock_nothrow();
2859     {
2860         if ( --suspendDepth > 0 )
2861             return;
2862 
2863         for ( Thread t = Thread.sm_tbeg; t; t = t.next )
2864         {
2865             // NOTE: We do not need to care about critical regions at all
2866             //       here. thread_suspendAll takes care of everything.
2867             resume( t );
2868         }
2869     }
2870 }
2871 
2872 /**
2873  * Indicates the kind of scan being performed by $(D thread_scanAllType).
2874  */
2875 enum ScanType
2876 {
2877     stack, /// The stack and/or registers are being scanned.
2878     tls, /// TLS data is being scanned.
2879 }
2880 
2881 alias ScanAllThreadsFn = void delegate(void*, void*) nothrow; /// The scanning function.
2882 alias ScanAllThreadsTypeFn = void delegate(ScanType, void*, void*) nothrow; /// ditto
2883 
2884 /**
2885  * The main entry point for garbage collection.  The supplied delegate
2886  * will be passed ranges representing both stack and register values.
2887  *
2888  * Params:
2889  *  scan        = The scanner function.  It should scan from p1 through p2 - 1.
2890  *
2891  * In:
2892  *  This routine must be preceded by a call to thread_suspendAll.
2893  */
thread_scanAllType(scope ScanAllThreadsTypeFn scan)2894 extern (C) void thread_scanAllType( scope ScanAllThreadsTypeFn scan ) nothrow
2895 in
2896 {
2897     assert( suspendDepth > 0 );
2898 }
2899 body
2900 {
2901     callWithStackShell(sp => scanAllTypeImpl(scan, sp));
2902 }
2903 
2904 
scanAllTypeImpl(scope ScanAllThreadsTypeFn scan,void * curStackTop)2905 private void scanAllTypeImpl( scope ScanAllThreadsTypeFn scan, void* curStackTop ) nothrow
2906 {
2907     Thread  thisThread  = null;
2908     void*   oldStackTop = null;
2909 
2910     if ( Thread.sm_tbeg )
2911     {
2912         thisThread  = Thread.getThis();
2913         if ( !thisThread.m_lock )
2914         {
2915             oldStackTop = thisThread.m_curr.tstack;
2916             thisThread.m_curr.tstack = curStackTop;
2917         }
2918     }
2919 
2920     scope( exit )
2921     {
2922         if ( Thread.sm_tbeg )
2923         {
2924             if ( !thisThread.m_lock )
2925             {
2926                 thisThread.m_curr.tstack = oldStackTop;
2927             }
2928         }
2929     }
2930 
2931     // NOTE: Synchronizing on Thread.slock is not needed because this
2932     //       function may only be called after all other threads have
2933     //       been suspended from within the same lock.
2934     if (Thread.nAboutToStart)
2935         scan(ScanType.stack, Thread.pAboutToStart, Thread.pAboutToStart + Thread.nAboutToStart);
2936 
2937     for ( Thread.Context* c = Thread.sm_cbeg; c; c = c.next )
2938     {
2939         version (StackGrowsDown)
2940         {
2941             // NOTE: We can't index past the bottom of the stack
2942             //       so don't do the "+1" for StackGrowsDown.
2943             if ( c.tstack && c.tstack < c.bstack )
2944                 scan( ScanType.stack, c.tstack, c.bstack );
2945         }
2946         else
2947         {
2948             if ( c.bstack && c.bstack < c.tstack )
2949                 scan( ScanType.stack, c.bstack, c.tstack + 1 );
2950         }
2951     }
2952 
2953     for ( Thread t = Thread.sm_tbeg; t; t = t.next )
2954     {
2955         version (Windows)
2956         {
2957             // Ideally, we'd pass ScanType.regs or something like that, but this
2958             // would make portability annoying because it only makes sense on Windows.
2959             scan( ScanType.stack, t.m_reg.ptr, t.m_reg.ptr + t.m_reg.length );
2960         }
2961 
2962         if (t.m_tlsgcdata !is null)
2963             rt_tlsgc_scan(t.m_tlsgcdata, (p1, p2) => scan(ScanType.tls, p1, p2));
2964     }
2965 }
2966 
2967 /**
2968  * The main entry point for garbage collection.  The supplied delegate
2969  * will be passed ranges representing both stack and register values.
2970  *
2971  * Params:
2972  *  scan        = The scanner function.  It should scan from p1 through p2 - 1.
2973  *
2974  * In:
2975  *  This routine must be preceded by a call to thread_suspendAll.
2976  */
thread_scanAll(scope ScanAllThreadsFn scan)2977 extern (C) void thread_scanAll( scope ScanAllThreadsFn scan ) nothrow
2978 {
2979     thread_scanAllType((type, p1, p2) => scan(p1, p2));
2980 }
2981 
2982 
2983 /**
2984  * Signals that the code following this call is a critical region. Any code in
2985  * this region must finish running before the calling thread can be suspended
2986  * by a call to thread_suspendAll.
2987  *
2988  * This function is, in particular, meant to help maintain garbage collector
2989  * invariants when a lock is not used.
2990  *
2991  * A critical region is exited with thread_exitCriticalRegion.
2992  *
2993  * $(RED Warning):
2994  * Using critical regions is extremely error-prone. For instance, using locks
2995  * inside a critical region can easily result in a deadlock when another thread
2996  * holding the lock already got suspended.
2997  *
2998  * The term and concept of a 'critical region' comes from
2999  * $(LINK2 https://github.com/mono/mono/blob/521f4a198e442573c400835ef19bbb36b60b0ebb/mono/metadata/sgen-gc.h#L925 Mono's SGen garbage collector).
3000  *
3001  * In:
3002  *  The calling thread must be attached to the runtime.
3003  */
thread_enterCriticalRegion()3004 extern (C) void thread_enterCriticalRegion() @nogc
3005 in
3006 {
3007     assert(Thread.getThis());
3008 }
3009 body
3010 {
3011     synchronized (Thread.criticalRegionLock)
3012         Thread.getThis().m_isInCriticalRegion = true;
3013 }
3014 
3015 
3016 /**
3017  * Signals that the calling thread is no longer in a critical region. Following
3018  * a call to this function, the thread can once again be suspended.
3019  *
3020  * In:
3021  *  The calling thread must be attached to the runtime.
3022  */
thread_exitCriticalRegion()3023 extern (C) void thread_exitCriticalRegion() @nogc
3024 in
3025 {
3026     assert(Thread.getThis());
3027 }
3028 body
3029 {
3030     synchronized (Thread.criticalRegionLock)
3031         Thread.getThis().m_isInCriticalRegion = false;
3032 }
3033 
3034 
3035 /**
3036  * Returns true if the current thread is in a critical region; otherwise, false.
3037  *
3038  * In:
3039  *  The calling thread must be attached to the runtime.
3040  */
thread_inCriticalRegion()3041 extern (C) bool thread_inCriticalRegion() @nogc
3042 in
3043 {
3044     assert(Thread.getThis());
3045 }
3046 body
3047 {
3048     synchronized (Thread.criticalRegionLock)
3049         return Thread.getThis().m_isInCriticalRegion;
3050 }
3051 
3052 
3053 /**
3054 * A callback for thread errors in D during collections. Since an allocation is not possible
3055 *  a preallocated ThreadError will be used as the Error instance
3056 *
3057 * Throws:
3058 *  ThreadError.
3059 */
3060 private void onThreadError(string msg = null, Throwable next = null) nothrow
3061 {
3062     __gshared ThreadError error = new ThreadError(null);
3063     error.msg = msg;
3064     error.next = next;
3065     import core.exception : SuppressTraceInfo;
3066     error.info = SuppressTraceInfo.instance;
3067     throw error;
3068 }
3069 
3070 
3071 unittest
3072 {
3073     assert(!thread_inCriticalRegion());
3074 
3075     {
3076         thread_enterCriticalRegion();
3077 
3078         scope (exit)
3079             thread_exitCriticalRegion();
3080 
3081         assert(thread_inCriticalRegion());
3082     }
3083 
3084     assert(!thread_inCriticalRegion());
3085 }
3086 
3087 unittest
3088 {
3089     // NOTE: This entire test is based on the assumption that no
3090     //       memory is allocated after the child thread is
3091     //       started. If an allocation happens, a collection could
3092     //       trigger, which would cause the synchronization below
3093     //       to cause a deadlock.
3094     // NOTE: DO NOT USE LOCKS IN CRITICAL REGIONS IN NORMAL CODE.
3095 
3096     import core.sync.semaphore;
3097 
3098     auto sema = new Semaphore(),
3099          semb = new Semaphore();
3100 
3101     auto thr = new Thread(
3102     {
3103         thread_enterCriticalRegion();
3104         assert(thread_inCriticalRegion());
3105         sema.notify();
3106 
3107         semb.wait();
3108         assert(thread_inCriticalRegion());
3109 
3110         thread_exitCriticalRegion();
3111         assert(!thread_inCriticalRegion());
3112         sema.notify();
3113 
3114         semb.wait();
3115         assert(!thread_inCriticalRegion());
3116     });
3117 
3118     thr.start();
3119 
3120     sema.wait();
3121     synchronized (Thread.criticalRegionLock)
3122         assert(thr.m_isInCriticalRegion);
3123     semb.notify();
3124 
3125     sema.wait();
3126     synchronized (Thread.criticalRegionLock)
3127         assert(!thr.m_isInCriticalRegion);
3128     semb.notify();
3129 
3130     thr.join();
3131 }
3132 
3133 unittest
3134 {
3135     import core.sync.semaphore;
3136 
3137     shared bool inCriticalRegion;
3138     auto sema = new Semaphore(),
3139          semb = new Semaphore();
3140 
3141     auto thr = new Thread(
3142     {
3143         thread_enterCriticalRegion();
3144         inCriticalRegion = true;
3145         sema.notify();
3146         semb.wait();
3147 
3148         Thread.sleep(dur!"msecs"(1));
3149         inCriticalRegion = false;
3150         thread_exitCriticalRegion();
3151     });
3152     thr.start();
3153 
3154     sema.wait();
3155     assert(inCriticalRegion);
3156     semb.notify();
3157 
3158     thread_suspendAll();
3159     assert(!inCriticalRegion);
3160     thread_resumeAll();
3161 }
3162 
3163 /**
3164  * Indicates whether an address has been marked by the GC.
3165  */
3166 enum IsMarked : int
3167 {
3168          no, /// Address is not marked.
3169         yes, /// Address is marked.
3170     unknown, /// Address is not managed by the GC.
3171 }
3172 
3173 alias IsMarkedDg = int delegate( void* addr ) nothrow; /// The isMarked callback function.
3174 
3175 /**
3176  * This routine allows the runtime to process any special per-thread handling
3177  * for the GC.  This is needed for taking into account any memory that is
3178  * referenced by non-scanned pointers but is about to be freed.  That currently
3179  * means the array append cache.
3180  *
3181  * Params:
3182  *  isMarked = The function used to check if $(D addr) is marked.
3183  *
3184  * In:
3185  *  This routine must be called just prior to resuming all threads.
3186  */
thread_processGCMarks(scope IsMarkedDg isMarked)3187 extern(C) void thread_processGCMarks( scope IsMarkedDg isMarked ) nothrow
3188 {
3189     for ( Thread t = Thread.sm_tbeg; t; t = t.next )
3190     {
3191         /* Can be null if collection was triggered between adding a
3192          * thread and calling rt_tlsgc_init.
3193          */
3194         if (t.m_tlsgcdata !is null)
3195             rt_tlsgc_processGCMarks(t.m_tlsgcdata, isMarked);
3196     }
3197 }
3198 
3199 
3200 extern (C) @nogc nothrow
3201 {
3202     version (CRuntime_Glibc) int pthread_getattr_np(pthread_t thread, pthread_attr_t* attr);
3203     version (FreeBSD) int pthread_attr_get_np(pthread_t thread, pthread_attr_t* attr);
3204     version (NetBSD) int pthread_attr_get_np(pthread_t thread, pthread_attr_t* attr);
3205     version (DragonFlyBSD) int pthread_attr_get_np(pthread_t thread, pthread_attr_t* attr);
3206     version (Solaris) int thr_stksegment(stack_t* stk);
3207     version (CRuntime_Bionic) int pthread_getattr_np(pthread_t thid, pthread_attr_t* attr);
3208     version (CRuntime_Musl) int pthread_getattr_np(pthread_t, pthread_attr_t*);
3209     version (CRuntime_UClibc) int pthread_getattr_np(pthread_t thread, pthread_attr_t* attr);
3210 }
3211 
3212 
getStackTop()3213 private void* getStackTop() nothrow @nogc
3214 {
3215     version (D_InlineAsm_X86)
3216         asm pure nothrow @nogc { naked; mov EAX, ESP; ret; }
3217     else version (D_InlineAsm_X86_64)
3218         asm pure nothrow @nogc { naked; mov RAX, RSP; ret; }
3219     else version (GNU)
3220         return __builtin_frame_address(0);
3221     else
3222         static assert(false, "Architecture not supported.");
3223 }
3224 
3225 
getStackBottom()3226 private void* getStackBottom() nothrow @nogc
3227 {
3228     version (Windows)
3229     {
3230         version (D_InlineAsm_X86)
3231             asm pure nothrow @nogc { naked; mov EAX, FS:4; ret; }
3232         else version (D_InlineAsm_X86_64)
3233             asm pure nothrow @nogc
3234             {    naked;
3235                  mov RAX, 8;
3236                  mov RAX, GS:[RAX];
3237                  ret;
3238             }
3239         else version (GNU_InlineAsm)
3240         {
3241             void *bottom;
3242 
3243             version (X86)
3244                 asm pure nothrow @nogc { "movl %%fs:4, %0;" : "=r" bottom; }
3245             else version (X86_64)
3246                 asm pure nothrow @nogc { "movq %%gs:8, %0;" : "=r" bottom; }
3247             else
3248                 static assert(false, "Platform not supported.");
3249 
3250             return bottom;
3251         }
3252         else
3253             static assert(false, "Architecture not supported.");
3254     }
3255     else version (Darwin)
3256     {
3257         import core.sys.darwin.pthread;
3258         return pthread_get_stackaddr_np(pthread_self());
3259     }
3260     else version (CRuntime_Glibc)
3261     {
3262         pthread_attr_t attr;
3263         void* addr; size_t size;
3264 
3265         pthread_getattr_np(pthread_self(), &attr);
3266         pthread_attr_getstack(&attr, &addr, &size);
3267         pthread_attr_destroy(&attr);
3268         version (StackGrowsDown)
3269             addr += size;
3270         return addr;
3271     }
3272     else version (FreeBSD)
3273     {
3274         pthread_attr_t attr;
3275         void* addr; size_t size;
3276 
3277         pthread_attr_init(&attr);
3278         pthread_attr_get_np(pthread_self(), &attr);
3279         pthread_attr_getstack(&attr, &addr, &size);
3280         pthread_attr_destroy(&attr);
3281         version (StackGrowsDown)
3282             addr += size;
3283         return addr;
3284     }
3285     else version (NetBSD)
3286     {
3287         pthread_attr_t attr;
3288         void* addr; size_t size;
3289 
3290         pthread_attr_init(&attr);
3291         pthread_attr_get_np(pthread_self(), &attr);
3292         pthread_attr_getstack(&attr, &addr, &size);
3293         pthread_attr_destroy(&attr);
3294         version (StackGrowsDown)
3295             addr += size;
3296         return addr;
3297     }
3298     else version (DragonFlyBSD)
3299     {
3300         pthread_attr_t attr;
3301         void* addr; size_t size;
3302 
3303         pthread_attr_init(&attr);
3304         pthread_attr_get_np(pthread_self(), &attr);
3305         pthread_attr_getstack(&attr, &addr, &size);
3306         pthread_attr_destroy(&attr);
3307         version (StackGrowsDown)
3308             addr += size;
3309         return addr;
3310     }
3311     else version (Solaris)
3312     {
3313         stack_t stk;
3314 
3315         thr_stksegment(&stk);
3316         return stk.ss_sp;
3317     }
3318     else version (CRuntime_Bionic)
3319     {
3320         pthread_attr_t attr;
3321         void* addr; size_t size;
3322 
3323         pthread_getattr_np(pthread_self(), &attr);
3324         pthread_attr_getstack(&attr, &addr, &size);
3325         pthread_attr_destroy(&attr);
3326         version (StackGrowsDown)
3327             addr += size;
3328         return addr;
3329     }
3330     else version (CRuntime_Musl)
3331     {
3332         pthread_attr_t attr;
3333         void* addr; size_t size;
3334 
3335         pthread_getattr_np(pthread_self(), &attr);
3336         pthread_attr_getstack(&attr, &addr, &size);
3337         pthread_attr_destroy(&attr);
3338         version (StackGrowsDown)
3339             addr += size;
3340         return addr;
3341     }
3342     else version (CRuntime_UClibc)
3343     {
3344         pthread_attr_t attr;
3345         void* addr; size_t size;
3346 
3347         pthread_getattr_np(pthread_self(), &attr);
3348         pthread_attr_getstack(&attr, &addr, &size);
3349         pthread_attr_destroy(&attr);
3350         version (StackGrowsDown)
3351             addr += size;
3352         return addr;
3353     }
3354     else
3355         static assert(false, "Platform not supported.");
3356 }
3357 
3358 
3359 /**
3360  * Returns the stack top of the currently active stack within the calling
3361  * thread.
3362  *
3363  * In:
3364  *  The calling thread must be attached to the runtime.
3365  *
3366  * Returns:
3367  *  The address of the stack top.
3368  */
thread_stackTop()3369 extern (C) void* thread_stackTop() nothrow @nogc
3370 in
3371 {
3372     // Not strictly required, but it gives us more flexibility.
3373     assert(Thread.getThis());
3374 }
3375 body
3376 {
3377     return getStackTop();
3378 }
3379 
3380 
3381 /**
3382  * Returns the stack bottom of the currently active stack within the calling
3383  * thread.
3384  *
3385  * In:
3386  *  The calling thread must be attached to the runtime.
3387  *
3388  * Returns:
3389  *  The address of the stack bottom.
3390  */
thread_stackBottom()3391 extern (C) void* thread_stackBottom() nothrow @nogc
3392 in
3393 {
3394     assert(Thread.getThis());
3395 }
3396 body
3397 {
3398     return Thread.getThis().topContext().bstack;
3399 }
3400 
3401 
3402 ///////////////////////////////////////////////////////////////////////////////
3403 // Thread Group
3404 ///////////////////////////////////////////////////////////////////////////////
3405 
3406 
3407 /**
3408  * This class is intended to simplify certain common programming techniques.
3409  */
3410 class ThreadGroup
3411 {
3412     /**
3413      * Creates and starts a new Thread object that executes fn and adds it to
3414      * the list of tracked threads.
3415      *
3416      * Params:
3417      *  fn = The thread function.
3418      *
3419      * Returns:
3420      *  A reference to the newly created thread.
3421      */
create(void function ()fn)3422     final Thread create( void function() fn )
3423     {
3424         Thread t = new Thread( fn ).start();
3425 
3426         synchronized( this )
3427         {
3428             m_all[t] = t;
3429         }
3430         return t;
3431     }
3432 
3433 
3434     /**
3435      * Creates and starts a new Thread object that executes dg and adds it to
3436      * the list of tracked threads.
3437      *
3438      * Params:
3439      *  dg = The thread function.
3440      *
3441      * Returns:
3442      *  A reference to the newly created thread.
3443      */
create(void delegate ()dg)3444     final Thread create( void delegate() dg )
3445     {
3446         Thread t = new Thread( dg ).start();
3447 
3448         synchronized( this )
3449         {
3450             m_all[t] = t;
3451         }
3452         return t;
3453     }
3454 
3455 
3456     /**
3457      * Add t to the list of tracked threads if it is not already being tracked.
3458      *
3459      * Params:
3460      *  t = The thread to add.
3461      *
3462      * In:
3463      *  t must not be null.
3464      */
add(Thread t)3465     final void add( Thread t )
3466     in
3467     {
3468         assert( t );
3469     }
3470     body
3471     {
synchronized(this)3472         synchronized( this )
3473         {
3474             m_all[t] = t;
3475         }
3476     }
3477 
3478 
3479     /**
3480      * Removes t from the list of tracked threads.  No operation will be
3481      * performed if t is not currently being tracked by this object.
3482      *
3483      * Params:
3484      *  t = The thread to remove.
3485      *
3486      * In:
3487      *  t must not be null.
3488      */
remove(Thread t)3489     final void remove( Thread t )
3490     in
3491     {
3492         assert( t );
3493     }
3494     body
3495     {
synchronized(this)3496         synchronized( this )
3497         {
3498             m_all.remove( t );
3499         }
3500     }
3501 
3502 
3503     /**
3504      * Operates on all threads currently tracked by this object.
3505      */
opApply(scope int delegate (ref Thread)dg)3506     final int opApply( scope int delegate( ref Thread ) dg )
3507     {
3508         synchronized( this )
3509         {
3510             int ret = 0;
3511 
3512             // NOTE: This loop relies on the knowledge that m_all uses the
3513             //       Thread object for both the key and the mapped value.
3514             foreach ( Thread t; m_all.keys )
3515             {
3516                 ret = dg( t );
3517                 if ( ret )
3518                     break;
3519             }
3520             return ret;
3521         }
3522     }
3523 
3524 
3525     /**
3526      * Iteratively joins all tracked threads.  This function will block add,
3527      * remove, and opApply until it completes.
3528      *
3529      * Params:
3530      *  rethrow = Rethrow any unhandled exception which may have caused the
3531      *            current thread to terminate.
3532      *
3533      * Throws:
3534      *  Any exception not handled by the joined threads.
3535      */
3536     final void joinAll( bool rethrow = true )
3537     {
synchronized(this)3538         synchronized( this )
3539         {
3540             // NOTE: This loop relies on the knowledge that m_all uses the
3541             //       Thread object for both the key and the mapped value.
3542             foreach ( Thread t; m_all.keys )
3543             {
3544                 t.join( rethrow );
3545             }
3546         }
3547     }
3548 
3549 
3550 private:
3551     Thread[Thread]  m_all;
3552 }
3553 
3554 
3555 ///////////////////////////////////////////////////////////////////////////////
3556 // Fiber Platform Detection and Memory Allocation
3557 ///////////////////////////////////////////////////////////////////////////////
3558 
3559 
3560 private
3561 {
version(D_InlineAsm_X86)3562     version (D_InlineAsm_X86)
3563     {
3564         version (Windows)
3565             version = AsmX86_Windows;
3566         else version (Posix)
3567             version = AsmX86_Posix;
3568 
3569         version (Darwin)
3570             version = AlignFiberStackTo16Byte;
3571     }
version(D_InlineAsm_X86_64)3572     else version (D_InlineAsm_X86_64)
3573     {
3574         version (Windows)
3575         {
3576             version = AsmX86_64_Windows;
3577             version = AlignFiberStackTo16Byte;
3578         }
3579         else version (Posix)
3580         {
3581             version = AsmX86_64_Posix;
3582             version = AlignFiberStackTo16Byte;
3583         }
3584     }
version(X86)3585     else version (X86)
3586     {
3587         version = AsmExternal;
3588 
3589         version (MinGW)
3590         {
3591             version = GNU_AsmX86_Windows;
3592             version = AlignFiberStackTo16Byte;
3593         }
3594         else version (Posix)
3595         {
3596             version = AsmX86_Posix;
3597             version (OSX)
3598                 version = AlignFiberStackTo16Byte;
3599         }
3600     }
version(X86_64)3601     else version (X86_64)
3602     {
3603         version (D_X32)
3604         {
3605             // let X32 be handled by ucontext swapcontext
3606         }
3607         else
3608         {
3609             version = AsmExternal;
3610             version = AlignFiberStackTo16Byte;
3611 
3612             version (MinGW)
3613                 version = GNU_AsmX86_64_Windows;
3614             else version (Posix)
3615                 version = AsmX86_64_Posix;
3616         }
3617     }
version(PPC)3618     else version (PPC)
3619     {
3620         version (Posix)
3621         {
3622             version = AsmPPC_Posix;
3623             version = AsmExternal;
3624         }
3625     }
version(PPC64)3626     else version (PPC64)
3627     {
3628         version (Posix)
3629         {
3630             version = AlignFiberStackTo16Byte;
3631         }
3632     }
version(MIPS_O32)3633     else version (MIPS_O32)
3634     {
3635         version (Posix)
3636         {
3637             version = AsmMIPS_O32_Posix;
3638             version = AsmExternal;
3639         }
3640     }
version(AArch64)3641     else version (AArch64)
3642     {
3643         version (Posix)
3644         {
3645             version = AsmAArch64_Posix;
3646             version = AsmExternal;
3647             version = AlignFiberStackTo16Byte;
3648         }
3649     }
version(ARM)3650     else version (ARM)
3651     {
3652         version (Posix)
3653         {
3654             version = AsmARM_Posix;
3655             version = AsmExternal;
3656         }
3657     }
version(SPARC)3658     else version (SPARC)
3659     {
3660         // NOTE: The SPARC ABI specifies only doubleword alignment.
3661         version = AlignFiberStackTo16Byte;
3662     }
version(SPARC64)3663     else version (SPARC64)
3664     {
3665         version = AlignFiberStackTo16Byte;
3666     }
3667 
version(Posix)3668     version (Posix)
3669     {
3670         import core.sys.posix.unistd;   // for sysconf
3671 
3672         version (AsmX86_Windows)    {} else
3673         version (AsmX86_Posix)      {} else
3674         version (AsmX86_64_Windows) {} else
3675         version (AsmX86_64_Posix)   {} else
3676         version (AsmExternal)       {} else
3677         {
3678             // NOTE: The ucontext implementation requires architecture specific
3679             //       data definitions to operate so testing for it must be done
3680             //       by checking for the existence of ucontext_t rather than by
3681             //       a version identifier.  Please note that this is considered
3682             //       an obsolescent feature according to the POSIX spec, so a
3683             //       custom solution is still preferred.
3684             import core.sys.posix.ucontext;
3685         }
3686     }
3687 
3688     static immutable size_t PAGESIZE;
3689     version (Posix) static immutable size_t PTHREAD_STACK_MIN;
3690 }
3691 
3692 
3693 shared static this()
3694 {
3695     version (Windows)
3696     {
3697         SYSTEM_INFO info;
3698         GetSystemInfo(&info);
3699 
3700         PAGESIZE = info.dwPageSize;
3701         assert(PAGESIZE < int.max);
3702     }
3703     else version (Posix)
3704     {
3705         PAGESIZE = cast(size_t)sysconf(_SC_PAGESIZE);
3706         PTHREAD_STACK_MIN = cast(size_t)sysconf(_SC_THREAD_STACK_MIN);
3707     }
3708     else
3709     {
3710         static assert(0, "unimplemented");
3711     }
3712 }
3713 
3714 
3715 ///////////////////////////////////////////////////////////////////////////////
3716 // Fiber Entry Point and Context Switch
3717 ///////////////////////////////////////////////////////////////////////////////
3718 
3719 
3720 private
3721 {
3722     extern (C) void fiber_entryPoint() nothrow
3723     {
3724         Fiber   obj = Fiber.getThis();
3725         assert( obj );
3726 
3727         assert( Thread.getThis().m_curr is obj.m_ctxt );
3728         atomicStore!(MemoryOrder.raw)(*cast(shared)&Thread.getThis().m_lock, false);
3729         obj.m_ctxt.tstack = obj.m_ctxt.bstack;
3730         obj.m_state = Fiber.State.EXEC;
3731 
3732         try
3733         {
3734             obj.run();
3735         }
3736         catch ( Throwable t )
3737         {
3738             obj.m_unhandled = t;
3739         }
3740 
3741         static if ( __traits( compiles, ucontext_t ) )
3742           obj.m_ucur = &obj.m_utxt;
3743 
3744         obj.m_state = Fiber.State.TERM;
3745         obj.switchOut();
3746     }
3747 
3748   // Look above the definition of 'class Fiber' for some information about the implementation of this routine
3749   version (AsmExternal)
3750   {
3751       extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow @nogc;
3752       version (AArch64)
3753           extern (C) void fiber_trampoline() nothrow;
3754   }
3755   else
3756     extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow @nogc
3757     {
3758         // NOTE: The data pushed and popped in this routine must match the
3759         //       default stack created by Fiber.initStack or the initial
3760         //       switch into a new context will fail.
3761 
3762         version (AsmX86_Windows)
3763         {
3764             asm pure nothrow @nogc
3765             {
3766                 naked;
3767 
3768                 // save current stack state
3769                 push EBP;
3770                 mov  EBP, ESP;
3771                 push EDI;
3772                 push ESI;
3773                 push EBX;
3774                 push dword ptr FS:[0];
3775                 push dword ptr FS:[4];
3776                 push dword ptr FS:[8];
3777                 push EAX;
3778 
3779                 // store oldp again with more accurate address
3780                 mov EAX, dword ptr 8[EBP];
3781                 mov [EAX], ESP;
3782                 // load newp to begin context switch
3783                 mov ESP, dword ptr 12[EBP];
3784 
3785                 // load saved state from new stack
3786                 pop EAX;
3787                 pop dword ptr FS:[8];
3788                 pop dword ptr FS:[4];
3789                 pop dword ptr FS:[0];
3790                 pop EBX;
3791                 pop ESI;
3792                 pop EDI;
3793                 pop EBP;
3794 
3795                 // 'return' to complete switch
3796                 pop ECX;
3797                 jmp ECX;
3798             }
3799         }
3800         else version (AsmX86_64_Windows)
3801         {
3802             asm pure nothrow @nogc
3803             {
3804                 naked;
3805 
3806                 // save current stack state
3807                 // NOTE: When changing the layout of registers on the stack,
3808                 //       make sure that the XMM registers are still aligned.
3809                 //       On function entry, the stack is guaranteed to not
3810                 //       be aligned to 16 bytes because of the return address
3811                 //       on the stack.
3812                 push RBP;
3813                 mov  RBP, RSP;
3814                 push R12;
3815                 push R13;
3816                 push R14;
3817                 push R15;
3818                 push RDI;
3819                 push RSI;
3820                 // 7 registers = 56 bytes; stack is now aligned to 16 bytes
3821                 sub RSP, 160;
3822                 movdqa [RSP + 144], XMM6;
3823                 movdqa [RSP + 128], XMM7;
3824                 movdqa [RSP + 112], XMM8;
3825                 movdqa [RSP + 96], XMM9;
3826                 movdqa [RSP + 80], XMM10;
3827                 movdqa [RSP + 64], XMM11;
3828                 movdqa [RSP + 48], XMM12;
3829                 movdqa [RSP + 32], XMM13;
3830                 movdqa [RSP + 16], XMM14;
3831                 movdqa [RSP], XMM15;
3832                 push RBX;
3833                 xor  RAX,RAX;
3834                 push qword ptr GS:[RAX];
3835                 push qword ptr GS:8[RAX];
3836                 push qword ptr GS:16[RAX];
3837 
3838                 // store oldp
3839                 mov [RCX], RSP;
3840                 // load newp to begin context switch
3841                 mov RSP, RDX;
3842 
3843                 // load saved state from new stack
3844                 pop qword ptr GS:16[RAX];
3845                 pop qword ptr GS:8[RAX];
3846                 pop qword ptr GS:[RAX];
3847                 pop RBX;
3848                 movdqa XMM15, [RSP];
3849                 movdqa XMM14, [RSP + 16];
3850                 movdqa XMM13, [RSP + 32];
3851                 movdqa XMM12, [RSP + 48];
3852                 movdqa XMM11, [RSP + 64];
3853                 movdqa XMM10, [RSP + 80];
3854                 movdqa XMM9, [RSP + 96];
3855                 movdqa XMM8, [RSP + 112];
3856                 movdqa XMM7, [RSP + 128];
3857                 movdqa XMM6, [RSP + 144];
3858                 add RSP, 160;
3859                 pop RSI;
3860                 pop RDI;
3861                 pop R15;
3862                 pop R14;
3863                 pop R13;
3864                 pop R12;
3865                 pop RBP;
3866 
3867                 // 'return' to complete switch
3868                 pop RCX;
3869                 jmp RCX;
3870             }
3871         }
3872         else version (AsmX86_Posix)
3873         {
3874             asm pure nothrow @nogc
3875             {
3876                 naked;
3877 
3878                 // save current stack state
3879                 push EBP;
3880                 mov  EBP, ESP;
3881                 push EDI;
3882                 push ESI;
3883                 push EBX;
3884                 push EAX;
3885 
3886                 // store oldp again with more accurate address
3887                 mov EAX, dword ptr 8[EBP];
3888                 mov [EAX], ESP;
3889                 // load newp to begin context switch
3890                 mov ESP, dword ptr 12[EBP];
3891 
3892                 // load saved state from new stack
3893                 pop EAX;
3894                 pop EBX;
3895                 pop ESI;
3896                 pop EDI;
3897                 pop EBP;
3898 
3899                 // 'return' to complete switch
3900                 pop ECX;
3901                 jmp ECX;
3902             }
3903         }
3904         else version (AsmX86_64_Posix)
3905         {
3906             asm pure nothrow @nogc
3907             {
3908                 naked;
3909 
3910                 // save current stack state
3911                 push RBP;
3912                 mov  RBP, RSP;
3913                 push RBX;
3914                 push R12;
3915                 push R13;
3916                 push R14;
3917                 push R15;
3918 
3919                 // store oldp
3920                 mov [RDI], RSP;
3921                 // load newp to begin context switch
3922                 mov RSP, RSI;
3923 
3924                 // load saved state from new stack
3925                 pop R15;
3926                 pop R14;
3927                 pop R13;
3928                 pop R12;
3929                 pop RBX;
3930                 pop RBP;
3931 
3932                 // 'return' to complete switch
3933                 pop RCX;
3934                 jmp RCX;
3935             }
3936         }
3937         else static if ( __traits( compiles, ucontext_t ) )
3938         {
3939             Fiber   cfib = Fiber.getThis();
3940             void*   ucur = cfib.m_ucur;
3941 
3942             *oldp = &ucur;
3943             swapcontext( **(cast(ucontext_t***) oldp),
3944                           *(cast(ucontext_t**)  newp) );
3945         }
3946         else
3947             static assert(0, "Not implemented");
3948     }
3949 }
3950 
3951 
3952 ///////////////////////////////////////////////////////////////////////////////
3953 // Fiber
3954 ///////////////////////////////////////////////////////////////////////////////
3955 /*
3956  * Documentation of Fiber internals:
3957  *
3958  * The main routines to implement when porting Fibers to new architectures are
3959  * fiber_switchContext and initStack. Some version constants have to be defined
3960  * for the new platform as well, search for "Fiber Platform Detection and Memory Allocation".
3961  *
3962  * Fibers are based on a concept called 'Context'. A Context describes the execution
3963  * state of a Fiber or main thread which is fully described by the stack, some
3964  * registers and a return address at which the Fiber/Thread should continue executing.
3965  * Please note that not only each Fiber has a Context, but each thread also has got a
3966  * Context which describes the threads stack and state. If you call Fiber fib; fib.call
3967  * the first time in a thread you switch from Threads Context into the Fibers Context.
3968  * If you call fib.yield in that Fiber you switch out of the Fibers context and back
3969  * into the Thread Context. (However, this is not always the case. You can call a Fiber
3970  * from within another Fiber, then you switch Contexts between the Fibers and the Thread
3971  * Context is not involved)
3972  *
3973  * In all current implementations the registers and the return address are actually
3974  * saved on a Contexts stack.
3975  *
3976  * The fiber_switchContext routine has got two parameters:
3977  * void** a:  This is the _location_ where we have to store the current stack pointer,
3978  *            the stack pointer of the currently executing Context (Fiber or Thread).
3979  * void*  b:  This is the pointer to the stack of the Context which we want to switch into.
3980  *            Note that we get the same pointer here as the one we stored into the void** a
3981  *            in a previous call to fiber_switchContext.
3982  *
3983  * In the simplest case, a fiber_switchContext rountine looks like this:
3984  * fiber_switchContext:
3985  *     push {return Address}
3986  *     push {registers}
3987  *     copy {stack pointer} into {location pointed to by a}
3988  *     //We have now switch to the stack of a different Context!
3989  *     copy {b} into {stack pointer}
3990  *     pop {registers}
3991  *     pop {return Address}
3992  *     jump to {return Address}
3993  *
3994  * The GC uses the value returned in parameter a to scan the Fibers stack. It scans from
3995  * the stack base to that value. As the GC dislikes false pointers we can actually optimize
3996  * this a little: By storing registers which can not contain references to memory managed
3997  * by the GC outside of the region marked by the stack base pointer and the stack pointer
3998  * saved in fiber_switchContext we can prevent the GC from scanning them.
3999  * Such registers are usually floating point registers and the return address. In order to
4000  * implement this, we return a modified stack pointer from fiber_switchContext. However,
4001  * we have to remember that when we restore the registers from the stack!
4002  *
4003  * --------------------------- <= Stack Base
4004  * |          Frame          | <= Many other stack frames
4005  * |          Frame          |
4006  * |-------------------------| <= The last stack frame. This one is created by fiber_switchContext
4007  * | registers with pointers |
4008  * |                         | <= Stack pointer. GC stops scanning here
4009  * |   return address        |
4010  * |floating point registers |
4011  * --------------------------- <= Real Stack End
4012  *
4013  * fiber_switchContext:
4014  *     push {registers with pointers}
4015  *     copy {stack pointer} into {location pointed to by a}
4016  *     push {return Address}
4017  *     push {Floating point registers}
4018  *     //We have now switch to the stack of a different Context!
4019  *     copy {b} into {stack pointer}
4020  *     //We now have to adjust the stack pointer to point to 'Real Stack End' so we can pop
4021  *     //the FP registers
4022  *     //+ or - depends on if your stack grows downwards or upwards
4023  *     {stack pointer} = {stack pointer} +- ({FPRegisters}.sizeof + {return address}.sizeof}
4024  *     pop {Floating point registers}
4025  *     pop {return Address}
4026  *     pop {registers with pointers}
4027  *     jump to {return Address}
4028  *
4029  * So the question now is which registers need to be saved? This depends on the specific
4030  * architecture ABI of course, but here are some general guidelines:
4031  * - If a register is callee-save (if the callee modifies the register it must saved and
4032  *   restored by the callee) it needs to be saved/restored in switchContext
4033  * - If a register is caller-save it needn't be saved/restored. (Calling fiber_switchContext
4034  *   is a function call and the compiler therefore already must save these registers before
4035  *   calling fiber_switchContext)
4036  * - Argument registers used for passing parameters to functions needn't be saved/restored
4037  * - The return register needn't be saved/restored (fiber_switchContext hasn't got a return type)
4038  * - All scratch registers needn't be saved/restored
4039  * - The link register usually needn't be saved/restored (but sometimes it must be cleared -
4040  *   see below for details)
4041  * - The frame pointer register - if it exists - is usually callee-save
4042  * - All current implementations do not save control registers
4043  *
4044  * What happens on the first switch into a Fiber? We never saved a state for this fiber before,
4045  * but the initial state is prepared in the initStack routine. (This routine will also be called
4046  * when a Fiber is being resetted). initStack must produce exactly the same stack layout as the
4047  * part of fiber_switchContext which saves the registers. Pay special attention to set the stack
4048  * pointer correctly if you use the GC optimization mentioned before. the return Address saved in
4049  * initStack must be the address of fiber_entrypoint.
4050  *
4051  * There's now a small but important difference between the first context switch into a fiber and
4052  * further context switches. On the first switch, Fiber.call is used and the returnAddress in
4053  * fiber_switchContext will point to fiber_entrypoint. The important thing here is that this jump
4054  * is a _function call_, we call fiber_entrypoint by jumping before it's function prologue. On later
4055  * calls, the user used yield() in a function, and therefore the return address points into a user
4056  * function, after the yield call. So here the jump in fiber_switchContext is a _function return_,
4057  * not a function call!
4058  *
4059  * The most important result of this is that on entering a function, i.e. fiber_entrypoint, we
4060  * would have to provide a return address / set the link register once fiber_entrypoint
4061  * returns. Now fiber_entrypoint does never return and therefore the actual value of the return
4062  * address / link register is never read/used and therefore doesn't matter. When fiber_switchContext
4063  * performs a _function return_ the value in the link register doesn't matter either.
4064  * However, the link register will still be saved to the stack in fiber_entrypoint and some
4065  * exception handling / stack unwinding code might read it from this stack location and crash.
4066  * The exact solution depends on your architecture, but see the ARM implementation for a way
4067  * to deal with this issue.
4068  *
4069  * The ARM implementation is meant to be used as a kind of documented example implementation.
4070  * Look there for a concrete example.
4071  *
4072  * FIXME: fiber_entrypoint might benefit from a @noreturn attribute, but D doesn't have one.
4073  */
4074 
4075 /**
4076  * This class provides a cooperative concurrency mechanism integrated with the
4077  * threading and garbage collection functionality.  Calling a fiber may be
4078  * considered a blocking operation that returns when the fiber yields (via
4079  * Fiber.yield()).  Execution occurs within the context of the calling thread
4080  * so synchronization is not necessary to guarantee memory visibility so long
4081  * as the same thread calls the fiber each time.  Please note that there is no
4082  * requirement that a fiber be bound to one specific thread.  Rather, fibers
4083  * may be freely passed between threads so long as they are not currently
4084  * executing.  Like threads, a new fiber thread may be created using either
4085  * derivation or composition, as in the following example.
4086  *
4087  * Warning:
4088  * Status registers are not saved by the current implementations. This means
4089  * floating point exception status bits (overflow, divide by 0), rounding mode
4090  * and similar stuff is set per-thread, not per Fiber!
4091  *
4092  * Warning:
4093  * On ARM FPU registers are not saved if druntime was compiled as ARM_SoftFloat.
4094  * If such a build is used on a ARM_SoftFP system which actually has got a FPU
4095  * and other libraries are using the FPU registers (other code is compiled
4096  * as ARM_SoftFP) this can cause problems. Druntime must be compiled as
4097  * ARM_SoftFP in this case.
4098  *
4099  * Example:
4100  * ----------------------------------------------------------------------
4101  *
4102  * class DerivedFiber : Fiber
4103  * {
4104  *     this()
4105  *     {
4106  *         super( &run );
4107  *     }
4108  *
4109  * private :
4110  *     void run()
4111  *     {
4112  *         printf( "Derived fiber running.\n" );
4113  *     }
4114  * }
4115  *
4116  * void fiberFunc()
4117  * {
4118  *     printf( "Composed fiber running.\n" );
4119  *     Fiber.yield();
4120  *     printf( "Composed fiber running.\n" );
4121  * }
4122  *
4123  * // create instances of each type
4124  * Fiber derived = new DerivedFiber();
4125  * Fiber composed = new Fiber( &fiberFunc );
4126  *
4127  * // call both fibers once
4128  * derived.call();
4129  * composed.call();
4130  * printf( "Execution returned to calling context.\n" );
4131  * composed.call();
4132  *
4133  * // since each fiber has run to completion, each should have state TERM
4134  * assert( derived.state == Fiber.State.TERM );
4135  * assert( composed.state == Fiber.State.TERM );
4136  *
4137  * ----------------------------------------------------------------------
4138  *
4139  * Authors: Based on a design by Mikola Lysenko.
4140  */
4141 class Fiber
4142 {
4143     ///////////////////////////////////////////////////////////////////////////
4144     // Initialization
4145     ///////////////////////////////////////////////////////////////////////////
4146 
4147 
4148     /**
4149      * Initializes a fiber object which is associated with a static
4150      * D function.
4151      *
4152      * Params:
4153      *  fn = The fiber function.
4154      *  sz = The stack size for this fiber.
4155      *  guardPageSize = size of the guard page to trap fiber's stack
4156      *                    overflows
4157      *
4158      * In:
4159      *  fn must not be null.
4160      */
4161     this( void function() fn, size_t sz = PAGESIZE*4,
4162           size_t guardPageSize = PAGESIZE ) nothrow
4163     in
4164     {
4165         assert( fn );
4166     }
4167     body
4168     {
4169         allocStack( sz, guardPageSize );
4170         reset( fn );
4171     }
4172 
4173 
4174     /**
4175      * Initializes a fiber object which is associated with a dynamic
4176      * D function.
4177      *
4178      * Params:
4179      *  dg = The fiber function.
4180      *  sz = The stack size for this fiber.
4181      *  guardPageSize = size of the guard page to trap fiber's stack
4182      *                    overflows
4183      *
4184      * In:
4185      *  dg must not be null.
4186      */
4187     this( void delegate() dg, size_t sz = PAGESIZE*4,
4188           size_t guardPageSize = PAGESIZE ) nothrow
4189     in
4190     {
4191         assert( dg );
4192     }
4193     body
4194     {
4195         allocStack( sz, guardPageSize);
4196         reset( dg );
4197     }
4198 
4199 
4200     /**
4201      * Cleans up any remaining resources used by this object.
4202      */
4203     ~this() nothrow @nogc
4204     {
4205         // NOTE: A live reference to this object will exist on its associated
4206         //       stack from the first time its call() method has been called
4207         //       until its execution completes with State.TERM.  Thus, the only
4208         //       times this dtor should be called are either if the fiber has
4209         //       terminated (and therefore has no active stack) or if the user
4210         //       explicitly deletes this object.  The latter case is an error
4211         //       but is not easily tested for, since State.HOLD may imply that
4212         //       the fiber was just created but has never been run.  There is
4213         //       not a compelling case to create a State.INIT just to offer a
4214         //       means of ensuring the user isn't violating this object's
4215         //       contract, so for now this requirement will be enforced by
4216         //       documentation only.
4217         freeStack();
4218     }
4219 
4220 
4221     ///////////////////////////////////////////////////////////////////////////
4222     // General Actions
4223     ///////////////////////////////////////////////////////////////////////////
4224 
4225 
4226     /**
4227      * Transfers execution to this fiber object.  The calling context will be
4228      * suspended until the fiber calls Fiber.yield() or until it terminates
4229      * via an unhandled exception.
4230      *
4231      * Params:
4232      *  rethrow = Rethrow any unhandled exception which may have caused this
4233      *            fiber to terminate.
4234      *
4235      * In:
4236      *  This fiber must be in state HOLD.
4237      *
4238      * Throws:
4239      *  Any exception not handled by the joined thread.
4240      *
4241      * Returns:
4242      *  Any exception not handled by this fiber if rethrow = false, null
4243      *  otherwise.
4244      */
4245     // Not marked with any attributes, even though `nothrow @nogc` works
4246     // because it calls arbitrary user code. Most of the implementation
4247     // is already `@nogc nothrow`, but in order for `Fiber.call` to
4248     // propagate the attributes of the user's function, the Fiber
4249     // class needs to be templated.
4250     final Throwable call( Rethrow rethrow = Rethrow.yes )
4251     {
4252         return rethrow ? call!(Rethrow.yes)() : call!(Rethrow.no);
4253     }
4254 
4255     /// ditto
4256     final Throwable call( Rethrow rethrow )()
4257     {
4258         callImpl();
4259         if ( m_unhandled )
4260         {
4261             Throwable t = m_unhandled;
4262             m_unhandled = null;
4263             static if ( rethrow )
4264                 throw t;
4265             else
4266                 return t;
4267         }
4268         return null;
4269     }
4270 
4271     /// ditto
4272     deprecated("Please pass Fiber.Rethrow.yes or .no instead of a boolean.")
4273     final Throwable call( bool rethrow )
4274     {
4275         return rethrow ? call!(Rethrow.yes)() : call!(Rethrow.no);
4276     }
4277 
4278     private void callImpl() nothrow @nogc
4279     in
4280     {
4281         assert( m_state == State.HOLD );
4282     }
4283     body
4284     {
4285         Fiber   cur = getThis();
4286 
4287         static if ( __traits( compiles, ucontext_t ) )
4288           m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt;
4289 
4290         setThis( this );
4291         this.switchIn();
4292         setThis( cur );
4293 
4294         static if ( __traits( compiles, ucontext_t ) )
4295           m_ucur = null;
4296 
4297         // NOTE: If the fiber has terminated then the stack pointers must be
4298         //       reset.  This ensures that the stack for this fiber is not
4299         //       scanned if the fiber has terminated.  This is necessary to
4300         //       prevent any references lingering on the stack from delaying
4301         //       the collection of otherwise dead objects.  The most notable
4302         //       being the current object, which is referenced at the top of
4303         //       fiber_entryPoint.
4304         if ( m_state == State.TERM )
4305         {
4306             m_ctxt.tstack = m_ctxt.bstack;
4307         }
4308     }
4309 
4310     /// Flag to control rethrow behavior of $(D $(LREF call))
4311     enum Rethrow : bool { no, yes }
4312 
4313     /**
4314      * Resets this fiber so that it may be re-used, optionally with a
4315      * new function/delegate.  This routine should only be called for
4316      * fibers that have terminated, as doing otherwise could result in
4317      * scope-dependent functionality that is not executed.
4318      * Stack-based classes, for example, may not be cleaned up
4319      * properly if a fiber is reset before it has terminated.
4320      *
4321      * In:
4322      *  This fiber must be in state TERM or HOLD.
4323      */
4324     final void reset() nothrow @nogc
4325     in
4326     {
4327         assert( m_state == State.TERM || m_state == State.HOLD );
4328     }
4329     body
4330     {
4331         m_ctxt.tstack = m_ctxt.bstack;
4332         m_state = State.HOLD;
4333         initStack();
4334         m_unhandled = null;
4335     }
4336 
4337     /// ditto
4338     final void reset( void function() fn ) nothrow @nogc
4339     {
4340         reset();
4341         m_fn    = fn;
4342         m_call  = Call.FN;
4343     }
4344 
4345     /// ditto
4346     final void reset( void delegate() dg ) nothrow @nogc
4347     {
4348         reset();
4349         m_dg    = dg;
4350         m_call  = Call.DG;
4351     }
4352 
4353     ///////////////////////////////////////////////////////////////////////////
4354     // General Properties
4355     ///////////////////////////////////////////////////////////////////////////
4356 
4357 
4358     /**
4359      * A fiber may occupy one of three states: HOLD, EXEC, and TERM.  The HOLD
4360      * state applies to any fiber that is suspended and ready to be called.
4361      * The EXEC state will be set for any fiber that is currently executing.
4362      * And the TERM state is set when a fiber terminates.  Once a fiber
4363      * terminates, it must be reset before it may be called again.
4364      */
4365     enum State
4366     {
4367         HOLD,   ///
4368         EXEC,   ///
4369         TERM    ///
4370     }
4371 
4372 
4373     /**
4374      * Gets the current state of this fiber.
4375      *
4376      * Returns:
4377      *  The state of this fiber as an enumerated value.
4378      */
4379     final @property State state() const @safe pure nothrow @nogc
4380     {
4381         return m_state;
4382     }
4383 
4384 
4385     ///////////////////////////////////////////////////////////////////////////
4386     // Actions on Calling Fiber
4387     ///////////////////////////////////////////////////////////////////////////
4388 
4389 
4390     /**
4391      * Forces a context switch to occur away from the calling fiber.
4392      */
4393     static void yield() nothrow @nogc
4394     {
4395         Fiber   cur = getThis();
4396         assert( cur, "Fiber.yield() called with no active fiber" );
4397         assert( cur.m_state == State.EXEC );
4398 
4399         static if ( __traits( compiles, ucontext_t ) )
4400           cur.m_ucur = &cur.m_utxt;
4401 
4402         cur.m_state = State.HOLD;
4403         cur.switchOut();
4404         cur.m_state = State.EXEC;
4405     }
4406 
4407 
4408     /**
4409      * Forces a context switch to occur away from the calling fiber and then
4410      * throws obj in the calling fiber.
4411      *
4412      * Params:
4413      *  t = The object to throw.
4414      *
4415      * In:
4416      *  t must not be null.
4417      */
4418     static void yieldAndThrow( Throwable t ) nothrow @nogc
4419     in
4420     {
4421         assert( t );
4422     }
4423     body
4424     {
4425         Fiber   cur = getThis();
4426         assert( cur, "Fiber.yield() called with no active fiber" );
4427         assert( cur.m_state == State.EXEC );
4428 
4429         static if ( __traits( compiles, ucontext_t ) )
4430           cur.m_ucur = &cur.m_utxt;
4431 
4432         cur.m_unhandled = t;
4433         cur.m_state = State.HOLD;
4434         cur.switchOut();
4435         cur.m_state = State.EXEC;
4436     }
4437 
4438 
4439     ///////////////////////////////////////////////////////////////////////////
4440     // Fiber Accessors
4441     ///////////////////////////////////////////////////////////////////////////
4442 
4443 
4444     /**
4445      * Provides a reference to the calling fiber or null if no fiber is
4446      * currently active.
4447      *
4448      * Returns:
4449      *  The fiber object representing the calling fiber or null if no fiber
4450      *  is currently active within this thread. The result of deleting this object is undefined.
4451      */
4452     static Fiber getThis() @safe nothrow @nogc
4453     {
4454         return sm_this;
4455     }
4456 
4457 
4458     ///////////////////////////////////////////////////////////////////////////
4459     // Static Initialization
4460     ///////////////////////////////////////////////////////////////////////////
4461 
4462 
4463     version (Posix)
4464     {
4465         static this()
4466         {
4467             static if ( __traits( compiles, ucontext_t ) )
4468             {
4469               int status = getcontext( &sm_utxt );
4470               assert( status == 0 );
4471             }
4472         }
4473     }
4474 
4475 private:
4476     //
4477     // Initializes a fiber object which has no associated executable function.
4478     //
4479     this() @safe pure nothrow @nogc
4480     {
4481         m_call = Call.NO;
4482     }
4483 
4484 
4485     //
4486     // Fiber entry point.  Invokes the function or delegate passed on
4487     // construction (if any).
4488     //
4489     final void run()
4490     {
4491         switch ( m_call )
4492         {
4493         case Call.FN:
4494             m_fn();
4495             break;
4496         case Call.DG:
4497             m_dg();
4498             break;
4499         default:
4500             break;
4501         }
4502     }
4503 
4504 
4505 private:
4506     //
4507     // The type of routine passed on fiber construction.
4508     //
4509     enum Call
4510     {
4511         NO,
4512         FN,
4513         DG
4514     }
4515 
4516 
4517     //
4518     // Standard fiber data
4519     //
4520     Call                m_call;
4521     union
4522     {
4523         void function() m_fn;
4524         void delegate() m_dg;
4525     }
4526     bool                m_isRunning;
4527     Throwable           m_unhandled;
4528     State               m_state;
4529 
4530 
4531 private:
4532     ///////////////////////////////////////////////////////////////////////////
4533     // Stack Management
4534     ///////////////////////////////////////////////////////////////////////////
4535 
4536 
4537     //
4538     // Allocate a new stack for this fiber.
4539     //
4540     final void allocStack( size_t sz, size_t guardPageSize ) nothrow
4541     in
4542     {
4543         assert( !m_pmem && !m_ctxt );
4544     }
4545     body
4546     {
4547         // adjust alloc size to a multiple of PAGESIZE
4548         sz += PAGESIZE - 1;
4549         sz -= sz % PAGESIZE;
4550 
4551         // NOTE: This instance of Thread.Context is dynamic so Fiber objects
4552         //       can be collected by the GC so long as no user level references
4553         //       to the object exist.  If m_ctxt were not dynamic then its
4554         //       presence in the global context list would be enough to keep
4555         //       this object alive indefinitely.  An alternative to allocating
4556         //       room for this struct explicitly would be to mash it into the
4557         //       base of the stack being allocated below.  However, doing so
4558         //       requires too much special logic to be worthwhile.
4559         m_ctxt = new Thread.Context;
4560 
4561         static if ( __traits( compiles, VirtualAlloc ) )
4562         {
4563             // reserve memory for stack
4564             m_pmem = VirtualAlloc( null,
4565                                    sz + guardPageSize,
4566                                    MEM_RESERVE,
4567                                    PAGE_NOACCESS );
4568             if ( !m_pmem )
4569                 onOutOfMemoryError();
4570 
4571             version (StackGrowsDown)
4572             {
4573                 void* stack = m_pmem + guardPageSize;
4574                 void* guard = m_pmem;
4575                 void* pbase = stack + sz;
4576             }
4577             else
4578             {
4579                 void* stack = m_pmem;
4580                 void* guard = m_pmem + sz;
4581                 void* pbase = stack;
4582             }
4583 
4584             // allocate reserved stack segment
4585             stack = VirtualAlloc( stack,
4586                                   sz,
4587                                   MEM_COMMIT,
4588                                   PAGE_READWRITE );
4589             if ( !stack )
4590                 onOutOfMemoryError();
4591 
4592             if (guardPageSize)
4593             {
4594                 // allocate reserved guard page
4595                 guard = VirtualAlloc( guard,
4596                                       guardPageSize,
4597                                       MEM_COMMIT,
4598                                       PAGE_READWRITE | PAGE_GUARD );
4599                 if ( !guard )
4600                     onOutOfMemoryError();
4601             }
4602 
4603             m_ctxt.bstack = pbase;
4604             m_ctxt.tstack = pbase;
4605             m_size = sz;
4606         }
4607         else
4608         {
4609             version (Posix) import core.sys.posix.sys.mman; // mmap
4610             version (FreeBSD) import core.sys.freebsd.sys.mman : MAP_ANON;
4611             version (NetBSD) import core.sys.netbsd.sys.mman : MAP_ANON;
4612             version (DragonFlyBSD) import core.sys.dragonflybsd.sys.mman : MAP_ANON;
4613             version (CRuntime_Glibc) import core.sys.linux.sys.mman : MAP_ANON;
4614             version (Darwin) import core.sys.darwin.sys.mman : MAP_ANON;
4615             version (CRuntime_UClibc) import core.sys.linux.sys.mman : MAP_ANON;
4616 
4617             static if ( __traits( compiles, mmap ) )
4618             {
4619                 // Allocate more for the memory guard
4620                 sz += guardPageSize;
4621 
4622                 m_pmem = mmap( null,
4623                                sz,
4624                                PROT_READ | PROT_WRITE,
4625                                MAP_PRIVATE | MAP_ANON,
4626                                -1,
4627                                0 );
4628                 if ( m_pmem == MAP_FAILED )
4629                     m_pmem = null;
4630             }
4631             else static if ( __traits( compiles, valloc ) )
4632             {
4633                 m_pmem = valloc( sz );
4634             }
4635             else static if ( __traits( compiles, malloc ) )
4636             {
4637                 m_pmem = malloc( sz );
4638             }
4639             else
4640             {
4641                 m_pmem = null;
4642             }
4643 
4644             if ( !m_pmem )
4645                 onOutOfMemoryError();
4646 
4647             version (StackGrowsDown)
4648             {
4649                 m_ctxt.bstack = m_pmem + sz;
4650                 m_ctxt.tstack = m_pmem + sz;
4651                 void* guard = m_pmem;
4652             }
4653             else
4654             {
4655                 m_ctxt.bstack = m_pmem;
4656                 m_ctxt.tstack = m_pmem;
4657                 void* guard = m_pmem + sz - guardPageSize;
4658             }
4659             m_size = sz;
4660 
4661             static if ( __traits( compiles, mmap ) )
4662             {
4663                 if (guardPageSize)
4664                 {
4665                     // protect end of stack
4666                     if ( mprotect(guard, guardPageSize, PROT_NONE) == -1 )
4667                         abort();
4668                 }
4669             }
4670             else
4671             {
4672                 // Supported only for mmap allocated memory - results are
4673                 // undefined if applied to memory not obtained by mmap
4674             }
4675         }
4676 
4677         Thread.add( m_ctxt );
4678     }
4679 
4680 
4681     //
4682     // Free this fiber's stack.
4683     //
4684     final void freeStack() nothrow @nogc
4685     in
4686     {
4687         assert( m_pmem && m_ctxt );
4688     }
4689     body
4690     {
4691         // NOTE: m_ctxt is guaranteed to be alive because it is held in the
4692         //       global context list.
4693         Thread.slock.lock_nothrow();
4694         scope(exit) Thread.slock.unlock_nothrow();
4695         Thread.remove( m_ctxt );
4696 
4697         static if ( __traits( compiles, VirtualAlloc ) )
4698         {
4699             VirtualFree( m_pmem, 0, MEM_RELEASE );
4700         }
4701         else
4702         {
4703             import core.sys.posix.sys.mman; // munmap
4704 
4705             static if ( __traits( compiles, mmap ) )
4706             {
4707                 munmap( m_pmem, m_size );
4708             }
4709             else static if ( __traits( compiles, valloc ) )
4710             {
4711                 free( m_pmem );
4712             }
4713             else static if ( __traits( compiles, malloc ) )
4714             {
4715                 free( m_pmem );
4716             }
4717         }
4718         m_pmem = null;
4719         m_ctxt = null;
4720     }
4721 
4722 
4723     //
4724     // Initialize the allocated stack.
4725     // Look above the definition of 'class Fiber' for some information about the implementation of this routine
4726     //
4727     final void initStack() nothrow @nogc
4728     in
4729     {
4730         assert( m_ctxt.tstack && m_ctxt.tstack == m_ctxt.bstack );
4731         assert( cast(size_t) m_ctxt.bstack % (void*).sizeof == 0 );
4732     }
4733     body
4734     {
4735         void* pstack = m_ctxt.tstack;
4736         scope( exit )  m_ctxt.tstack = pstack;
4737 
4738         void push( size_t val ) nothrow
4739         {
4740             version (StackGrowsDown)
4741             {
4742                 pstack -= size_t.sizeof;
4743                 *(cast(size_t*) pstack) = val;
4744             }
4745             else
4746             {
4747                 pstack += size_t.sizeof;
4748                 *(cast(size_t*) pstack) = val;
4749             }
4750         }
4751 
4752         // NOTE: On OS X the stack must be 16-byte aligned according
4753         // to the IA-32 call spec. For x86_64 the stack also needs to
4754         // be aligned to 16-byte according to SysV AMD64 ABI.
4755         version (AlignFiberStackTo16Byte)
4756         {
4757             version (StackGrowsDown)
4758             {
4759                 pstack = cast(void*)(cast(size_t)(pstack) - (cast(size_t)(pstack) & 0x0F));
4760             }
4761             else
4762             {
4763                 pstack = cast(void*)(cast(size_t)(pstack) + (cast(size_t)(pstack) & 0x0F));
4764             }
4765         }
4766 
4767         version (AsmX86_Windows)
4768         {
4769             version (StackGrowsDown) {} else static assert( false );
4770 
4771             // On Windows Server 2008 and 2008 R2, an exploit mitigation
4772             // technique known as SEHOP is activated by default. To avoid
4773             // hijacking of the exception handler chain, the presence of a
4774             // Windows-internal handler (ntdll.dll!FinalExceptionHandler) at
4775             // its end is tested by RaiseException. If it is not present, all
4776             // handlers are disregarded, and the program is thus aborted
4777             // (see http://blogs.technet.com/b/srd/archive/2009/02/02/
4778             // preventing-the-exploitation-of-seh-overwrites-with-sehop.aspx).
4779             // For new threads, this handler is installed by Windows immediately
4780             // after creation. To make exception handling work in fibers, we
4781             // have to insert it for our new stacks manually as well.
4782             //
4783             // To do this, we first determine the handler by traversing the SEH
4784             // chain of the current thread until its end, and then construct a
4785             // registration block for the last handler on the newly created
4786             // thread. We then continue to push all the initial register values
4787             // for the first context switch as for the other implementations.
4788             //
4789             // Note that this handler is never actually invoked, as we install
4790             // our own one on top of it in the fiber entry point function.
4791             // Thus, it should not have any effects on OSes not implementing
4792             // exception chain verification.
4793 
4794             alias fp_t = void function(); // Actual signature not relevant.
4795             static struct EXCEPTION_REGISTRATION
4796             {
4797                 EXCEPTION_REGISTRATION* next; // sehChainEnd if last one.
4798                 fp_t handler;
4799             }
4800             enum sehChainEnd = cast(EXCEPTION_REGISTRATION*) 0xFFFFFFFF;
4801 
4802             __gshared static fp_t finalHandler = null;
4803             if ( finalHandler is null )
4804             {
4805                 static EXCEPTION_REGISTRATION* fs0() nothrow
4806                 {
4807                     asm pure nothrow @nogc
4808                     {
4809                         naked;
4810                         mov EAX, FS:[0];
4811                         ret;
4812                     }
4813                 }
4814                 auto reg = fs0();
4815                 while ( reg.next != sehChainEnd ) reg = reg.next;
4816 
4817                 // Benign races are okay here, just to avoid re-lookup on every
4818                 // fiber creation.
4819                 finalHandler = reg.handler;
4820             }
4821 
4822             // When linking with /safeseh (supported by LDC, but not DMD)
4823             // the exception chain must not extend to the very top
4824             // of the stack, otherwise the exception chain is also considered
4825             // invalid. Reserving additional 4 bytes at the top of the stack will
4826             // keep the EXCEPTION_REGISTRATION below that limit
4827             size_t reserve = EXCEPTION_REGISTRATION.sizeof + 4;
4828             pstack -= reserve;
4829             *(cast(EXCEPTION_REGISTRATION*)pstack) =
4830                 EXCEPTION_REGISTRATION( sehChainEnd, finalHandler );
4831 
4832             push( cast(size_t) &fiber_entryPoint );                 // EIP
4833             push( cast(size_t) m_ctxt.bstack - reserve );           // EBP
4834             push( 0x00000000 );                                     // EDI
4835             push( 0x00000000 );                                     // ESI
4836             push( 0x00000000 );                                     // EBX
4837             push( cast(size_t) m_ctxt.bstack - reserve );           // FS:[0]
4838             push( cast(size_t) m_ctxt.bstack );                     // FS:[4]
4839             push( cast(size_t) m_ctxt.bstack - m_size );            // FS:[8]
4840             push( 0x00000000 );                                     // EAX
4841         }
4842         else version (AsmX86_64_Windows)
4843         {
4844             // Using this trampoline instead of the raw fiber_entryPoint
4845             // ensures that during context switches, source and destination
4846             // stacks have the same alignment. Otherwise, the stack would need
4847             // to be shifted by 8 bytes for the first call, as fiber_entryPoint
4848             // is an actual function expecting a stack which is not aligned
4849             // to 16 bytes.
4850             static void trampoline()
4851             {
4852                 asm pure nothrow @nogc
4853                 {
4854                     naked;
4855                     sub RSP, 32; // Shadow space (Win64 calling convention)
4856                     call fiber_entryPoint;
4857                     xor RCX, RCX; // This should never be reached, as
4858                     jmp RCX;      // fiber_entryPoint must never return.
4859                 }
4860             }
4861 
4862             push( cast(size_t) &trampoline );                       // RIP
4863             push( 0x00000000_00000000 );                            // RBP
4864             push( 0x00000000_00000000 );                            // R12
4865             push( 0x00000000_00000000 );                            // R13
4866             push( 0x00000000_00000000 );                            // R14
4867             push( 0x00000000_00000000 );                            // R15
4868             push( 0x00000000_00000000 );                            // RDI
4869             push( 0x00000000_00000000 );                            // RSI
4870             push( 0x00000000_00000000 );                            // XMM6 (high)
4871             push( 0x00000000_00000000 );                            // XMM6 (low)
4872             push( 0x00000000_00000000 );                            // XMM7 (high)
4873             push( 0x00000000_00000000 );                            // XMM7 (low)
4874             push( 0x00000000_00000000 );                            // XMM8 (high)
4875             push( 0x00000000_00000000 );                            // XMM8 (low)
4876             push( 0x00000000_00000000 );                            // XMM9 (high)
4877             push( 0x00000000_00000000 );                            // XMM9 (low)
4878             push( 0x00000000_00000000 );                            // XMM10 (high)
4879             push( 0x00000000_00000000 );                            // XMM10 (low)
4880             push( 0x00000000_00000000 );                            // XMM11 (high)
4881             push( 0x00000000_00000000 );                            // XMM11 (low)
4882             push( 0x00000000_00000000 );                            // XMM12 (high)
4883             push( 0x00000000_00000000 );                            // XMM12 (low)
4884             push( 0x00000000_00000000 );                            // XMM13 (high)
4885             push( 0x00000000_00000000 );                            // XMM13 (low)
4886             push( 0x00000000_00000000 );                            // XMM14 (high)
4887             push( 0x00000000_00000000 );                            // XMM14 (low)
4888             push( 0x00000000_00000000 );                            // XMM15 (high)
4889             push( 0x00000000_00000000 );                            // XMM15 (low)
4890             push( 0x00000000_00000000 );                            // RBX
4891             push( 0xFFFFFFFF_FFFFFFFF );                            // GS:[0]
4892             version (StackGrowsDown)
4893             {
4894                 push( cast(size_t) m_ctxt.bstack );                 // GS:[8]
4895                 push( cast(size_t) m_ctxt.bstack - m_size );        // GS:[16]
4896             }
4897             else
4898             {
4899                 push( cast(size_t) m_ctxt.bstack );                 // GS:[8]
4900                 push( cast(size_t) m_ctxt.bstack + m_size );        // GS:[16]
4901             }
4902         }
4903         else version (AsmX86_Posix)
4904         {
4905             push( 0x00000000 );                                     // Return address of fiber_entryPoint call
4906             push( cast(size_t) &fiber_entryPoint );                 // EIP
4907             push( cast(size_t) m_ctxt.bstack );                     // EBP
4908             push( 0x00000000 );                                     // EDI
4909             push( 0x00000000 );                                     // ESI
4910             push( 0x00000000 );                                     // EBX
4911             push( 0x00000000 );                                     // EAX
4912         }
4913         else version (AsmX86_64_Posix)
4914         {
4915             push( 0x00000000_00000000 );                            // Return address of fiber_entryPoint call
4916             push( cast(size_t) &fiber_entryPoint );                 // RIP
4917             push( cast(size_t) m_ctxt.bstack );                     // RBP
4918             push( 0x00000000_00000000 );                            // RBX
4919             push( 0x00000000_00000000 );                            // R12
4920             push( 0x00000000_00000000 );                            // R13
4921             push( 0x00000000_00000000 );                            // R14
4922             push( 0x00000000_00000000 );                            // R15
4923         }
4924         else version (AsmPPC_Posix)
4925         {
4926             version (StackGrowsDown)
4927             {
4928                 pstack -= int.sizeof * 5;
4929             }
4930             else
4931             {
4932                 pstack += int.sizeof * 5;
4933             }
4934 
4935             push( cast(size_t) &fiber_entryPoint );     // link register
4936             push( 0x00000000 );                         // control register
4937             push( 0x00000000 );                         // old stack pointer
4938 
4939             // GPR values
4940             version (StackGrowsDown)
4941             {
4942                 pstack -= int.sizeof * 20;
4943             }
4944             else
4945             {
4946                 pstack += int.sizeof * 20;
4947             }
4948 
4949             assert( (cast(size_t) pstack & 0x0f) == 0 );
4950         }
4951         else version (AsmMIPS_O32_Posix)
4952         {
4953             version (StackGrowsDown) {}
4954             else static assert(0);
4955 
4956             /* We keep the FP registers and the return address below
4957              * the stack pointer, so they don't get scanned by the
4958              * GC. The last frame before swapping the stack pointer is
4959              * organized like the following.
4960              *
4961              *     |-----------|<= frame pointer
4962              *     |    $gp    |
4963              *     |   $s0-8   |
4964              *     |-----------|<= stack pointer
4965              *     |    $ra    |
4966              *     |  align(8) |
4967              *     |  $f20-30  |
4968              *     |-----------|
4969              *
4970              */
4971             enum SZ_GP = 10 * size_t.sizeof; // $gp + $s0-8
4972             enum SZ_RA = size_t.sizeof;      // $ra
4973             version (MIPS_HardFloat)
4974             {
4975                 enum SZ_FP = 6 * 8;          // $f20-30
4976                 enum ALIGN = -(SZ_FP + SZ_RA) & (8 - 1);
4977             }
4978             else
4979             {
4980                 enum SZ_FP = 0;
4981                 enum ALIGN = 0;
4982             }
4983 
4984             enum BELOW = SZ_FP + ALIGN + SZ_RA;
4985             enum ABOVE = SZ_GP;
4986             enum SZ = BELOW + ABOVE;
4987 
4988             (cast(ubyte*)pstack - SZ)[0 .. SZ] = 0;
4989             pstack -= ABOVE;
4990             *cast(size_t*)(pstack - SZ_RA) = cast(size_t)&fiber_entryPoint;
4991         }
4992         else version (AsmAArch64_Posix)
4993         {
4994             // Like others, FP registers and return address (lr) are kept
4995             // below the saved stack top (tstack) to hide from GC scanning.
4996             // fiber_switchContext expects newp sp to look like this:
4997             //   19: x19
4998             //   ...
4999             //    9: x29 (fp)  <-- newp tstack
5000             //    8: x30 (lr)  [&fiber_entryPoint]
5001             //    7: d8
5002             //   ...
5003             //    0: d15
5004 
5005             version (StackGrowsDown) {}
5006             else
5007                 static assert(false, "Only full descending stacks supported on AArch64");
5008 
5009             // Only need to set return address (lr).  Everything else is fine
5010             // zero initialized.
5011             pstack -= size_t.sizeof * 11;    // skip past x19-x29
5012             push(cast(size_t) &fiber_trampoline); // see threadasm.S for docs
5013             pstack += size_t.sizeof;         // adjust sp (newp) above lr
5014         }
5015         else version (AsmARM_Posix)
5016         {
5017             /* We keep the FP registers and the return address below
5018              * the stack pointer, so they don't get scanned by the
5019              * GC. The last frame before swapping the stack pointer is
5020              * organized like the following.
5021              *
5022              *   |  |-----------|<= 'frame starts here'
5023              *   |  |     fp    | (the actual frame pointer, r11 isn't
5024              *   |  |   r10-r4  |  updated and still points to the previous frame)
5025              *   |  |-----------|<= stack pointer
5026              *   |  |     lr    |
5027              *   |  | 4byte pad |
5028              *   |  |   d15-d8  |(if FP supported)
5029              *   |  |-----------|
5030              *   Y
5031              *   stack grows down: The pointer value here is smaller than some lines above
5032              */
5033             // frame pointer can be zero, r10-r4 also zero initialized
5034             version (StackGrowsDown)
5035                 pstack -= int.sizeof * 8;
5036             else
5037                 static assert(false, "Only full descending stacks supported on ARM");
5038 
5039             // link register
5040             push( cast(size_t) &fiber_entryPoint );
5041             /*
5042              * We do not push padding and d15-d8 as those are zero initialized anyway
5043              * Position the stack pointer above the lr register
5044              */
5045             pstack += int.sizeof * 1;
5046         }
5047         else version (GNU_AsmX86_Windows)
5048         {
5049             version (StackGrowsDown) {} else static assert( false );
5050 
5051             // Currently, MinGW doesn't utilize SEH exceptions.
5052             // See DMD AsmX86_Windows If this code ever becomes fails and SEH is used.
5053 
5054             push( 0x00000000 );                                     // Return address of fiber_entryPoint call
5055             push( cast(size_t) &fiber_entryPoint );                 // EIP
5056             push( 0x00000000 );                                     // EBP
5057             push( 0x00000000 );                                     // EDI
5058             push( 0x00000000 );                                     // ESI
5059             push( 0x00000000 );                                     // EBX
5060             push( 0xFFFFFFFF );                                     // FS:[0] - Current SEH frame
5061             push( cast(size_t) m_ctxt.bstack );                     // FS:[4] - Top of stack
5062             push( cast(size_t) m_ctxt.bstack - m_size );            // FS:[8] - Bottom of stack
5063             push( 0x00000000 );                                     // EAX
5064         }
5065         else version (GNU_AsmX86_64_Windows)
5066         {
5067             push( 0x00000000_00000000 );                            // Return address of fiber_entryPoint call
5068             push( cast(size_t) &fiber_entryPoint );                 // RIP
5069             push( 0x00000000_00000000 );                            // RBP
5070             push( 0x00000000_00000000 );                            // RBX
5071             push( 0x00000000_00000000 );                            // R12
5072             push( 0x00000000_00000000 );                            // R13
5073             push( 0x00000000_00000000 );                            // R14
5074             push( 0x00000000_00000000 );                            // R15
5075             push( 0xFFFFFFFF_FFFFFFFF );                            // GS:[0] - Current SEH frame
5076             version (StackGrowsDown)
5077             {
5078                 push( cast(size_t) m_ctxt.bstack );                 // GS:[8]  - Top of stack
5079                 push( cast(size_t) m_ctxt.bstack - m_size );        // GS:[16] - Bottom of stack
5080             }
5081             else
5082             {
5083                 push( cast(size_t) m_ctxt.bstack );                 // GS:[8]  - Top of stack
5084                 push( cast(size_t) m_ctxt.bstack + m_size );        // GS:[16] - Bottom of stack
5085             }
5086         }
5087         else static if ( __traits( compiles, ucontext_t ) )
5088         {
5089             getcontext( &m_utxt );
5090             m_utxt.uc_stack.ss_sp   = m_pmem;
5091             m_utxt.uc_stack.ss_size = m_size;
5092             makecontext( &m_utxt, &fiber_entryPoint, 0 );
5093             // NOTE: If ucontext is being used then the top of the stack will
5094             //       be a pointer to the ucontext_t struct for that fiber.
5095             push( cast(size_t) &m_utxt );
5096         }
5097         else
5098             static assert(0, "Not implemented");
5099     }
5100 
5101 
5102     Thread.Context* m_ctxt;
5103     size_t          m_size;
5104     void*           m_pmem;
5105 
5106     static if ( __traits( compiles, ucontext_t ) )
5107     {
5108         // NOTE: The static ucontext instance is used to represent the context
5109         //       of the executing thread.
5110         static ucontext_t       sm_utxt = void;
5111         ucontext_t              m_utxt  = void;
5112         ucontext_t*             m_ucur  = null;
5113     }
5114 
5115 
5116 private:
5117     ///////////////////////////////////////////////////////////////////////////
5118     // Storage of Active Fiber
5119     ///////////////////////////////////////////////////////////////////////////
5120 
5121 
5122     //
5123     // Sets a thread-local reference to the current fiber object.
5124     //
5125     static void setThis( Fiber f ) nothrow @nogc
5126     {
5127         sm_this = f;
5128     }
5129 
5130     static Fiber sm_this;
5131 
5132 
5133 private:
5134     ///////////////////////////////////////////////////////////////////////////
5135     // Context Switching
5136     ///////////////////////////////////////////////////////////////////////////
5137 
5138 
5139     //
5140     // Switches into the stack held by this fiber.
5141     //
5142     final void switchIn() nothrow @nogc
5143     {
5144         Thread  tobj = Thread.getThis();
5145         void**  oldp = &tobj.m_curr.tstack;
5146         void*   newp = m_ctxt.tstack;
5147 
5148         // NOTE: The order of operations here is very important.  The current
5149         //       stack top must be stored before m_lock is set, and pushContext
5150         //       must not be called until after m_lock is set.  This process
5151         //       is intended to prevent a race condition with the suspend
5152         //       mechanism used for garbage collection.  If it is not followed,
5153         //       a badly timed collection could cause the GC to scan from the
5154         //       bottom of one stack to the top of another, or to miss scanning
5155         //       a stack that still contains valid data.  The old stack pointer
5156         //       oldp will be set again before the context switch to guarantee
5157         //       that it points to exactly the correct stack location so the
5158         //       successive pop operations will succeed.
5159         *oldp = getStackTop();
5160         atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, true);
5161         tobj.pushContext( m_ctxt );
5162 
5163         fiber_switchContext( oldp, newp );
5164 
5165         // NOTE: As above, these operations must be performed in a strict order
5166         //       to prevent Bad Things from happening.
5167         tobj.popContext();
5168         atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, false);
5169         tobj.m_curr.tstack = tobj.m_curr.bstack;
5170     }
5171 
5172 
5173     //
5174     // Switches out of the current stack and into the enclosing stack.
5175     //
5176     final void switchOut() nothrow @nogc
5177     {
5178         Thread  tobj = Thread.getThis();
5179         void**  oldp = &m_ctxt.tstack;
5180         void*   newp = tobj.m_curr.within.tstack;
5181 
5182         // NOTE: The order of operations here is very important.  The current
5183         //       stack top must be stored before m_lock is set, and pushContext
5184         //       must not be called until after m_lock is set.  This process
5185         //       is intended to prevent a race condition with the suspend
5186         //       mechanism used for garbage collection.  If it is not followed,
5187         //       a badly timed collection could cause the GC to scan from the
5188         //       bottom of one stack to the top of another, or to miss scanning
5189         //       a stack that still contains valid data.  The old stack pointer
5190         //       oldp will be set again before the context switch to guarantee
5191         //       that it points to exactly the correct stack location so the
5192         //       successive pop operations will succeed.
5193         *oldp = getStackTop();
5194         atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, true);
5195 
5196         fiber_switchContext( oldp, newp );
5197 
5198         // NOTE: As above, these operations must be performed in a strict order
5199         //       to prevent Bad Things from happening.
5200         // NOTE: If use of this fiber is multiplexed across threads, the thread
5201         //       executing here may be different from the one above, so get the
5202         //       current thread handle before unlocking, etc.
5203         tobj = Thread.getThis();
5204         atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, false);
5205         tobj.m_curr.tstack = tobj.m_curr.bstack;
5206     }
5207 }
5208 
5209 
5210 version (unittest)
5211 {
5212     class TestFiber : Fiber
5213     {
5214         this()
5215         {
5216             super(&run);
5217         }
5218 
5219         void run()
5220         {
5221             foreach (i; 0 .. 1000)
5222             {
5223                 sum += i;
5224                 Fiber.yield();
5225             }
5226         }
5227 
5228         enum expSum = 1000 * 999 / 2;
5229         size_t sum;
5230     }
5231 
5232     void runTen()
5233     {
5234         TestFiber[10] fibs;
5235         foreach (ref fib; fibs)
5236             fib = new TestFiber();
5237 
5238         bool cont;
5239         do {
5240             cont = false;
5241             foreach (fib; fibs) {
5242                 if (fib.state == Fiber.State.HOLD)
5243                 {
5244                     fib.call();
5245                     cont |= fib.state != Fiber.State.TERM;
5246                 }
5247             }
5248         } while (cont);
5249 
5250         foreach (fib; fibs)
5251         {
5252             assert(fib.sum == TestFiber.expSum);
5253         }
5254     }
5255 }
5256 
5257 
5258 // Single thread running separate fibers
5259 unittest
5260 {
5261     runTen();
5262 }
5263 
5264 
5265 // Multiple threads running separate fibers
5266 unittest
5267 {
5268     auto group = new ThreadGroup();
5269     foreach (_; 0 .. 4)
5270     {
5271         group.create(&runTen);
5272     }
5273     group.joinAll();
5274 }
5275 
5276 
5277 // Multiple threads running shared fibers
5278 unittest
5279 {
5280     shared bool[10] locks;
5281     TestFiber[10] fibs;
5282 
5283     void runShared()
5284     {
5285         bool cont;
5286         do {
5287             cont = false;
5288             foreach (idx; 0 .. 10)
5289             {
5290                 if (cas(&locks[idx], false, true))
5291                 {
5292                     if (fibs[idx].state == Fiber.State.HOLD)
5293                     {
5294                         fibs[idx].call();
5295                         cont |= fibs[idx].state != Fiber.State.TERM;
5296                     }
5297                     locks[idx] = false;
5298                 }
5299                 else
5300                 {
5301                     cont = true;
5302                 }
5303             }
5304         } while (cont);
5305     }
5306 
5307     foreach (ref fib; fibs)
5308     {
5309         fib = new TestFiber();
5310     }
5311 
5312     auto group = new ThreadGroup();
5313     foreach (_; 0 .. 4)
5314     {
5315         group.create(&runShared);
5316     }
5317     group.joinAll();
5318 
5319     foreach (fib; fibs)
5320     {
5321         assert(fib.sum == TestFiber.expSum);
5322     }
5323 }
5324 
5325 
5326 // Test exception handling inside fibers.
5327 version (Win32) {
5328     // broken on win32 under windows server 2012: bug 13821
5329 } else unittest {
5330     enum MSG = "Test message.";
5331     string caughtMsg;
5332     (new Fiber({
5333         try
5334         {
5335             throw new Exception(MSG);
5336         }
5337         catch (Exception e)
5338         {
5339             caughtMsg = e.msg;
5340         }
5341     })).call();
5342     assert(caughtMsg == MSG);
5343 }
5344 
5345 
5346 unittest
5347 {
5348     int x = 0;
5349 
5350     (new Fiber({
5351         x++;
5352     })).call();
5353     assert( x == 1 );
5354 }
5355 
5356 nothrow unittest
5357 {
5358     new Fiber({}).call!(Fiber.Rethrow.no)();
5359 }
5360 
5361 unittest
5362 {
5363     new Fiber({}).call(Fiber.Rethrow.yes);
5364     new Fiber({}).call(Fiber.Rethrow.no);
5365 }
5366 
5367 deprecated unittest
5368 {
5369     new Fiber({}).call(true);
5370     new Fiber({}).call(false);
5371 }
5372 
5373 version (Win32) {
5374     // broken on win32 under windows server 2012: bug 13821
5375 } else unittest {
5376     enum MSG = "Test message.";
5377 
5378     try
5379     {
5380         (new Fiber({
5381             throw new Exception( MSG );
5382         })).call();
5383         assert( false, "Expected rethrown exception." );
5384     }
5385     catch ( Throwable t )
5386     {
5387         assert( t.msg == MSG );
5388     }
5389 }
5390 
5391 // Test exception chaining when switching contexts in finally blocks.
5392 unittest
5393 {
5394     static void throwAndYield(string msg) {
5395       try {
5396         throw new Exception(msg);
5397       } finally {
5398         Fiber.yield();
5399       }
5400     }
5401 
5402     static void fiber(string name) {
5403       try {
5404         try {
5405           throwAndYield(name ~ ".1");
5406         } finally {
5407           throwAndYield(name ~ ".2");
5408         }
5409       } catch (Exception e) {
5410         assert(e.msg == name ~ ".1");
5411         assert(e.next);
5412         assert(e.next.msg == name ~ ".2");
5413         assert(!e.next.next);
5414       }
5415     }
5416 
5417     auto first = new Fiber(() => fiber("first"));
5418     auto second = new Fiber(() => fiber("second"));
5419     first.call();
5420     second.call();
5421     first.call();
5422     second.call();
5423     first.call();
5424     second.call();
5425     assert(first.state == Fiber.State.TERM);
5426     assert(second.state == Fiber.State.TERM);
5427 }
5428 
5429 // Test Fiber resetting
5430 unittest
5431 {
5432     static string method;
5433 
5434     static void foo()
5435     {
5436         method = "foo";
5437     }
5438 
5439     void bar()
5440     {
5441         method = "bar";
5442     }
5443 
5444     static void expect(Fiber fib, string s)
5445     {
5446         assert(fib.state == Fiber.State.HOLD);
5447         fib.call();
5448         assert(fib.state == Fiber.State.TERM);
5449         assert(method == s); method = null;
5450     }
5451     auto fib = new Fiber(&foo);
5452     expect(fib, "foo");
5453 
5454     fib.reset();
5455     expect(fib, "foo");
5456 
5457     fib.reset(&foo);
5458     expect(fib, "foo");
5459 
5460     fib.reset(&bar);
5461     expect(fib, "bar");
5462 
5463     fib.reset(function void(){method = "function";});
5464     expect(fib, "function");
5465 
5466     fib.reset(delegate void(){method = "delegate";});
5467     expect(fib, "delegate");
5468 }
5469 
5470 // Test unsafe reset in hold state
5471 unittest
5472 {
5473     auto fib = new Fiber(function {ubyte[2048] buf = void; Fiber.yield();}, 4096);
5474     foreach (_; 0 .. 10)
5475     {
5476         fib.call();
5477         assert(fib.state == Fiber.State.HOLD);
5478         fib.reset();
5479     }
5480 }
5481 
5482 // stress testing GC stack scanning
5483 unittest
5484 {
5485     import core.memory;
5486 
5487     static void unreferencedThreadObject()
5488     {
5489         static void sleep() { Thread.sleep(dur!"msecs"(100)); }
5490         auto thread = new Thread(&sleep).start();
5491     }
5492     unreferencedThreadObject();
5493     GC.collect();
5494 
5495     static class Foo
5496     {
5497         this(int value)
5498         {
5499             _value = value;
5500         }
5501 
5502         int bar()
5503         {
5504             return _value;
5505         }
5506 
5507         int _value;
5508     }
5509 
5510     static void collect()
5511     {
5512         auto foo = new Foo(2);
5513         assert(foo.bar() == 2);
5514         GC.collect();
5515         Fiber.yield();
5516         GC.collect();
5517         assert(foo.bar() == 2);
5518     }
5519 
5520     auto fiber = new Fiber(&collect);
5521 
5522     fiber.call();
5523     GC.collect();
5524     fiber.call();
5525 
5526     // thread reference
5527     auto foo = new Foo(2);
5528 
5529     void collect2()
5530     {
5531         assert(foo.bar() == 2);
5532         GC.collect();
5533         Fiber.yield();
5534         GC.collect();
5535         assert(foo.bar() == 2);
5536     }
5537 
5538     fiber = new Fiber(&collect2);
5539 
5540     fiber.call();
5541     GC.collect();
5542     fiber.call();
5543 
5544     static void recurse(size_t cnt)
5545     {
5546         --cnt;
5547         Fiber.yield();
5548         if (cnt)
5549         {
5550             auto fib = new Fiber(() { recurse(cnt); });
5551             fib.call();
5552             GC.collect();
5553             fib.call();
5554         }
5555     }
5556     fiber = new Fiber(() { recurse(20); });
5557     fiber.call();
5558 }
5559 
5560 
5561 version (AsmX86_64_Windows)
5562 {
5563     // Test Windows x64 calling convention
5564     unittest
5565     {
5566         void testNonvolatileRegister(alias REG)()
5567         {
5568             auto zeroRegister = new Fiber(() {
5569                 mixin("asm pure nothrow @nogc { naked; xor "~REG~", "~REG~"; ret; }");
5570             });
5571             long after;
5572 
5573             mixin("asm pure nothrow @nogc { mov "~REG~", 0xFFFFFFFFFFFFFFFF; }");
5574             zeroRegister.call();
5575             mixin("asm pure nothrow @nogc { mov after, "~REG~"; }");
5576 
5577             assert(after == -1);
5578         }
5579 
5580         void testNonvolatileRegisterSSE(alias REG)()
5581         {
5582             auto zeroRegister = new Fiber(() {
5583                 mixin("asm pure nothrow @nogc { naked; xorpd "~REG~", "~REG~"; ret; }");
5584             });
5585             long[2] before = [0xFFFFFFFF_FFFFFFFF, 0xFFFFFFFF_FFFFFFFF], after;
5586 
5587             mixin("asm pure nothrow @nogc { movdqu "~REG~", before; }");
5588             zeroRegister.call();
5589             mixin("asm pure nothrow @nogc { movdqu after, "~REG~"; }");
5590 
5591             assert(before == after);
5592         }
5593 
5594         testNonvolatileRegister!("R12")();
5595         testNonvolatileRegister!("R13")();
5596         testNonvolatileRegister!("R14")();
5597         testNonvolatileRegister!("R15")();
5598         testNonvolatileRegister!("RDI")();
5599         testNonvolatileRegister!("RSI")();
5600         testNonvolatileRegister!("RBX")();
5601 
5602         testNonvolatileRegisterSSE!("XMM6")();
5603         testNonvolatileRegisterSSE!("XMM7")();
5604         testNonvolatileRegisterSSE!("XMM8")();
5605         testNonvolatileRegisterSSE!("XMM9")();
5606         testNonvolatileRegisterSSE!("XMM10")();
5607         testNonvolatileRegisterSSE!("XMM11")();
5608         testNonvolatileRegisterSSE!("XMM12")();
5609         testNonvolatileRegisterSSE!("XMM13")();
5610         testNonvolatileRegisterSSE!("XMM14")();
5611         testNonvolatileRegisterSSE!("XMM15")();
5612     }
5613 }
5614 
5615 
5616 version (D_InlineAsm_X86_64)
5617 {
5618     unittest
5619     {
5620         void testStackAlignment()
5621         {
5622             void* pRSP;
5623             asm pure nothrow @nogc
5624             {
5625                 mov pRSP, RSP;
5626             }
5627             assert((cast(size_t)pRSP & 0xF) == 0);
5628         }
5629 
5630         auto fib = new Fiber(&testStackAlignment);
5631         fib.call();
5632     }
5633 }
5634 
5635 // regression test for Issue 13416
5636 version (FreeBSD) unittest
5637 {
5638     static void loop()
5639     {
5640         pthread_attr_t attr;
5641         pthread_attr_init(&attr);
5642         auto thr = pthread_self();
5643         foreach (i; 0 .. 50)
5644             pthread_attr_get_np(thr, &attr);
5645         pthread_attr_destroy(&attr);
5646     }
5647 
5648     auto thr = new Thread(&loop).start();
5649     foreach (i; 0 .. 50)
5650     {
5651         thread_suspendAll();
5652         thread_resumeAll();
5653     }
5654     thr.join();
5655 }
5656 
5657 version (DragonFlyBSD) unittest
5658 {
5659     static void loop()
5660     {
5661         pthread_attr_t attr;
5662         pthread_attr_init(&attr);
5663         auto thr = pthread_self();
5664         foreach (i; 0 .. 50)
5665             pthread_attr_get_np(thr, &attr);
5666         pthread_attr_destroy(&attr);
5667     }
5668 
5669     auto thr = new Thread(&loop).start();
5670     foreach (i; 0 .. 50)
5671     {
5672         thread_suspendAll();
5673         thread_resumeAll();
5674     }
5675     thr.join();
5676 }
5677 
5678 unittest
5679 {
5680     // use >PAGESIZE to avoid stack overflow (e.g. in an syscall)
5681     auto thr = new Thread(function{}, 4096 + 1).start();
5682     thr.join();
5683 }
5684 
5685 /**
5686  * Represents the ID of a thread, as returned by $(D Thread.)$(LREF id).
5687  * The exact type varies from platform to platform.
5688  */
5689 version (Windows)
5690     alias ThreadID = uint;
5691 else
5692 version (Posix)
5693     alias ThreadID = pthread_t;
5694