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