]> git.llucax.com Git - software/druntime.git/blob - src/common/core/thread.d
* Changed top-level exception class name from 'Exception' to 'Throwable'.
[software/druntime.git] / src / common / core / thread.d
1 /**
2  * The thread module provides support for thread creation and management.
3  *
4  * Copyright: Copyright (c) 2005-2008, The D Runtime Project
5  * License:   BSD Style, see LICENSE
6  * Authors:   Sean Kelly
7  */
8 module core.thread;
9
10
11 // this should be true for most architectures
12 version = StackGrowsDown;
13
14
15 ///////////////////////////////////////////////////////////////////////////////
16 // Thread and Fiber Exceptions
17 ///////////////////////////////////////////////////////////////////////////////
18
19
20 /**
21  * Base class for thread exceptions.
22  */
23 class ThreadException : Exception
24 {
25     this( string msg )
26     {
27         super( msg );
28     }
29 }
30
31
32 /**
33  * Base class for fiber exceptions.
34  */
35 class FiberException : Exception
36 {
37     this( string msg )
38     {
39         super( msg );
40     }
41 }
42
43
44 private
45 {
46     //
47     // exposed by compiler runtime
48     //
49     extern (C) void* rt_stackBottom();
50     extern (C) void* rt_stackTop();
51
52
53     void* getStackBottom()
54     {
55         return rt_stackBottom();
56     }
57
58
59     void* getStackTop()
60     {
61         version( D_InlineAsm_X86 )
62         {
63             asm
64             {
65                 naked;
66                 mov EAX, ESP;
67                 ret;
68             }
69         }
70         else
71         {
72             return rt_stackTop();
73         }
74     }
75 }
76
77
78 ///////////////////////////////////////////////////////////////////////////////
79 // Thread Entry Point and Signal Handlers
80 ///////////////////////////////////////////////////////////////////////////////
81
82
83 version( Windows )
84 {
85     private
86     {
87         import stdc.stdint : uintptr_t; // for _beginthreadex decl below
88         import sys.windows.windows;
89
90         const DWORD TLS_OUT_OF_INDEXES  = 0xFFFFFFFF;
91
92         extern (Windows) alias uint function(void*) btex_fptr;
93         extern (C) uintptr_t _beginthreadex(void*, uint, btex_fptr, void*, uint, uint*);
94
95
96         //
97         // entry point for Windows threads
98         //
99         extern (Windows) uint thread_entryPoint( void* arg )
100         {
101             Thread  obj = cast(Thread) arg;
102             assert( obj );
103             scope( exit ) Thread.remove( obj );
104
105             assert( obj.m_curr is &obj.m_main );
106             obj.m_main.bstack = getStackBottom();
107             obj.m_main.tstack = obj.m_main.bstack;
108             Thread.add( &obj.m_main );
109             Thread.setThis( obj );
110
111             // NOTE: No GC allocations may occur until the stack pointers have
112             //       been set and Thread.getThis returns a valid reference to
113             //       this thread object (this latter condition is not strictly
114             //       necessary on Win32 but it should be followed for the sake
115             //       of consistency).
116
117             // TODO: Consider putting an auto exception object here (using
118             //       alloca) forOutOfMemoryError plus something to track
119             //       whether an exception is in-flight?
120
121             try
122             {
123                 obj.run();
124             }
125             catch( Object o )
126             {
127                 obj.m_unhandled = o;
128             }
129             return 0;
130         }
131
132
133         //
134         // copy of the same-named function in phobos.std.thread--it uses the
135         // Windows naming convention to be consistent with GetCurrentThreadId
136         //
137         HANDLE GetCurrentThreadHandle()
138         {
139             const uint DUPLICATE_SAME_ACCESS = 0x00000002;
140
141             HANDLE curr = GetCurrentThread(),
142                    proc = GetCurrentProcess(),
143                    hndl;
144
145             DuplicateHandle( proc, curr, proc, &hndl, 0, TRUE, DUPLICATE_SAME_ACCESS );
146             return hndl;
147         }
148     }
149 }
150 else version( Posix )
151 {
152     private
153     {
154         import stdc.posix.semaphore;
155         import stdc.posix.pthread;
156         import stdc.posix.signal;
157         import stdc.posix.time;
158         import stdc.errno;
159
160         version( GNU )
161         {
162             import gcc.builtins;
163         }
164
165
166         //
167         // entry point for POSIX threads
168         //
169         extern (C) void* thread_entryPoint( void* arg )
170         {
171             Thread  obj = cast(Thread) arg;
172             assert( obj );
173             scope( exit )
174             {
175                 // NOTE: isRunning should be set to false after the thread is
176                 //       removed or a double-removal could occur between this
177                 //       function and thread_suspendAll.
178                 Thread.remove( obj );
179                 obj.m_isRunning = false;
180             }
181
182             static extern (C) void thread_cleanupHandler( void* arg )
183             {
184                 Thread  obj = cast(Thread) arg;
185                 assert( obj );
186
187                 // NOTE: If the thread terminated abnormally, just set it as
188                 //       not running and let thread_suspendAll remove it from
189                 //       the thread list.  This is safer and is consistent
190                 //       with the Windows thread code.
191                 obj.m_isRunning = false;
192             }
193
194             // NOTE: Using void to skip the initialization here relies on
195             //       knowledge of how pthread_cleanup is implemented.  It may
196             //       not be appropriate for all platforms.  However, it does
197             //       avoid the need to link the pthread module.  If any
198             //       implementation actually requires default initialization
199             //       then pthread_cleanup should be restructured to maintain
200             //       the current lack of a link dependency.
201             pthread_cleanup cleanup = void;
202             cleanup.push( &thread_cleanupHandler, cast(void*) obj );
203
204             // NOTE: For some reason this does not always work for threads.
205             //obj.m_main.bstack = getStackBottom();
206             version( D_InlineAsm_X86 )
207             {
208                 static void* getBasePtr()
209                 {
210                     asm
211                     {
212                         naked;
213                         mov EAX, EBP;
214                         ret;
215                     }
216                 }
217
218                 obj.m_main.bstack = getBasePtr();
219             }
220             else version( StackGrowsDown )
221                 obj.m_main.bstack = &obj + 1;
222             else
223                 obj.m_main.bstack = &obj;
224             obj.m_main.tstack = obj.m_main.bstack;
225             assert( obj.m_curr == &obj.m_main );
226             Thread.add( &obj.m_main );
227             Thread.setThis( obj );
228
229             // NOTE: No GC allocations may occur until the stack pointers have
230             //       been set and Thread.getThis returns a valid reference to
231             //       this thread object (this latter condition is not strictly
232             //       necessary on Win32 but it should be followed for the sake
233             //       of consistency).
234
235             // TODO: Consider putting an auto exception object here (using
236             //       alloca) forOutOfMemoryError plus something to track
237             //       whether an exception is in-flight?
238
239             try
240             {
241                 obj.run();
242             }
243             catch( Object o )
244             {
245                 obj.m_unhandled = o;
246             }
247             return null;
248         }
249
250
251         //
252         // used to track the number of suspended threads
253         //
254         sem_t   suspendCount;
255
256
257         extern (C) void thread_suspendHandler( int sig )
258         in
259         {
260             assert( sig == SIGUSR1 );
261         }
262         body
263         {
264             version( D_InlineAsm_X86 )
265             {
266                 asm
267                 {
268                     pushad;
269                 }
270             }
271             else version( GNU )
272             {
273                 __builtin_unwind_init();
274             }
275             else
276             {
277                 static assert( false, "Architecture not supported." );
278             }
279
280             // NOTE: Since registers are being pushed and popped from the
281             //       stack, any other stack data used by this function should
282             //       be gone before the stack cleanup code is called below.
283             {
284                 Thread  obj = Thread.getThis();
285
286                 // NOTE: The thread reference returned by getThis is set within
287                 //       the thread startup code, so it is possible that this
288                 //       handler may be called before the reference is set.  In
289                 //       this case it is safe to simply suspend and not worry
290                 //       about the stack pointers as the thread will not have
291                 //       any references to GC-managed data.
292                 if( obj && !obj.m_lock )
293                 {
294                     obj.m_curr.tstack = getStackTop();
295                 }
296
297                 sigset_t    sigres = void;
298                 int         status;
299
300                 status = sigfillset( &sigres );
301                 assert( status == 0 );
302
303                 status = sigdelset( &sigres, SIGUSR2 );
304                 assert( status == 0 );
305
306                 status = sem_post( &suspendCount );
307                 assert( status == 0 );
308
309                 sigsuspend( &sigres );
310
311                 if( obj && !obj.m_lock )
312                 {
313                     obj.m_curr.tstack = obj.m_curr.bstack;
314                 }
315             }
316
317             version( D_InlineAsm_X86 )
318             {
319                 asm
320                 {
321                     popad;
322                 }
323             }
324             else version( GNU )
325             {
326                 // registers will be popped automatically
327             }
328             else
329             {
330                 static assert( false, "Architecture not supported." );
331             }
332         }
333
334
335         extern (C) void thread_resumeHandler( int sig )
336         in
337         {
338             assert( sig == SIGUSR2 );
339         }
340         body
341         {
342
343         }
344     }
345 }
346 else
347 {
348     // NOTE: This is the only place threading versions are checked.  If a new
349     //       version is added, the module code will need to be searched for
350     //       places where version-specific code may be required.  This can be
351     //       easily accomlished by searching for 'Windows' or 'Posix'.
352     static assert( false, "Unknown threading implementation." );
353 }
354
355
356 ///////////////////////////////////////////////////////////////////////////////
357 // Thread
358 ///////////////////////////////////////////////////////////////////////////////
359
360
361 /**
362  * This class encapsulates all threading functionality for the D
363  * programming language.  As thread manipulation is a required facility
364  * for garbage collection, all user threads should derive from this
365  * class, and instances of this class should never be explicitly deleted.
366  * A new thread may be created using either derivation or composition, as
367  * in the following example.
368  *
369  * Example:
370  * ----------------------------------------------------------------------------
371  *
372  * class DerivedThread : Thread
373  * {
374  *     this()
375  *     {
376  *         super( &run );
377  *     }
378  *
379  * private :
380  *     void run()
381  *     {
382  *         printf( "Derived thread running.\n" );
383  *     }
384  * }
385  *
386  * void threadFunc()
387  * {
388  *     printf( "Composed thread running.\n" );
389  * }
390  *
391  * // create instances of each type
392  * Thread derived = new DerivedThread();
393  * Thread composed = new Thread( &threadFunc );
394  *
395  * // start both threads
396  * derived.start();
397  * composed.start();
398  *
399  * ----------------------------------------------------------------------------
400  */
401 class Thread
402 {
403     ///////////////////////////////////////////////////////////////////////////
404     // Initialization
405     ///////////////////////////////////////////////////////////////////////////
406
407
408     /**
409      * Initializes a thread object which is associated with a static
410      * D function.
411      *
412      * Params:
413      *  fn = The thread function.
414      *  sz = The stack size for this thread.
415      *
416      * In:
417      *  fn must not be null.
418      */
419     this( void function() fn, size_t sz = 0 )
420     in
421     {
422         assert( fn );
423     }
424     body
425     {
426         m_fn   = fn;
427         m_sz   = sz;
428         m_call = Call.FN;
429         m_curr = &m_main;
430     }
431
432
433     /**
434      * Initializes a thread object which is associated with a dynamic
435      * D function.
436      *
437      * Params:
438      *  dg = The thread function.
439      *  sz = The stack size for this thread.
440      *
441      * In:
442      *  dg must not be null.
443      */
444     this( void delegate() dg, size_t sz = 0 )
445     in
446     {
447         assert( dg );
448     }
449     body
450     {
451         m_dg   = dg;
452         m_sz   = sz;
453         m_call = Call.DG;
454         m_curr = &m_main;
455     }
456
457
458     /**
459      * Cleans up any remaining resources used by this object.
460      */
461     ~this()
462     {
463         if( m_addr == m_addr.init )
464         {
465             return;
466         }
467
468         version( Win32 )
469         {
470             m_addr = m_addr.init;
471             CloseHandle( m_hndl );
472             m_hndl = m_hndl.init;
473         }
474         else version( Posix )
475         {
476             pthread_detach( m_addr );
477             m_addr = m_addr.init;
478         }
479     }
480
481
482     ///////////////////////////////////////////////////////////////////////////
483     // General Actions
484     ///////////////////////////////////////////////////////////////////////////
485
486
487     /**
488      * Starts the thread and invokes the function or delegate passed upon
489      * construction.
490      *
491      * In:
492      *  This routine may only be called once per thread instance.
493      *
494      * Throws:
495      *  ThreadException if the thread fails to start.
496      */
497     final void start()
498     in
499     {
500         assert( !next && !prev );
501     }
502     body
503     {
504         version( Win32 ) {} else
505         version( Posix )
506         {
507             pthread_attr_t  attr;
508
509             if( pthread_attr_init( &attr ) )
510                 throw new ThreadException( "Error initializing thread attributes" );
511             if( m_sz && pthread_attr_setstacksize( &attr, m_sz ) )
512                 throw new ThreadException( "Error initializing thread stack size" );
513             if( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) )
514                 throw new ThreadException( "Error setting thread joinable" );
515         }
516
517         // NOTE: This operation needs to be synchronized to avoid a race
518         //       condition with the GC.  Without this lock, the thread
519         //       could start and allocate memory before being added to
520         //       the global thread list, preventing it from being scanned
521         //       and causing memory to be collected that is still in use.
522         synchronized( slock )
523         {
524             version( Win32 )
525             {
526                 m_hndl = cast(HANDLE) _beginthreadex( null, m_sz, &thread_entryPoint, cast(void*) this, 0, &m_addr );
527                 if( cast(size_t) m_hndl == 0 )
528                     throw new ThreadException( "Error creating thread" );
529             }
530             else version( Posix )
531             {
532                 m_isRunning = true;
533                 scope( failure ) m_isRunning = false;
534
535                 if( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 )
536                     throw new ThreadException( "Error creating thread" );
537             }
538             multiThreadedFlag = true;
539             add( this );
540         }
541     }
542
543
544     /**
545      * Waits for this thread to complete.  If the thread terminated as the
546      * result of an unhandled exception, this exception will be rethrown.
547      *
548      * Params:
549      *  rethrow = Rethrow any unhandled exception which may have caused this
550      *            thread to terminate.
551      *
552      * Throws:
553      *  ThreadException if the operation fails.
554      *  Any exception not handled by the joined thread.
555      *
556      * Returns:
557      *  Any exception not handled by this thread if rethrow = false, null
558      *  otherwise.
559      */
560     final Object join( bool rethrow = true )
561     {
562         version( Win32 )
563         {
564             if( WaitForSingleObject( m_hndl, INFINITE ) != WAIT_OBJECT_0 )
565                 throw new ThreadException( "Unable to join thread" );
566             // NOTE: m_addr must be cleared before m_hndl is closed to avoid
567             //       a race condition with isRunning.  The operation is labeled
568             //       volatile to prevent compiler reordering.
569             volatile m_addr = m_addr.init;
570             CloseHandle( m_hndl );
571             m_hndl = m_hndl.init;
572         }
573         else version( Posix )
574         {
575             if( pthread_join( m_addr, null ) != 0 )
576                 throw new ThreadException( "Unable to join thread" );
577             // NOTE: pthread_join acts as a substitute for pthread_detach,
578             //       which is normally called by the dtor.  Setting m_addr
579             //       to zero ensures that pthread_detach will not be called
580             //       on object destruction.
581             volatile m_addr = m_addr.init;
582         }
583         if( m_unhandled )
584         {
585             if( rethrow )
586                 throw m_unhandled;
587             return m_unhandled;
588         }
589         return null;
590     }
591
592
593     ///////////////////////////////////////////////////////////////////////////
594     // General Properties
595     ///////////////////////////////////////////////////////////////////////////
596
597
598     /**
599      * Gets the user-readable label for this thread.
600      *
601      * Returns:
602      *  The name of this thread.
603      */
604     final char[] name()
605     {
606         synchronized( this )
607         {
608             return m_name;
609         }
610     }
611
612
613     /**
614      * Sets the user-readable label for this thread.
615      *
616      * Params:
617      *  val = The new name of this thread.
618      */
619     final void name( char[] val )
620     {
621         synchronized( this )
622         {
623             m_name = val.dup;
624         }
625     }
626
627
628     /**
629      * Gets the daemon status for this thread.  While the runtime will wait for
630      * all normal threads to complete before tearing down the process, daemon
631      * threads are effectively ignored and thus will not prevent the process
632      * from terminating.  In effect, daemon threads will be terminated
633      * automatically by the OS when the process exits.
634      *
635      * Returns:
636      *  true if this is a daemon thread.
637      */
638     final bool isDaemon()
639     {
640         synchronized( this )
641         {
642             return m_isDaemon;
643         }
644     }
645
646
647     /**
648      * Sets the daemon status for this thread.  While the runtime will wait for
649      * all normal threads to complete before tearing down the process, daemon
650      * threads are effectively ignored and thus will not prevent the process
651      * from terminating.  In effect, daemon threads will be terminated
652      * automatically by the OS when the process exits.
653      *
654      * Params:
655      *  val = The new daemon status for this thread.
656      */
657     final void isDaemon( bool val )
658     {
659         synchronized( this )
660         {
661             m_isDaemon = val;
662         }
663     }
664
665
666     /**
667      * Tests whether this thread is running.
668      *
669      * Returns:
670      *  true if the thread is running, false if not.
671      */
672     final bool isRunning()
673     {
674         if( m_addr == m_addr.init )
675         {
676             return false;
677         }
678
679         version( Win32 )
680         {
681             uint ecode = 0;
682             GetExitCodeThread( m_hndl, &ecode );
683             return ecode == STILL_ACTIVE;
684         }
685         else version( Posix )
686         {
687             // NOTE: It should be safe to access this value without
688             //       memory barriers because word-tearing and such
689             //       really isn't an issue for boolean values.
690             return m_isRunning;
691         }
692     }
693
694
695     ///////////////////////////////////////////////////////////////////////////
696     // Thread Priority Actions
697     ///////////////////////////////////////////////////////////////////////////
698
699
700     /**
701      * The minimum scheduling priority that may be set for a thread.  On
702      * systems where multiple scheduling policies are defined, this value
703      * represents the minimum valid priority for the scheduling policy of
704      * the process.
705      */
706     static const int PRIORITY_MIN;
707
708
709     /**
710      * The maximum scheduling priority that may be set for a thread.  On
711      * systems where multiple scheduling policies are defined, this value
712      * represents the minimum valid priority for the scheduling policy of
713      * the process.
714      */
715     static const int PRIORITY_MAX;
716
717
718     /**
719      * Gets the scheduling priority for the associated thread.
720      *
721      * Returns:
722      *  The scheduling priority of this thread.
723      */
724     final int priority()
725     {
726         version( Win32 )
727         {
728             return GetThreadPriority( m_hndl );
729         }
730         else version( Posix )
731         {
732             int         policy;
733             sched_param param;
734
735             if( pthread_getschedparam( m_addr, &policy, &param ) )
736                 throw new ThreadException( "Unable to get thread priority" );
737             return param.sched_priority;
738         }
739     }
740
741
742     /**
743      * Sets the scheduling priority for the associated thread.
744      *
745      * Params:
746      *  val = The new scheduling priority of this thread.
747      */
748     final void priority( int val )
749     {
750         version( Win32 )
751         {
752             if( !SetThreadPriority( m_hndl, val ) )
753                 throw new ThreadException( "Unable to set thread priority" );
754         }
755         else version( Posix )
756         {
757             // NOTE: pthread_setschedprio is not implemented on linux, so use
758             //       the more complicated get/set sequence below.
759             //if( pthread_setschedprio( m_addr, val ) )
760             //    throw new ThreadException( "Unable to set thread priority" );
761
762             int         policy;
763             sched_param param;
764
765             if( pthread_getschedparam( m_addr, &policy, &param ) )
766                 throw new ThreadException( "Unable to set thread priority" );
767             param.sched_priority = val;
768             if( pthread_setschedparam( m_addr, policy, &param ) )
769                 throw new ThreadException( "Unable to set thread priority" );
770         }
771     }
772
773
774     ///////////////////////////////////////////////////////////////////////////
775     // Actions on Calling Thread
776     ///////////////////////////////////////////////////////////////////////////
777
778
779     /**
780      * Suspends the calling thread for at least the supplied time, up to a
781      * maximum of (uint.max - 1) milliseconds.
782      *
783      * Params:
784      *  period = The minimum duration the calling thread should be suspended,
785      *           in seconds.  Sub-second durations are specified as fractional
786      *           values.
787      *
788      * In:
789      *  period must be less than (uint.max - 1) milliseconds.
790      *
791      * Example:
792      * ------------------------------------------------------------------------
793      *
794      * Thread.sleep( 0.05 ); // sleep for 50 milliseconds
795      * Thread.sleep( 5 );    // sleep for 5 seconds
796      *
797      * ------------------------------------------------------------------------
798      */
799     static void sleep( double period )
800     in
801     {
802         // NOTE: The fractional value added to period is to correct fp error.
803         assert( period * 1000 + 0.1 < uint.max - 1 );
804     }
805     body
806     {
807         version( Win32 )
808         {
809             Sleep( cast(uint)( period * 1000 + 0.1 ) );
810         }
811         else version( Posix )
812         {
813             timespec tin  = void;
814             timespec tout = void;
815
816             period += 0.000_000_000_1;
817
818             if( tin.tv_sec.max < period )
819             {
820                 tin.tv_sec  = tin.tv_sec.max;
821                 tin.tv_nsec = 0;
822             }
823             else
824             {
825                 tin.tv_sec  = cast(typeof(tin.tv_sec))  period;
826                 tin.tv_nsec = cast(typeof(tin.tv_nsec)) ((period % 1.0) * 1_000_000_000);
827             }
828
829             while( true )
830             {
831                 if( !nanosleep( &tin, &tout ) )
832                     return;
833                 if( getErrno() != EINTR )
834                     throw new ThreadException( "Unable to sleep for specified duration" );
835                 tin = tout;
836             }
837         }
838     }
839
840
841     /**
842      * Forces a context switch to occur away from the calling thread.
843      */
844     static void yield()
845     {
846         version( Win32 )
847         {
848             // NOTE: Sleep(1) is necessary because Sleep(0) does not give
849             //       lower priority threads any timeslice, so looping on
850             //       Sleep(0) could be resource-intensive in some cases.
851             Sleep( 1 );
852         }
853         else version( Posix )
854         {
855             sched_yield();
856         }
857     }
858
859
860     ///////////////////////////////////////////////////////////////////////////
861     // Thread Accessors
862     ///////////////////////////////////////////////////////////////////////////
863
864
865     /**
866      * Provides a reference to the calling thread.
867      *
868      * Returns:
869      *  The thread object representing the calling thread.  The result of
870      *  deleting this object is undefined.
871      */
872     static Thread getThis()
873     {
874         // NOTE: This function may not be called until thread_init has
875         //       completed.  See thread_suspendAll for more information
876         //       on why this might occur.
877         version( Win32 )
878         {
879             return cast(Thread) TlsGetValue( sm_this );
880         }
881         else version( Posix )
882         {
883             return cast(Thread) pthread_getspecific( sm_this );
884         }
885     }
886
887
888     /**
889      * Provides a list of all threads currently being tracked by the system.
890      *
891      * Returns:
892      *  An array containing references to all threads currently being
893      *  tracked by the system.  The result of deleting any contained
894      *  objects is undefined.
895      */
896     static Thread[] getAll()
897     {
898         synchronized( slock )
899         {
900             size_t   pos = 0;
901             Thread[] buf = new Thread[sm_tlen];
902
903             foreach( Thread t; Thread )
904             {
905                 buf[pos++] = t;
906             }
907             return buf;
908         }
909     }
910
911
912     /**
913      * Operates on all threads currently being tracked by the system.  The
914      * result of deleting any Thread object is undefined.
915      *
916      * Params:
917      *  dg = The supplied code as a delegate.
918      *
919      * Returns:
920      *  Zero if all elemented are visited, nonzero if not.
921      */
922     static int opApply( int delegate( inout Thread ) dg )
923     {
924         synchronized( slock )
925         {
926             int ret = 0;
927
928             for( Thread t = sm_tbeg; t; t = t.next )
929             {
930                 ret = dg( t );
931                 if( ret )
932                     break;
933             }
934             return ret;
935         }
936     }
937
938
939     ///////////////////////////////////////////////////////////////////////////
940     // Local Storage Actions
941     ///////////////////////////////////////////////////////////////////////////
942
943
944     /**
945      * Indicates the number of local storage pointers available at program
946      * startup.  It is recommended that this number be at least 64.
947      */
948     static const uint LOCAL_MAX = 64;
949
950
951     /**
952      * Reserves a local storage pointer for use and initializes this location
953      * to null for all running threads.
954      *
955      * Returns:
956      *  A key representing the array offset of this memory location.
957      */
958     static uint createLocal()
959     {
960         synchronized( slock )
961         {
962             foreach( uint key, inout bool set; sm_local )
963             {
964                 if( !set )
965                 {
966                     //foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
967                     for( Thread t = sm_tbeg; t; t = t.next )
968                     {
969                         t.m_local[key] = null;
970                     }
971                     set = true;
972                     return key;
973                 }
974             }
975             throw new ThreadException( "No more local storage slots available" );
976         }
977     }
978
979
980     /**
981      * Marks the supplied key as available and sets the associated location
982      * to null for all running threads.  It is assumed that any key passed
983      * to this function is valid.  The result of calling this function for
984      * a key which is still in use is undefined.
985      *
986      * Params:
987      *  key = The key to delete.
988      */
989     static void deleteLocal( uint key )
990     {
991         synchronized( slock )
992         {
993             sm_local[key] = false;
994             // foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
995             for( Thread t = sm_tbeg; t; t = t.next )
996             {
997                 t.m_local[key] = null;
998             }
999         }
1000     }
1001
1002
1003     /**
1004      * Loads the value stored at key within a thread-local static array.  It is
1005      * assumed that any key passed to this function is valid.
1006      *
1007      * Params:
1008      *  key = The location which holds the desired data.
1009      *
1010      * Returns:
1011      *  The data associated with the supplied key.
1012      */
1013     static void* getLocal( uint key )
1014     {
1015         return getThis().m_local[key];
1016     }
1017
1018
1019     /**
1020      * Stores the supplied value at key within a thread-local static array.  It
1021      * is assumed that any key passed to this function is valid.
1022      *
1023      * Params:
1024      *  key = The location to store the supplied data.
1025      *  val = The data to store.
1026      *
1027      * Returns:
1028      *  A copy of the data which has just been stored.
1029      */
1030     static void* setLocal( uint key, void* val )
1031     {
1032         return getThis().m_local[key] = val;
1033     }
1034
1035
1036     ///////////////////////////////////////////////////////////////////////////
1037     // Static Initalizer
1038     ///////////////////////////////////////////////////////////////////////////
1039
1040
1041     /**
1042      * This initializer is used to set thread constants.  All functional
1043      * initialization occurs within thread_init().
1044      */
1045     static this()
1046     {
1047         version( Win32 )
1048         {
1049             PRIORITY_MIN = -15;
1050             PRIORITY_MAX =  15;
1051         }
1052         else version( Posix )
1053         {
1054             int         policy;
1055             sched_param param;
1056             pthread_t   self = pthread_self();
1057
1058             int status = pthread_getschedparam( self, &policy, &param );
1059             assert( status == 0 );
1060
1061             PRIORITY_MIN = sched_get_priority_min( policy );
1062             assert( PRIORITY_MIN != -1 );
1063
1064             PRIORITY_MAX = sched_get_priority_max( policy );
1065             assert( PRIORITY_MAX != -1 );
1066         }
1067     }
1068
1069
1070 private:
1071     //
1072     // Initializes a thread object which has no associated executable function.
1073     // This is used for the main thread initialized in thread_init().
1074     //
1075     this()
1076     {
1077         m_call = Call.NO;
1078         m_curr = &m_main;
1079     }
1080
1081
1082     //
1083     // Thread entry point.  Invokes the function or delegate passed on
1084     // construction (if any).
1085     //
1086     final void run()
1087     {
1088         switch( m_call )
1089         {
1090         case Call.FN:
1091             m_fn();
1092             break;
1093         case Call.DG:
1094             m_dg();
1095             break;
1096         default:
1097             break;
1098         }
1099     }
1100
1101
1102 private:
1103     //
1104     // The type of routine passed on thread construction.
1105     //
1106     enum Call
1107     {
1108         NO,
1109         FN,
1110         DG
1111     }
1112
1113
1114     //
1115     // Standard types
1116     //
1117     version( Win32 )
1118     {
1119         alias uint TLSKey;
1120         alias uint ThreadAddr;
1121     }
1122     else version( Posix )
1123     {
1124         alias pthread_key_t TLSKey;
1125         alias pthread_t     ThreadAddr;
1126     }
1127
1128
1129     //
1130     // Local storage
1131     //
1132     static bool[LOCAL_MAX]  sm_local;
1133     static TLSKey           sm_this;
1134
1135     void*[LOCAL_MAX]        m_local;
1136
1137
1138     //
1139     // Standard thread data
1140     //
1141     version( Win32 )
1142     {
1143         HANDLE          m_hndl;
1144     }
1145     ThreadAddr          m_addr;
1146     Call                m_call;
1147     char[]              m_name;
1148     union
1149     {
1150         void function() m_fn;
1151         void delegate() m_dg;
1152     }
1153     size_t              m_sz;
1154     version( Posix )
1155     {
1156         bool            m_isRunning;
1157     }
1158     bool                m_isDaemon;
1159     Object              m_unhandled;
1160
1161
1162 private:
1163     ///////////////////////////////////////////////////////////////////////////
1164     // Storage of Active Thread
1165     ///////////////////////////////////////////////////////////////////////////
1166
1167
1168     //
1169     // Sets a thread-local reference to the current thread object.
1170     //
1171     static void setThis( Thread t )
1172     {
1173         version( Win32 )
1174         {
1175             TlsSetValue( sm_this, cast(void*) t );
1176         }
1177         else version( Posix )
1178         {
1179             pthread_setspecific( sm_this, cast(void*) t );
1180         }
1181     }
1182
1183
1184 private:
1185     ///////////////////////////////////////////////////////////////////////////
1186     // Thread Context and GC Scanning Support
1187     ///////////////////////////////////////////////////////////////////////////
1188
1189
1190     final void pushContext( Context* c )
1191     in
1192     {
1193         assert( !c.within );
1194     }
1195     body
1196     {
1197         c.within = m_curr;
1198         m_curr = c;
1199     }
1200
1201
1202     final void popContext()
1203     in
1204     {
1205         assert( m_curr && m_curr.within );
1206     }
1207     body
1208     {
1209         Context* c = m_curr;
1210         m_curr = c.within;
1211         c.within = null;
1212     }
1213
1214
1215     final Context* topContext()
1216     in
1217     {
1218         assert( m_curr );
1219     }
1220     body
1221     {
1222         return m_curr;
1223     }
1224
1225
1226     static struct Context
1227     {
1228         void*           bstack,
1229                         tstack;
1230         Context*        within;
1231         Context*        next,
1232                         prev;
1233     }
1234
1235
1236     Context             m_main;
1237     Context*            m_curr;
1238     bool                m_lock;
1239
1240     version( Win32 )
1241     {
1242         uint[8]         m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
1243     }
1244
1245
1246 private:
1247     ///////////////////////////////////////////////////////////////////////////
1248     // GC Scanning Support
1249     ///////////////////////////////////////////////////////////////////////////
1250
1251
1252     // NOTE: The GC scanning process works like so:
1253     //
1254     //          1. Suspend all threads.
1255     //          2. Scan the stacks of all suspended threads for roots.
1256     //          3. Resume all threads.
1257     //
1258     //       Step 1 and 3 require a list of all threads in the system, while
1259     //       step 2 requires a list of all thread stacks (each represented by
1260     //       a Context struct).  Traditionally, there was one stack per thread
1261     //       and the Context structs were not necessary.  However, Fibers have
1262     //       changed things so that each thread has its own 'main' stack plus
1263     //       an arbitrary number of nested stacks (normally referenced via
1264     //       m_curr).  Also, there may be 'free-floating' stacks in the system,
1265     //       which are Fibers that are not currently executing on any specific
1266     //       thread but are still being processed and still contain valid
1267     //       roots.
1268     //
1269     //       To support all of this, the Context struct has been created to
1270     //       represent a stack range, and a global list of Context structs has
1271     //       been added to enable scanning of these stack ranges.  The lifetime
1272     //       (and presence in the Context list) of a thread's 'main' stack will
1273     //       be equivalent to the thread's lifetime.  So the Ccontext will be
1274     //       added to the list on thread entry, and removed from the list on
1275     //       thread exit (which is essentially the same as the presence of a
1276     //       Thread object in its own global list).  The lifetime of a Fiber's
1277     //       context, however, will be tied to the lifetime of the Fiber object
1278     //       itself, and Fibers are expected to add/remove their Context struct
1279     //       on construction/deletion.
1280
1281
1282     //
1283     // All use of the global lists should synchronize on this lock.
1284     //
1285     static Object slock()
1286     {
1287         return Thread.classinfo;
1288     }
1289
1290
1291     static Context*     sm_cbeg;
1292     static size_t       sm_clen;
1293
1294     static Thread       sm_tbeg;
1295     static size_t       sm_tlen;
1296
1297     //
1298     // Used for ordering threads in the global thread list.
1299     //
1300     Thread              prev;
1301     Thread              next;
1302
1303
1304     ///////////////////////////////////////////////////////////////////////////
1305     // Global Context List Operations
1306     ///////////////////////////////////////////////////////////////////////////
1307
1308
1309     //
1310     // Add a context to the global context list.
1311     //
1312     static void add( Context* c )
1313     in
1314     {
1315         assert( c );
1316         assert( !c.next && !c.prev );
1317     }
1318     body
1319     {
1320         synchronized( slock )
1321         {
1322             if( sm_cbeg )
1323             {
1324                 c.next = sm_cbeg;
1325                 sm_cbeg.prev = c;
1326             }
1327             sm_cbeg = c;
1328             ++sm_clen;
1329         }
1330     }
1331
1332
1333     //
1334     // Remove a context from the global context list.
1335     //
1336     static void remove( Context* c )
1337     in
1338     {
1339         assert( c );
1340         assert( c.next || c.prev );
1341     }
1342     body
1343     {
1344         synchronized( slock )
1345         {
1346             if( c.prev )
1347                 c.prev.next = c.next;
1348             if( c.next )
1349                 c.next.prev = c.prev;
1350             if( sm_cbeg == c )
1351                 sm_cbeg = c.next;
1352             --sm_clen;
1353         }
1354         // NOTE: Don't null out c.next or c.prev because opApply currently
1355         //       follows c.next after removing a node.  This could be easily
1356         //       addressed by simply returning the next node from this
1357         //       function, however, a context should never be re-added to the
1358         //       list anyway and having next and prev be non-null is a good way
1359         //       to ensure that.
1360     }
1361
1362
1363     ///////////////////////////////////////////////////////////////////////////
1364     // Global Thread List Operations
1365     ///////////////////////////////////////////////////////////////////////////
1366
1367
1368     //
1369     // Add a thread to the global thread list.
1370     //
1371     static void add( Thread t )
1372     in
1373     {
1374         assert( t );
1375         assert( !t.next && !t.prev );
1376         assert( t.isRunning );
1377     }
1378     body
1379     {
1380         synchronized( slock )
1381         {
1382             if( sm_tbeg )
1383             {
1384                 t.next = sm_tbeg;
1385                 sm_tbeg.prev = t;
1386             }
1387             sm_tbeg = t;
1388             ++sm_tlen;
1389         }
1390     }
1391
1392
1393     //
1394     // Remove a thread from the global thread list.
1395     //
1396     static void remove( Thread t )
1397     in
1398     {
1399         assert( t );
1400         assert( t.next || t.prev );
1401         version( Win32 )
1402         {
1403             // NOTE: This doesn't work for Posix as m_isRunning must be set to
1404             //       false after the thread is removed during normal execution.
1405             assert( !t.isRunning );
1406         }
1407     }
1408     body
1409     {
1410         synchronized( slock )
1411         {
1412             // NOTE: When a thread is removed from the global thread list its
1413             //       main context is invalid and should be removed as well.
1414             //       It is possible that t.m_curr could reference more
1415             //       than just the main context if the thread exited abnormally
1416             //       (if it was terminated), but we must assume that the user
1417             //       retains a reference to them and that they may be re-used
1418             //       elsewhere.  Therefore, it is the responsibility of any
1419             //       object that creates contexts to clean them up properly
1420             //       when it is done with them.
1421             remove( &t.m_main );
1422
1423             if( t.prev )
1424                 t.prev.next = t.next;
1425             if( t.next )
1426                 t.next.prev = t.prev;
1427             if( sm_tbeg == t )
1428                 sm_tbeg = t.next;
1429             --sm_tlen;
1430         }
1431         // NOTE: Don't null out t.next or t.prev because opApply currently
1432         //       follows t.next after removing a node.  This could be easily
1433         //       addressed by simply returning the next node from this
1434         //       function, however, a thread should never be re-added to the
1435         //       list anyway and having next and prev be non-null is a good way
1436         //       to ensure that.
1437     }
1438 }
1439
1440
1441 ///////////////////////////////////////////////////////////////////////////////
1442 // GC Support Routines
1443 ///////////////////////////////////////////////////////////////////////////////
1444
1445
1446 /**
1447  * Initializes the thread module.  This function must be called by the
1448  * garbage collector on startup and before any other thread routines
1449  * are called.
1450  */
1451 extern (C) void thread_init()
1452 {
1453     // NOTE: If thread_init itself performs any allocations then the thread
1454     //       routines reserved for garbage collector use may be called while
1455     //       thread_init is being processed.  However, since no memory should
1456     //       exist to be scanned at this point, it is sufficient for these
1457     //       functions to detect the condition and return immediately.
1458
1459     version( Win32 )
1460     {
1461         Thread.sm_this = TlsAlloc();
1462         assert( Thread.sm_this != TLS_OUT_OF_INDEXES );
1463     }
1464     else version( Posix )
1465     {
1466         int         status;
1467         sigaction_t sigusr1 = void;
1468         sigaction_t sigusr2 = void;
1469
1470         // This is a quick way to zero-initialize the structs without using
1471         // memset or creating a link dependency on their static initializer.
1472         (cast(byte*) &sigusr1)[0 .. sigaction_t.sizeof] = 0;
1473         (cast(byte*) &sigusr2)[0 .. sigaction_t.sizeof] = 0;
1474
1475         // NOTE: SA_RESTART indicates that system calls should restart if they
1476         //       are interrupted by a signal, but this is not available on all
1477         //       Posix systems, even those that support multithreading.
1478         static if( is( typeof( SA_RESTART ) ) )
1479             sigusr1.sa_flags = SA_RESTART;
1480         else
1481             sigusr1.sa_flags   = 0;
1482         sigusr1.sa_handler = &thread_suspendHandler;
1483         // NOTE: We want to ignore all signals while in this handler, so fill
1484         //       sa_mask to indicate this.
1485         status = sigfillset( &sigusr1.sa_mask );
1486         assert( status == 0 );
1487
1488         // NOTE: Since SIGUSR2 should only be issued for threads within the
1489         //       suspend handler, we don't want this signal to trigger a
1490         //       restart.
1491         sigusr2.sa_flags   = 0;
1492         sigusr2.sa_handler = &thread_resumeHandler;
1493         // NOTE: We want to ignore all signals while in this handler, so fill
1494         //       sa_mask to indicate this.
1495         status = sigfillset( &sigusr2.sa_mask );
1496         assert( status == 0 );
1497
1498         status = sigaction( SIGUSR1, &sigusr1, null );
1499         assert( status == 0 );
1500
1501         status = sigaction( SIGUSR2, &sigusr2, null );
1502         assert( status == 0 );
1503
1504         status = sem_init( &suspendCount, 0, 0 );
1505         assert( status == 0 );
1506
1507         status = pthread_key_create( &Thread.sm_this, null );
1508         assert( status == 0 );
1509     }
1510
1511     thread_attachThis();
1512 }
1513
1514
1515 /**
1516  * Registers the calling thread for use with the D Runtime.  If this routine
1517  * is called for a thread which is already registered, the result is undefined.
1518  */
1519 extern (C) void thread_attachThis()
1520 {
1521     version( Win32 )
1522     {
1523         Thread          thisThread  = new Thread();
1524         Thread.Context* thisContext = &thisThread.m_main;
1525         assert( thisContext == thisThread.m_curr );
1526
1527         thisThread.m_addr  = GetCurrentThreadId();
1528         thisThread.m_hndl  = GetCurrentThreadHandle();
1529         thisContext.bstack = getStackBottom();
1530         thisContext.tstack = thisContext.bstack;
1531
1532         thisThread.m_isDaemon = true;
1533
1534         Thread.setThis( thisThread );
1535     }
1536     else version( Posix )
1537     {
1538         Thread          thisThread  = new Thread();
1539         Thread.Context* thisContext = thisThread.m_curr;
1540         assert( thisContext == &thisThread.m_main );
1541
1542         thisThread.m_addr  = pthread_self();
1543         thisContext.bstack = getStackBottom();
1544         thisContext.tstack = thisContext.bstack;
1545
1546         thisThread.m_isRunning = true;
1547         thisThread.m_isDaemon  = true;
1548
1549         Thread.setThis( thisThread );
1550     }
1551
1552     Thread.add( thisThread );
1553     Thread.add( thisContext );
1554 }
1555
1556
1557 /**
1558  * Deregisters the calling thread from use with the runtime.  If this routine
1559  * is called for a thread which is already registered, the result is undefined.
1560  */
1561 extern (C) void thread_detachThis()
1562 {
1563     Thread.remove( Thread.getThis() );
1564 }
1565
1566
1567 /**
1568  * Joins all non-daemon threads that are currently running.  This is done by
1569  * performing successive scans through the thread list until a scan consists
1570  * of only daemon threads.
1571  */
1572 extern (C) void thread_joinAll()
1573 {
1574
1575     while( true )
1576     {
1577         Thread nonDaemon = null;
1578
1579         foreach( t; Thread )
1580         {
1581             if( !t.isDaemon )
1582             {
1583                 nonDaemon = t;
1584                 break;
1585             }
1586         }
1587         if( nonDaemon is null )
1588             return;
1589         nonDaemon.join();
1590     }
1591 }
1592
1593
1594 /**
1595  * Performs intermediate shutdown of the thread module.
1596  */
1597 static ~this()
1598 {
1599     // NOTE: The functionality related to garbage collection must be minimally
1600     //       operable after this dtor completes.  Therefore, only minimal
1601     //       cleanup may occur.
1602
1603     for( Thread t = Thread.sm_tbeg; t; t = t.next )
1604     {
1605         if( !t.isRunning )
1606             Thread.remove( t );
1607     }
1608 }
1609
1610
1611 // Used for needLock below
1612 private bool multiThreadedFlag = false;
1613
1614
1615 /**
1616  * This function is used to determine whether the the process is
1617  * multi-threaded.  Optimizations may only be performed on this
1618  * value if the programmer can guarantee that no path from the
1619  * enclosed code will start a thread.
1620  *
1621  * Returns:
1622  *  True if Thread.start() has been called in this process.
1623  */
1624 extern (C) bool thread_needLock()
1625 {
1626     return multiThreadedFlag;
1627 }
1628
1629
1630 // Used for suspendAll/resumeAll below
1631 private uint suspendDepth = 0;
1632
1633
1634 /**
1635  * Suspend all threads but the calling thread for "stop the world" garbage
1636  * collection runs.  This function may be called multiple times, and must
1637  * be followed by a matching number of calls to thread_resumeAll before
1638  * processing is resumed.
1639  *
1640  * Throws:
1641  *  ThreadException if the suspend operation fails for a running thread.
1642  */
1643 extern (C) void thread_suspendAll()
1644 {
1645     /**
1646      * Suspend the specified thread and load stack and register information for
1647      * use by thread_scanAll.  If the supplied thread is the calling thread,
1648      * stack and register information will be loaded but the thread will not
1649      * be suspended.  If the suspend operation fails and the thread is not
1650      * running then it will be removed from the global thread list, otherwise
1651      * an exception will be thrown.
1652      *
1653      * Params:
1654      *  t = The thread to suspend.
1655      *
1656      * Throws:
1657      *  ThreadException if the suspend operation fails for a running thread.
1658      */
1659     void suspend( Thread t )
1660     {
1661         version( Win32 )
1662         {
1663             if( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF )
1664             {
1665                 if( !t.isRunning )
1666                 {
1667                     Thread.remove( t );
1668                     return;
1669                 }
1670                 throw new ThreadException( "Unable to suspend thread" );
1671             }
1672
1673             CONTEXT context = void;
1674             context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
1675
1676             if( !GetThreadContext( t.m_hndl, &context ) )
1677                 throw new ThreadException( "Unable to load thread context" );
1678             if( !t.m_lock )
1679                 t.m_curr.tstack = cast(void*) context.Esp;
1680             // edi,esi,ebp,esp,ebx,edx,ecx,eax
1681             t.m_reg[0] = context.Edi;
1682             t.m_reg[1] = context.Esi;
1683             t.m_reg[2] = context.Ebp;
1684             t.m_reg[3] = context.Esp;
1685             t.m_reg[4] = context.Ebx;
1686             t.m_reg[5] = context.Edx;
1687             t.m_reg[6] = context.Ecx;
1688             t.m_reg[7] = context.Eax;
1689         }
1690         else version( Posix )
1691         {
1692             if( t.m_addr != pthread_self() )
1693             {
1694                 if( pthread_kill( t.m_addr, SIGUSR1 ) != 0 )
1695                 {
1696                     if( !t.isRunning )
1697                     {
1698                         Thread.remove( t );
1699                         return;
1700                     }
1701                     throw new ThreadException( "Unable to suspend thread" );
1702                 }
1703                 // NOTE: It's really not ideal to wait for each thread to
1704                 //       signal individually -- rather, it would be better to
1705                 //       suspend them all and wait once at the end.  However,
1706                 //       semaphores don't really work this way, and the obvious
1707                 //       alternative (looping on an atomic suspend count)
1708                 //       requires either the atomic module (which only works on
1709                 //       x86) or other specialized functionality.  It would
1710                 //       also be possible to simply loop on sem_wait at the
1711                 //       end, but I'm not convinced that this would be much
1712                 //       faster than the current approach.
1713                 sem_wait( &suspendCount );
1714             }
1715             else if( !t.m_lock )
1716             {
1717                 t.m_curr.tstack = getStackTop();
1718             }
1719         }
1720     }
1721
1722
1723     // NOTE: We've got an odd chicken & egg problem here, because while the GC
1724     //       is required to call thread_init before calling any other thread
1725     //       routines, thread_init may allocate memory which could in turn
1726     //       trigger a collection.  Thus, thread_suspendAll, thread_scanAll,
1727     //       and thread_resumeAll must be callable before thread_init
1728     //       completes, with the assumption that no other GC memory has yet
1729     //       been allocated by the system, and thus there is no risk of losing
1730     //       data if the global thread list is empty.  The check of
1731     //       Thread.sm_tbeg below is done to ensure thread_init has completed,
1732     //       and therefore that calling Thread.getThis will not result in an
1733     //       error.  For the short time when Thread.sm_tbeg is null, there is
1734     //       no reason not to simply call the multithreaded code below, with
1735     //       the expectation that the foreach loop will never be entered.
1736     if( !multiThreadedFlag && Thread.sm_tbeg )
1737     {
1738         if( ++suspendDepth == 1 )
1739             suspend( Thread.getThis() );
1740         return;
1741     }
1742     synchronized( Thread.slock )
1743     {
1744         if( ++suspendDepth > 1 )
1745             return;
1746
1747         // NOTE: I'd really prefer not to check isRunning within this loop but
1748         //       not doing so could be problematic if threads are termianted
1749         //       abnormally and a new thread is created with the same thread
1750         //       address before the next GC run.  This situation might cause
1751         //       the same thread to be suspended twice, which would likely
1752         //       cause the second suspend to fail, the garbage collection to
1753         //       abort, and Bad Things to occur.
1754         for( Thread t = Thread.sm_tbeg; t; t = t.next )
1755         {
1756             if( t.isRunning )
1757                 suspend( t );
1758             else
1759                 Thread.remove( t );
1760         }
1761
1762         version( Posix )
1763         {
1764             // wait on semaphore -- see note in suspend for
1765             // why this is currently not implemented
1766         }
1767     }
1768 }
1769
1770
1771 /**
1772  * Resume all threads but the calling thread for "stop the world" garbage
1773  * collection runs.  This function must be called once for each preceding
1774  * call to thread_suspendAll before the threads are actually resumed.
1775  *
1776  * In:
1777  *  This routine must be preceded by a call to thread_suspendAll.
1778  *
1779  * Throws:
1780  *  ThreadException if the resume operation fails for a running thread.
1781  */
1782 extern (C) void thread_resumeAll()
1783 in
1784 {
1785     assert( suspendDepth > 0 );
1786 }
1787 body
1788 {
1789     /**
1790      * Resume the specified thread and unload stack and register information.
1791      * If the supplied thread is the calling thread, stack and register
1792      * information will be unloaded but the thread will not be resumed.  If
1793      * the resume operation fails and the thread is not running then it will
1794      * be removed from the global thread list, otherwise an exception will be
1795      * thrown.
1796      *
1797      * Params:
1798      *  t = The thread to resume.
1799      *
1800      * Throws:
1801      *  ThreadException if the resume fails for a running thread.
1802      */
1803     void resume( Thread t )
1804     {
1805         version( Win32 )
1806         {
1807             if( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF )
1808             {
1809                 if( !t.isRunning )
1810                 {
1811                     Thread.remove( t );
1812                     return;
1813                 }
1814                 throw new ThreadException( "Unable to resume thread" );
1815             }
1816
1817             if( !t.m_lock )
1818                 t.m_curr.tstack = t.m_curr.bstack;
1819             t.m_reg[0 .. $] = 0;
1820         }
1821         else version( Posix )
1822         {
1823             if( t.m_addr != pthread_self() )
1824             {
1825                 if( pthread_kill( t.m_addr, SIGUSR2 ) != 0 )
1826                 {
1827                     if( !t.isRunning )
1828                     {
1829                         Thread.remove( t );
1830                         return;
1831                     }
1832                     throw new ThreadException( "Unable to resume thread" );
1833                 }
1834             }
1835             else if( !t.m_lock )
1836             {
1837                 t.m_curr.tstack = t.m_curr.bstack;
1838             }
1839         }
1840     }
1841
1842
1843     // NOTE: See thread_suspendAll for the logic behind this.
1844     if( !multiThreadedFlag && Thread.sm_tbeg )
1845     {
1846         if( --suspendDepth == 0 )
1847             resume( Thread.getThis() );
1848         return;
1849     }
1850     synchronized( Thread.slock )
1851     {
1852         if( --suspendDepth > 0 )
1853             return;
1854
1855         for( Thread t = Thread.sm_tbeg; t; t = t.next )
1856         {
1857             resume( t );
1858         }
1859     }
1860 }
1861
1862
1863 private alias void delegate( void*, void* ) scanAllThreadsFn;
1864
1865
1866 /**
1867  * The main entry point for garbage collection.  The supplied delegate
1868  * will be passed ranges representing both stack and register values.
1869  *
1870  * Params:
1871  *  scan        = The scanner function.  It should scan from p1 through p2 - 1.
1872  *  curStackTop = An optional pointer to the top of the calling thread's stack.
1873  *
1874  * In:
1875  *  This routine must be preceded by a call to thread_suspendAll.
1876  */
1877 extern (C) void thread_scanAll( scanAllThreadsFn scan, void* curStackTop = null )
1878 in
1879 {
1880     assert( suspendDepth > 0 );
1881 }
1882 body
1883 {
1884     Thread  thisThread  = null;
1885     void*   oldStackTop = null;
1886
1887     if( curStackTop && Thread.sm_tbeg )
1888     {
1889         thisThread  = Thread.getThis();
1890         if( !thisThread.m_lock )
1891         {
1892             oldStackTop = thisThread.m_curr.tstack;
1893             thisThread.m_curr.tstack = curStackTop;
1894         }
1895     }
1896
1897     scope( exit )
1898     {
1899         if( curStackTop && Thread.sm_tbeg )
1900         {
1901             if( !thisThread.m_lock )
1902             {
1903                 thisThread.m_curr.tstack = oldStackTop;
1904             }
1905         }
1906     }
1907
1908     // NOTE: Synchronizing on Thread.slock is not needed because this
1909     //       function may only be called after all other threads have
1910     //       been suspended from within the same lock.
1911     for( Thread.Context* c = Thread.sm_cbeg; c; c = c.next )
1912     {
1913         version( StackGrowsDown )
1914         {
1915             // NOTE: We can't index past the bottom of the stack
1916             //       so don't do the "+1" for StackGrowsDown.
1917             if( c.tstack && c.tstack < c.bstack )
1918                 scan( c.tstack, c.bstack );
1919         }
1920         else
1921         {
1922             if( c.bstack && c.bstack < c.tstack )
1923                 scan( c.bstack, c.tstack + 1 );
1924         }
1925     }
1926     version( Win32 )
1927     {
1928         for( Thread t = Thread.sm_tbeg; t; t = t.next )
1929         {
1930             scan( &t.m_reg[0], &t.m_reg[0] + t.m_reg.length );
1931         }
1932     }
1933 }
1934
1935
1936 ///////////////////////////////////////////////////////////////////////////////
1937 // Thread Local
1938 ///////////////////////////////////////////////////////////////////////////////
1939
1940
1941 /**
1942  * This class encapsulates the operations required to initialize, access, and
1943  * destroy thread local data.
1944  */
1945 class ThreadLocal( T )
1946 {
1947     ///////////////////////////////////////////////////////////////////////////
1948     // Initialization
1949     ///////////////////////////////////////////////////////////////////////////
1950
1951
1952     /**
1953      * Initializes thread local storage for the indicated value which will be
1954      * initialized to def for all threads.
1955      *
1956      * Params:
1957      *  def = The default value to return if no value has been explicitly set.
1958      */
1959     this( T def = T.init )
1960     {
1961         m_def = def;
1962         m_key = Thread.createLocal();
1963     }
1964
1965
1966     ~this()
1967     {
1968         Thread.deleteLocal( m_key );
1969     }
1970
1971
1972     ///////////////////////////////////////////////////////////////////////////
1973     // Accessors
1974     ///////////////////////////////////////////////////////////////////////////
1975
1976
1977     /**
1978      * Gets the value last set by the calling thread, or def if no such value
1979      * has been set.
1980      *
1981      * Returns:
1982      *  The stored value or def if no value is stored.
1983      */
1984     T val()
1985     {
1986         Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
1987
1988         return wrap ? wrap.val : m_def;
1989     }
1990
1991
1992     /**
1993      * Copies newval to a location specific to the calling thread, and returns
1994      * newval.
1995      *
1996      * Params:
1997      *  newval = The value to set.
1998      *
1999      * Returns:
2000      *  The value passed to this function.
2001      */
2002     T val( T newval )
2003     {
2004         Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
2005
2006         if( wrap is null )
2007         {
2008             wrap = new Wrap;
2009             Thread.setLocal( m_key, wrap );
2010         }
2011         wrap.val = newval;
2012         return newval;
2013     }
2014
2015
2016 private:
2017     //
2018     // A wrapper for the stored data.  This is needed for determining whether
2019     // set has ever been called for this thread (and therefore whether the
2020     // default value should be returned) and also to flatten the differences
2021     // between data that is smaller and larger than (void*).sizeof.  The
2022     // obvious tradeoff here is an extra per-thread allocation for each
2023     // ThreadLocal value as compared to calling the Thread routines directly.
2024     //
2025     struct Wrap
2026     {
2027         T   val;
2028     }
2029
2030
2031     T       m_def;
2032     uint    m_key;
2033 }
2034
2035
2036 ///////////////////////////////////////////////////////////////////////////////
2037 // Thread Group
2038 ///////////////////////////////////////////////////////////////////////////////
2039
2040
2041 /**
2042  * This class is intended to simplify certain common programming techniques.
2043  */
2044 class ThreadGroup
2045 {
2046     /**
2047      * Creates and starts a new Thread object that executes fn and adds it to
2048      * the list of tracked threads.
2049      *
2050      * Params:
2051      *  fn = The thread function.
2052      *
2053      * Returns:
2054      *  A reference to the newly created thread.
2055      */
2056     final Thread create( void function() fn )
2057     {
2058         Thread t = new Thread( fn );
2059
2060         t.start();
2061         synchronized( this )
2062         {
2063             m_all[t] = t;
2064         }
2065         return t;
2066     }
2067
2068
2069     /**
2070      * Creates and starts a new Thread object that executes dg and adds it to
2071      * the list of tracked threads.
2072      *
2073      * Params:
2074      *  dg = The thread function.
2075      *
2076      * Returns:
2077      *  A reference to the newly created thread.
2078      */
2079     final Thread create( void delegate() dg )
2080     {
2081         Thread t = new Thread( dg );
2082
2083         t.start();
2084         synchronized( this )
2085         {
2086             m_all[t] = t;
2087         }
2088         return t;
2089     }
2090
2091
2092     /**
2093      * Add t to the list of tracked threads if it is not already being tracked.
2094      *
2095      * Params:
2096      *  t = The thread to add.
2097      *
2098      * In:
2099      *  t must not be null.
2100      */
2101     final void add( Thread t )
2102     in
2103     {
2104         assert( t );
2105     }
2106     body
2107     {
2108         synchronized( this )
2109         {
2110             m_all[t] = t;
2111         }
2112     }
2113
2114
2115     /**
2116      * Removes t from the list of tracked threads.  No operation will be
2117      * performed if t is not currently being tracked by this object.
2118      *
2119      * Params:
2120      *  t = The thread to remove.
2121      *
2122      * In:
2123      *  t must not be null.
2124      */
2125     final void remove( Thread t )
2126     in
2127     {
2128         assert( t );
2129     }
2130     body
2131     {
2132         synchronized( this )
2133         {
2134             m_all.remove( t );
2135         }
2136     }
2137
2138
2139     /**
2140      * Operates on all threads currently tracked by this object.
2141      */
2142     final int opApply( int delegate( inout Thread ) dg )
2143     {
2144         synchronized( this )
2145         {
2146             int ret = 0;
2147
2148             // NOTE: This loop relies on the knowledge that m_all uses the
2149             //       Thread object for both the key and the mapped value.
2150             foreach( Thread t; m_all.keys )
2151             {
2152                 ret = dg( t );
2153                 if( ret )
2154                     break;
2155             }
2156             return ret;
2157         }
2158     }
2159
2160
2161     /**
2162      * Iteratively joins all tracked threads.  This function will block add,
2163      * remove, and opApply until it completes.
2164      *
2165      * Params:
2166      *  rethrow = Rethrow any unhandled exception which may have caused the
2167      *            current thread to terminate.
2168      *
2169      * Throws:
2170      *  Any exception not handled by the joined threads.
2171      */
2172     final void joinAll( bool rethrow = true )
2173     {
2174         synchronized( this )
2175         {
2176             // NOTE: This loop relies on the knowledge that m_all uses the
2177             //       Thread object for both the key and the mapped value.
2178             foreach( Thread t; m_all.keys )
2179             {
2180                 t.join( rethrow );
2181             }
2182         }
2183     }
2184
2185
2186 private:
2187     Thread[Thread]  m_all;
2188 }
2189
2190
2191 ///////////////////////////////////////////////////////////////////////////////
2192 // Fiber Platform Detection and Memory Allocation
2193 ///////////////////////////////////////////////////////////////////////////////
2194
2195
2196 private
2197 {
2198     version( D_InlineAsm_X86 )
2199     {
2200         version( X86_64 )
2201         {
2202
2203         }
2204         else
2205         {
2206             version( Win32 )
2207                 version = AsmX86_Win32;
2208             else version( Posix )
2209                 version = AsmX86_Posix;
2210         }
2211     }
2212     else version( PPC )
2213     {
2214         version( Posix )
2215             version = AsmPPC_Posix;
2216     }
2217
2218
2219     version( Posix )
2220     {
2221         import stdc.posix.unistd;   // for sysconf
2222         import stdc.posix.sys.mman; // for mmap
2223         import stdc.posix.stdlib;   // for malloc, valloc, free
2224
2225         version( AsmX86_Win32 ) {} else
2226         version( AsmX86_Posix ) {} else
2227         version( AsmPPC_Posix ) {} else
2228         {
2229             // NOTE: The ucontext implementation requires architecture specific
2230             //       data definitions to operate so testing for it must be done
2231             //       by checking for the existence of ucontext_t rather than by
2232             //       a version identifier.  Please note that this is considered
2233             //       an obsolescent feature according to the POSIX spec, so a
2234             //       custom solution is still preferred.
2235             import stdc.posix.ucontext;
2236         }
2237     }
2238
2239     const size_t PAGESIZE;
2240 }
2241
2242
2243 static this()
2244 {
2245     static if( is( typeof( GetSystemInfo ) ) )
2246     {
2247         SYSTEM_INFO info;
2248         GetSystemInfo( &info );
2249
2250         PAGESIZE = info.dwPageSize;
2251         assert( PAGESIZE < int.max );
2252     }
2253     else static if( is( typeof( sysconf ) ) &&
2254                     is( typeof( _SC_PAGESIZE ) ) )
2255     {
2256         PAGESIZE = cast(size_t) sysconf( _SC_PAGESIZE );
2257         assert( PAGESIZE < int.max );
2258     }
2259     else
2260     {
2261         version( PPC )
2262             PAGESIZE = 8192;
2263         else
2264             PAGESIZE = 4096;
2265     }
2266 }
2267
2268
2269 ///////////////////////////////////////////////////////////////////////////////
2270 // Fiber Entry Point and Context Switch
2271 ///////////////////////////////////////////////////////////////////////////////
2272
2273
2274 private
2275 {
2276     extern (C) void fiber_entryPoint()
2277     {
2278         Fiber   obj = Fiber.getThis();
2279         assert( obj );
2280
2281         assert( Thread.getThis().m_curr is obj.m_ctxt );
2282         volatile Thread.getThis().m_lock = false;
2283         obj.m_ctxt.tstack = obj.m_ctxt.bstack;
2284         obj.m_state = Fiber.State.EXEC;
2285
2286         try
2287         {
2288             obj.run();
2289         }
2290         catch( Object o )
2291         {
2292             obj.m_unhandled = o;
2293         }
2294
2295         static if( is( ucontext_t ) )
2296           obj.m_ucur = &obj.m_utxt;
2297
2298         obj.m_state = Fiber.State.TERM;
2299         obj.switchOut();
2300     }
2301
2302
2303   // NOTE: If AsmPPC_Posix is defined then the context switch routine will
2304   //       be defined externally until GDC supports inline PPC ASM.
2305   version( AsmPPC_Posix )
2306     extern (C) void fiber_switchContext( void** oldp, void* newp );
2307   else
2308     extern (C) void fiber_switchContext( void** oldp, void* newp )
2309     {
2310         // NOTE: The data pushed and popped in this routine must match the
2311         //       default stack created by Fiber.initStack or the initial
2312         //       switch into a new context will fail.
2313
2314         version( AsmX86_Win32 )
2315         {
2316             asm
2317             {
2318                 naked;
2319
2320                 // save current stack state
2321                 push EBP;
2322                 mov  EBP, ESP;
2323                 push EAX;
2324                 push dword ptr FS:[0];
2325                 push dword ptr FS:[4];
2326                 push dword ptr FS:[8];
2327                 push EBX;
2328                 push ESI;
2329                 push EDI;
2330
2331                 // store oldp again with more accurate address
2332                 mov EAX, dword ptr 8[EBP];
2333                 mov [EAX], ESP;
2334                 // load newp to begin context switch
2335                 mov ESP, dword ptr 12[EBP];
2336
2337                 // load saved state from new stack
2338                 pop EDI;
2339                 pop ESI;
2340                 pop EBX;
2341                 pop dword ptr FS:[8];
2342                 pop dword ptr FS:[4];
2343                 pop dword ptr FS:[0];
2344                 pop EAX;
2345                 pop EBP;
2346
2347                 // 'return' to complete switch
2348                 ret;
2349             }
2350         }
2351         else version( AsmX86_Posix )
2352         {
2353             asm
2354             {
2355                 naked;
2356
2357                 // save current stack state
2358                 push EBP;
2359                 mov  EBP, ESP;
2360                 push EAX;
2361                 push EBX;
2362                 push ESI;
2363                 push EDI;
2364
2365                 // store oldp again with more accurate address
2366                 mov EAX, dword ptr 8[EBP];
2367                 mov [EAX], ESP;
2368                 // load newp to begin context switch
2369                 mov ESP, dword ptr 12[EBP];
2370
2371                 // load saved state from new stack
2372                 pop EDI;
2373                 pop ESI;
2374                 pop EBX;
2375                 pop EAX;
2376                 pop EBP;
2377
2378                 // 'return' to complete switch
2379                 ret;
2380             }
2381         }
2382         else static if( is( ucontext_t ) )
2383         {
2384             Fiber   cfib = Fiber.getThis();
2385             void*   ucur = cfib.m_ucur;
2386
2387             *oldp = &ucur;
2388             swapcontext( **(cast(ucontext_t***) oldp),
2389                           *(cast(ucontext_t**)  newp) );
2390         }
2391     }
2392 }
2393
2394
2395 ///////////////////////////////////////////////////////////////////////////////
2396 // Fiber
2397 ///////////////////////////////////////////////////////////////////////////////
2398
2399
2400 /**
2401  * This class provides a cooperative concurrency mechanism integrated with the
2402  * threading and garbage collection functionality.  Calling a fiber may be
2403  * considered a blocking operation that returns when the fiber yields (via
2404  * Fiber.yield()).  Execution occurs within the context of the calling thread
2405  * so synchronization is not necessary to guarantee memory visibility so long
2406  * as the same thread calls the fiber each time.  Please note that there is no
2407  * requirement that a fiber be bound to one specific thread.  Rather, fibers
2408  * may be freely passed between threads so long as they are not currently
2409  * executing.  Like threads, a new fiber thread may be created using either
2410  * derivation or composition, as in the following example.
2411  *
2412  * Example:
2413  * ----------------------------------------------------------------------
2414  *
2415  * class DerivedFiber : Fiber
2416  * {
2417  *     this()
2418  *     {
2419  *         super( &run );
2420  *     }
2421  *
2422  * private :
2423  *     void run()
2424  *     {
2425  *         printf( "Derived fiber running.\n" );
2426  *     }
2427  * }
2428  *
2429  * void fiberFunc()
2430  * {
2431  *     printf( "Composed fiber running.\n" );
2432  *     Fiber.yield();
2433  *     printf( "Composed fiber running.\n" );
2434  * }
2435  *
2436  * // create instances of each type
2437  * Fiber derived = new DerivedFiber();
2438  * Fiber composed = new Fiber( &fiberFunc );
2439  *
2440  * // call both fibers once
2441  * derived.call();
2442  * composed.call();
2443  * printf( "Execution returned to calling context.\n" );
2444  * composed.call();
2445  *
2446  * // since each fiber has run to completion, each should have state TERM
2447  * assert( derived.state == Fiber.State.TERM );
2448  * assert( composed.state == Fiber.State.TERM );
2449  *
2450  * ----------------------------------------------------------------------
2451  *
2452  * Authors: Based on a design by Mikola Lysenko.
2453  */
2454 class Fiber
2455 {
2456     ///////////////////////////////////////////////////////////////////////////
2457     // Initialization
2458     ///////////////////////////////////////////////////////////////////////////
2459
2460
2461     /**
2462      * Initializes a fiber object which is associated with a static
2463      * D function.
2464      *
2465      * Params:
2466      *  fn = The thread function.
2467      *  sz = The stack size for this fiber.
2468      *
2469      * In:
2470      *  fn must not be null.
2471      */
2472     this( void function() fn, size_t sz = PAGESIZE )
2473     in
2474     {
2475         assert( fn );
2476     }
2477     body
2478     {
2479         m_fn    = fn;
2480         m_call  = Call.FN;
2481         m_state = State.HOLD;
2482         allocStack( sz );
2483         initStack();
2484     }
2485
2486
2487     /**
2488      * Initializes a fiber object which is associated with a dynamic
2489      * D function.
2490      *
2491      * Params:
2492      *  dg = The thread function.
2493      *  sz = The stack size for this fiber.
2494      *
2495      * In:
2496      *  dg must not be null.
2497      */
2498     this( void delegate() dg, size_t sz = PAGESIZE )
2499     in
2500     {
2501         assert( dg );
2502     }
2503     body
2504     {
2505         m_dg    = dg;
2506         m_call  = Call.DG;
2507         m_state = State.HOLD;
2508         allocStack( sz );
2509         initStack();
2510     }
2511
2512
2513     /**
2514      * Cleans up any remaining resources used by this object.
2515      */
2516     ~this()
2517     {
2518         // NOTE: A live reference to this object will exist on its associated
2519         //       stack from the first time its call() method has been called
2520         //       until its execution completes with State.TERM.  Thus, the only
2521         //       times this dtor should be called are either if the fiber has
2522         //       terminated (and therefore has no active stack) or if the user
2523         //       explicitly deletes this object.  The latter case is an error
2524         //       but is not easily tested for, since State.HOLD may imply that
2525         //       the fiber was just created but has never been run.  There is
2526         //       not a compelling case to create a State.INIT just to offer a
2527         //       means of ensuring the user isn't violating this object's
2528         //       contract, so for now this requirement will be enforced by
2529         //       documentation only.
2530         freeStack();
2531     }
2532
2533
2534     ///////////////////////////////////////////////////////////////////////////
2535     // General Actions
2536     ///////////////////////////////////////////////////////////////////////////
2537
2538
2539     /**
2540      * Transfers execution to this fiber object.  The calling context will be
2541      * suspended until the fiber calls Fiber.yield() or until it terminates
2542      * via an unhandled exception.
2543      *
2544      * Params:
2545      *  rethrow = Rethrow any unhandled exception which may have caused this
2546      *            fiber to terminate.
2547      *
2548      * In:
2549      *  This fiber must be in state HOLD.
2550      *
2551      * Throws:
2552      *  Any exception not handled by the joined thread.
2553      *
2554      * Returns:
2555      *  Any exception not handled by this fiber if rethrow = false, null
2556      *  otherwise.
2557      */
2558     final Object call( bool rethrow = true )
2559     in
2560     {
2561         assert( m_state == State.HOLD );
2562     }
2563     body
2564     {
2565         Fiber   cur = getThis();
2566
2567         static if( is( ucontext_t ) )
2568           m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt;
2569
2570         setThis( this );
2571         this.switchIn();
2572         setThis( cur );
2573
2574         static if( is( ucontext_t ) )
2575           m_ucur = null;
2576
2577         // NOTE: If the fiber has terminated then the stack pointers must be
2578         //       reset.  This ensures that the stack for this fiber is not
2579         //       scanned if the fiber has terminated.  This is necessary to
2580         //       prevent any references lingering on the stack from delaying
2581         //       the collection of otherwise dead objects.  The most notable
2582         //       being the current object, which is referenced at the top of
2583         //       fiber_entryPoint.
2584         if( m_state == State.TERM )
2585         {
2586             m_ctxt.tstack = m_ctxt.bstack;
2587         }
2588         if( m_unhandled )
2589         {
2590             Object obj  = m_unhandled;
2591             m_unhandled = null;
2592             if( rethrow )
2593                 throw obj;
2594             return obj;
2595         }
2596         return null;
2597     }
2598
2599
2600     /**
2601      * Resets this fiber so that it may be re-used.  This routine may only be
2602      * called for fibers that have terminated, as doing otherwise could result
2603      * in scope-dependent functionality that is not executed.  Stack-based
2604      * classes, for example, may not be cleaned up properly if a fiber is reset
2605      * before it has terminated.
2606      *
2607      * In:
2608      *  This fiber must be in state TERM.
2609      */
2610     final void reset()
2611     in
2612     {
2613         assert( m_state == State.TERM );
2614         assert( m_ctxt.tstack == m_ctxt.bstack );
2615     }
2616     body
2617     {
2618         m_state = State.HOLD;
2619         initStack();
2620         m_unhandled = null;
2621     }
2622
2623
2624     ///////////////////////////////////////////////////////////////////////////
2625     // General Properties
2626     ///////////////////////////////////////////////////////////////////////////
2627
2628
2629     /**
2630      * A fiber may occupy one of three states: HOLD, EXEC, and TERM.  The HOLD
2631      * state applies to any fiber that is suspended and ready to be called.
2632      * The EXEC state will be set for any fiber that is currently executing.
2633      * And the TERM state is set when a fiber terminates.  Once a fiber
2634      * terminates, it must be reset before it may be called again.
2635      */
2636     enum State
2637     {
2638         HOLD,   ///
2639         EXEC,   ///
2640         TERM    ///
2641     }
2642
2643
2644     /**
2645      * Gets the current state of this fiber.
2646      *
2647      * Returns:
2648      *  The state of this fiber as an enumerated value.
2649      */
2650     final State state()
2651     {
2652         return m_state;
2653     }
2654
2655
2656     ///////////////////////////////////////////////////////////////////////////
2657     // Actions on Calling Fiber
2658     ///////////////////////////////////////////////////////////////////////////
2659
2660
2661     /**
2662      * Forces a context switch to occur away from the calling fiber.
2663      */
2664     static void yield()
2665     {
2666         Fiber   cur = getThis();
2667         assert( cur, "Fiber.yield() called with no active fiber" );
2668         assert( cur.m_state == State.EXEC );
2669
2670         static if( is( ucontext_t ) )
2671           cur.m_ucur = &cur.m_utxt;
2672
2673         cur.m_state = State.HOLD;
2674         cur.switchOut();
2675         cur.m_state = State.EXEC;
2676     }
2677
2678
2679     /**
2680      * Forces a context switch to occur away from the calling fiber and then
2681      * throws obj in the calling fiber.
2682      *
2683      * Params:
2684      *  obj = The object to throw.
2685      *
2686      * In:
2687      *  obj must not be null.
2688      */
2689     static void yieldAndThrow( Object obj )
2690     in
2691     {
2692         assert( obj );
2693     }
2694     body
2695     {
2696         Fiber   cur = getThis();
2697         assert( cur, "Fiber.yield() called with no active fiber" );
2698         assert( cur.m_state == State.EXEC );
2699
2700         static if( is( ucontext_t ) )
2701           cur.m_ucur = &cur.m_utxt;
2702
2703         cur.m_unhandled = obj;
2704         cur.m_state = State.HOLD;
2705         cur.switchOut();
2706         cur.m_state = State.EXEC;
2707     }
2708
2709
2710     ///////////////////////////////////////////////////////////////////////////
2711     // Fiber Accessors
2712     ///////////////////////////////////////////////////////////////////////////
2713
2714
2715     /**
2716      * Provides a reference to the calling fiber or null if no fiber is
2717      * currently active.
2718      *
2719      * Returns:
2720      *  The fiber object representing the calling fiber or null if no fiber
2721      *  is currently active.  The result of deleting this object is undefined.
2722      */
2723     static Fiber getThis()
2724     {
2725         version( Win32 )
2726         {
2727             return cast(Fiber) TlsGetValue( sm_this );
2728         }
2729         else version( Posix )
2730         {
2731             return cast(Fiber) pthread_getspecific( sm_this );
2732         }
2733     }
2734
2735
2736     ///////////////////////////////////////////////////////////////////////////
2737     // Static Initialization
2738     ///////////////////////////////////////////////////////////////////////////
2739
2740
2741     static this()
2742     {
2743         version( Win32 )
2744         {
2745             sm_this = TlsAlloc();
2746             assert( sm_this != TLS_OUT_OF_INDEXES );
2747         }
2748         else version( Posix )
2749         {
2750             int status;
2751
2752             status = pthread_key_create( &sm_this, null );
2753             assert( status == 0 );
2754
2755           static if( is( ucontext_t ) )
2756           {
2757             status = getcontext( &sm_utxt );
2758             assert( status == 0 );
2759           }
2760         }
2761     }
2762
2763
2764 private:
2765     //
2766     // Initializes a fiber object which has no associated executable function.
2767     //
2768     this()
2769     {
2770         m_call = Call.NO;
2771     }
2772
2773
2774     //
2775     // Fiber entry point.  Invokes the function or delegate passed on
2776     // construction (if any).
2777     //
2778     final void run()
2779     {
2780         switch( m_call )
2781         {
2782         case Call.FN:
2783             m_fn();
2784             break;
2785         case Call.DG:
2786             m_dg();
2787             break;
2788         default:
2789             break;
2790         }
2791     }
2792
2793
2794 private:
2795     //
2796     // The type of routine passed on fiber construction.
2797     //
2798     enum Call
2799     {
2800         NO,
2801         FN,
2802         DG
2803     }
2804
2805
2806     //
2807     // Standard fiber data
2808     //
2809     Call                m_call;
2810     union
2811     {
2812         void function() m_fn;
2813         void delegate() m_dg;
2814     }
2815     bool                m_isRunning;
2816     Object              m_unhandled;
2817     State               m_state;
2818
2819
2820 private:
2821     ///////////////////////////////////////////////////////////////////////////
2822     // Stack Management
2823     ///////////////////////////////////////////////////////////////////////////
2824
2825
2826     //
2827     // Allocate a new stack for this fiber.
2828     //
2829     final void allocStack( size_t sz )
2830     in
2831     {
2832         assert( !m_pmem && !m_ctxt );
2833     }
2834     body
2835     {
2836         // adjust alloc size to a multiple of PAGESIZE
2837         sz += PAGESIZE - 1;
2838         sz -= sz % PAGESIZE;
2839
2840         // NOTE: This instance of Thread.Context is dynamic so Fiber objects
2841         //       can be collected by the GC so long as no user level references
2842         //       to the object exist.  If m_ctxt were not dynamic then its
2843         //       presence in the global context list would be enough to keep
2844         //       this object alive indefinitely.  An alternative to allocating
2845         //       room for this struct explicitly would be to mash it into the
2846         //       base of the stack being allocated below.  However, doing so
2847         //       requires too much special logic to be worthwhile.
2848         m_ctxt = new Thread.Context;
2849
2850         static if( is( typeof( VirtualAlloc ) ) )
2851         {
2852             // reserve memory for stack
2853             m_pmem = VirtualAlloc( null,
2854                                    sz + PAGESIZE,
2855                                    MEM_RESERVE,
2856                                    PAGE_NOACCESS );
2857             if( !m_pmem )
2858             {
2859                 throw new FiberException( "Unable to reserve memory for stack" );
2860             }
2861
2862             version( StackGrowsDown )
2863             {
2864                 void* stack = m_pmem + PAGESIZE;
2865                 void* guard = m_pmem;
2866                 void* pbase = stack + sz;
2867             }
2868             else
2869             {
2870                 void* stack = m_pmem;
2871                 void* guard = m_pmem + sz;
2872                 void* pbase = stack;
2873             }
2874
2875             // allocate reserved stack segment
2876             stack = VirtualAlloc( stack,
2877                                   sz,
2878                                   MEM_COMMIT,
2879                                   PAGE_READWRITE );
2880             if( !stack )
2881             {
2882                 throw new FiberException( "Unable to allocate memory for stack" );
2883             }
2884
2885             // allocate reserved guard page
2886             guard = VirtualAlloc( guard,
2887                                   PAGESIZE,
2888                                   MEM_COMMIT,
2889                                   PAGE_READWRITE | PAGE_GUARD );
2890             if( !guard )
2891             {
2892                 throw new FiberException( "Unable to create guard page for stack" );
2893             }
2894
2895             m_ctxt.bstack = pbase;
2896             m_ctxt.tstack = pbase;
2897             m_size = sz;
2898         }
2899         else
2900         {   static if( is( typeof( mmap ) ) )
2901             {
2902                 m_pmem = mmap( null,
2903                                sz,
2904                                PROT_READ | PROT_WRITE,
2905                                MAP_PRIVATE | MAP_ANON,
2906                                -1,
2907                                0 );
2908                 if( m_pmem == MAP_FAILED )
2909                     m_pmem = null;
2910             }
2911             else static if( is( typeof( valloc ) ) )
2912             {
2913                 m_pmem = valloc( sz );
2914             }
2915             else static if( is( typeof( malloc ) ) )
2916             {
2917                 m_pmem = malloc( sz );
2918             }
2919             else
2920             {
2921                 m_pmem = null;
2922             }
2923
2924             if( !m_pmem )
2925             {
2926                 throw new FiberException( "Unable to allocate memory for stack" );
2927             }
2928
2929             version( StackGrowsDown )
2930             {
2931                 m_ctxt.bstack = m_pmem + sz;
2932                 m_ctxt.tstack = m_pmem + sz;
2933             }
2934             else
2935             {
2936                 m_ctxt.bstack = m_pmem;
2937                 m_ctxt.tstack = m_pmem;
2938             }
2939             m_size = sz;
2940         }
2941
2942         Thread.add( m_ctxt );
2943     }
2944
2945
2946     //
2947     // Free this fiber's stack.
2948     //
2949     final void freeStack()
2950     in
2951     {
2952         assert( m_pmem && m_ctxt );
2953     }
2954     body
2955     {
2956         // NOTE: Since this routine is only ever expected to be called from
2957         //       the dtor, pointers to freed data are not set to null.
2958
2959         // NOTE: m_ctxt is guaranteed to be alive because it is held in the
2960         //       global context list.
2961         Thread.remove( m_ctxt );
2962
2963         static if( is( typeof( VirtualAlloc ) ) )
2964         {
2965             VirtualFree( m_pmem, 0, MEM_RELEASE );
2966         }
2967         else static if( is( typeof( mmap ) ) )
2968         {
2969             munmap( m_pmem, m_size );
2970         }
2971         else static if( is( typeof( valloc ) ) )
2972         {
2973             free( m_pmem );
2974         }
2975         else static if( is( typeof( malloc ) ) )
2976         {
2977             free( m_pmem );
2978         }
2979         delete m_ctxt;
2980     }
2981
2982
2983     //
2984     // Initialize the allocated stack.
2985     //
2986     final void initStack()
2987     in
2988     {
2989         assert( m_ctxt.tstack && m_ctxt.tstack == m_ctxt.bstack );
2990         assert( cast(size_t) m_ctxt.bstack % (void*).sizeof == 0 );
2991     }
2992     body
2993     {
2994         void* pstack = m_ctxt.tstack;
2995         scope( exit )  m_ctxt.tstack = pstack;
2996
2997         void push( size_t val )
2998         {
2999             version( StackGrowsDown )
3000             {
3001                 pstack -= size_t.sizeof;
3002                 *(cast(size_t*) pstack) = val;
3003             }
3004             else
3005             {
3006                 pstack += size_t.sizeof;
3007                 *(cast(size_t*) pstack) = val;
3008             }
3009         }
3010
3011         // NOTE: On OS X the stack must be 16-byte aligned according to the
3012         // IA-32 call spec.
3013         version( darwin )
3014         {
3015              pstack = cast(void*)(cast(uint)(pstack) - (cast(uint)(pstack) & 0x0F));
3016         }
3017
3018         version( AsmX86_Win32 )
3019         {
3020             push( cast(size_t) &fiber_entryPoint );                 // EIP
3021             push( 0xFFFFFFFF );                                     // EBP
3022             push( 0x00000000 );                                     // EAX
3023             push( 0xFFFFFFFF );                                     // FS:[0]
3024             version( StackGrowsDown )
3025             {
3026                 push( cast(size_t) m_ctxt.bstack );                 // FS:[4]
3027                 push( cast(size_t) m_ctxt.bstack - m_size );        // FS:[8]
3028             }
3029             else
3030             {
3031                 push( cast(size_t) m_ctxt.bstack );                 // FS:[4]
3032                 push( cast(size_t) m_ctxt.bstack + m_size );        // FS:[8]
3033             }
3034             push( 0x00000000 );                                     // EBX
3035             push( 0x00000000 );                                     // ESI
3036             push( 0x00000000 );                                     // EDI
3037         }
3038         else version( AsmX86_Posix )
3039         {
3040             push( cast(size_t) &fiber_entryPoint );                 // EIP
3041             push( 0x00000000 );                                     // EBP
3042             push( 0x00000000 );                                     // EAX
3043             push( 0x00000000 );                                     // EBX
3044             push( 0x00000000 );                                     // ESI
3045             push( 0x00000000 );                                     // EDI
3046         }
3047         else version( AsmPPC_Posix )
3048         {
3049             version( StackGrowsDown )
3050             {
3051                 pstack -= int.sizeof * 5;
3052             }
3053             else
3054             {
3055                 pstack += int.sizeof * 5;
3056             }
3057
3058             push( cast(size_t) &fiber_entryPoint );     // link register
3059             push( 0x00000000 );                         // control register
3060             push( 0x00000000 );                         // old stack pointer
3061
3062             // GPR values
3063             version( StackGrowsDown )
3064             {
3065                 pstack -= int.sizeof * 20;
3066             }
3067             else
3068             {
3069                 pstack += int.sizeof * 20;
3070             }
3071
3072             assert( cast(uint) pstack & 0x0f == 0 );
3073         }
3074         else static if( is( ucontext_t ) )
3075         {
3076             getcontext( &m_utxt );
3077             m_utxt.uc_stack.ss_sp   = m_ctxt.bstack;
3078             m_utxt.uc_stack.ss_size = m_size;
3079             makecontext( &m_utxt, &fiber_entryPoint, 0 );
3080             // NOTE: If ucontext is being used then the top of the stack will
3081             //       be a pointer to the ucontext_t struct for that fiber.
3082             push( cast(size_t) &m_utxt );
3083         }
3084     }
3085
3086
3087     Thread.Context* m_ctxt;
3088     size_t          m_size;
3089     void*           m_pmem;
3090
3091     static if( is( ucontext_t ) )
3092     {
3093         // NOTE: The static ucontext instance is used to represent the context
3094         //       of the main application thread.
3095         static ucontext_t   sm_utxt = void;
3096         ucontext_t          m_utxt  = void;
3097         ucontext_t*         m_ucur  = null;
3098     }
3099
3100
3101 private:
3102     ///////////////////////////////////////////////////////////////////////////
3103     // Storage of Active Fiber
3104     ///////////////////////////////////////////////////////////////////////////
3105
3106
3107     //
3108     // Sets a thread-local reference to the current fiber object.
3109     //
3110     static void setThis( Fiber f )
3111     {
3112         version( Win32 )
3113         {
3114             TlsSetValue( sm_this, cast(void*) f );
3115         }
3116         else version( Posix )
3117         {
3118             pthread_setspecific( sm_this, cast(void*) f );
3119         }
3120     }
3121
3122
3123     static Thread.TLSKey    sm_this;
3124
3125
3126 private:
3127     ///////////////////////////////////////////////////////////////////////////
3128     // Context Switching
3129     ///////////////////////////////////////////////////////////////////////////
3130
3131
3132     //
3133     // Switches into the stack held by this fiber.
3134     //
3135     final void switchIn()
3136     {
3137         Thread  tobj = Thread.getThis();
3138         void**  oldp = &tobj.m_curr.tstack;
3139         void*   newp = m_ctxt.tstack;
3140
3141         // NOTE: The order of operations here is very important.  The current
3142         //       stack top must be stored before m_lock is set, and pushContext
3143         //       must not be called until after m_lock is set.  This process
3144         //       is intended to prevent a race condition with the suspend
3145         //       mechanism used for garbage collection.  If it is not followed,
3146         //       a badly timed collection could cause the GC to scan from the
3147         //       bottom of one stack to the top of another, or to miss scanning
3148         //       a stack that still contains valid data.  The old stack pointer
3149         //       oldp will be set again before the context switch to guarantee
3150         //       that it points to exactly the correct stack location so the
3151         //       successive pop operations will succeed.
3152         *oldp = getStackTop();
3153         volatile tobj.m_lock = true;
3154         tobj.pushContext( m_ctxt );
3155
3156         fiber_switchContext( oldp, newp );
3157
3158         // NOTE: As above, these operations must be performed in a strict order
3159         //       to prevent Bad Things from happening.
3160         tobj.popContext();
3161         volatile tobj.m_lock = false;
3162         tobj.m_curr.tstack = tobj.m_curr.bstack;
3163     }
3164
3165
3166     //
3167     // Switches out of the current stack and into the enclosing stack.
3168     //
3169     final void switchOut()
3170     {
3171         Thread  tobj = Thread.getThis();
3172         void**  oldp = &m_ctxt.tstack;
3173         void*   newp = tobj.m_curr.within.tstack;
3174
3175         // NOTE: The order of operations here is very important.  The current
3176         //       stack top must be stored before m_lock is set, and pushContext
3177         //       must not be called until after m_lock is set.  This process
3178         //       is intended to prevent a race condition with the suspend
3179         //       mechanism used for garbage collection.  If it is not followed,
3180         //       a badly timed collection could cause the GC to scan from the
3181         //       bottom of one stack to the top of another, or to miss scanning
3182         //       a stack that still contains valid data.  The old stack pointer
3183         //       oldp will be set again before the context switch to guarantee
3184         //       that it points to exactly the correct stack location so the
3185         //       successive pop operations will succeed.
3186         *oldp = getStackTop();
3187         volatile tobj.m_lock = true;
3188
3189         fiber_switchContext( oldp, newp );
3190
3191         // NOTE: As above, these operations must be performed in a strict order
3192         //       to prevent Bad Things from happening.
3193         volatile tobj.m_lock = false;
3194         tobj.m_curr.tstack = tobj.m_curr.bstack;
3195     }
3196 }