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