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