]> git.llucax.com Git - software/druntime.git/blob - src/common/core/thread.d
First attempt at support for dynamic library loading and unloading. Currently, only...
[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 Win32 but it should be followed for the sake
115             //       of consistency).
116
117             // TODO: Consider putting an auto exception object here (using
118             //       alloca) forOutOfMemoryError plus something to track
119             //       whether an exception is in-flight?
120
121             try
122             {
123                 obj.run();
124             }
125             catch( Object o )
126             {
127                 obj.m_unhandled = o;
128             }
129             return 0;
130         }
131
132
133         //
134         // copy of the same-named function in phobos.std.thread--it uses the
135         // Windows naming convention to be consistent with GetCurrentThreadId
136         //
137         HANDLE GetCurrentThreadHandle()
138         {
139             const uint DUPLICATE_SAME_ACCESS = 0x00000002;
140
141             HANDLE curr = GetCurrentThread(),
142                    proc = GetCurrentProcess(),
143                    hndl;
144
145             DuplicateHandle( proc, curr, proc, &hndl, 0, TRUE, DUPLICATE_SAME_ACCESS );
146             return hndl;
147         }
148     }
149 }
150 else version( Posix )
151 {
152     private
153     {
154         import 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 Win32 but it should be followed for the sake
247             //       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( Win32 )
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( Win32 ) {} 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( Win32 )
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( Win32 )
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( Win32 )
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( Win32 )
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( Win32 )
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 );        // 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( Win32 )
821         {
822             enum : uint
823             {
824                 TICKS_PER_MILLI  = 10_000,
825                 MAX_SLEEP_MILLIS = uint.max - 1
826             }
827
828             period = period < TICKS_PER_MILLI ?
829                         1 :
830                         period / TICKS_PER_MILLI;
831             while( period > MAX_SLEEP_MILLIS )
832             {
833                 Sleep( MAX_SLEEP_MILLIS );
834                 period -= MAX_SLEEP_MILLIS;
835             }
836             Sleep( cast(uint) period );
837         }
838         else version( Posix )
839         {
840             timespec tin  = void;
841             timespec tout = void;
842
843             enum : uint
844             {
845                 NANOS_PER_TICK   = 100,
846                 TICKS_PER_SECOND = 10_000_000,
847             }
848             enum : typeof(period)
849             {
850                 MAX_SLEEP_TICKS = cast(typeof(period)) tin.tv_sec.max * TICKS_PER_SECOND
851             }
852
853             do
854             {
855                 if( period > MAX_SLEEP_TICKS )
856                 {
857                     tin.tv_sec = tin.tv_sec.max;
858                     tin.tv_nsec = 0;
859                 }
860                 else
861                 {
862                     tin.tv_sec = cast(typeof(tin.tv_sec)) (period / TICKS_PER_SECOND);
863                     tin.tv_nsec = cast(typeof(tin.tv_nsec)) (period % TICKS_PER_SECOND) * NANOS_PER_TICK;
864                 }
865                 while( true )
866                 {
867                     if( !nanosleep( &tin, &tout ) )
868                         return;
869                     if( getErrno() != EINTR )
870                         throw new ThreadException( "Unable to sleep for the specified duration" );
871                     tin = tout;
872                 }
873                 period -= (cast(typeof(period)) tin.tv_sec) * TICKS_PER_SECOND;
874                 period -= (cast(typeof(period)) tin.tv_nsec) / NANOS_PER_TICK;
875             } while( period > 0 );
876         }
877     }
878
879
880     /**
881      * Forces a context switch to occur away from the calling thread.
882      */
883     static void yield()
884     {
885         version( Win32 )
886         {
887             // NOTE: Sleep(1) is necessary because Sleep(0) does not give
888             //       lower priority threads any timeslice, so looping on
889             //       Sleep(0) could be resource-intensive in some cases.
890             Sleep( 1 );
891         }
892         else version( Posix )
893         {
894             sched_yield();
895         }
896     }
897
898
899     ///////////////////////////////////////////////////////////////////////////
900     // Thread Accessors
901     ///////////////////////////////////////////////////////////////////////////
902
903
904     /**
905      * Provides a reference to the calling thread.
906      *
907      * Returns:
908      *  The thread object representing the calling thread.  The result of
909      *  deleting this object is undefined.
910      */
911     static Thread getThis()
912     {
913         // NOTE: This function may not be called until thread_init has
914         //       completed.  See thread_suspendAll for more information
915         //       on why this might occur.
916         version( Win32 )
917         {
918             return cast(Thread) TlsGetValue( sm_this );
919         }
920         else version( Posix )
921         {
922             return cast(Thread) pthread_getspecific( sm_this );
923         }
924     }
925
926
927     /**
928      * Provides a list of all threads currently being tracked by the system.
929      *
930      * Returns:
931      *  An array containing references to all threads currently being
932      *  tracked by the system.  The result of deleting any contained
933      *  objects is undefined.
934      */
935     static Thread[] getAll()
936     {
937         synchronized( slock )
938         {
939             size_t   pos = 0;
940             Thread[] buf = new Thread[sm_tlen];
941
942             foreach( Thread t; Thread )
943             {
944                 buf[pos++] = t;
945             }
946             return buf;
947         }
948     }
949
950
951     /**
952      * Operates on all threads currently being tracked by the system.  The
953      * result of deleting any Thread object is undefined.
954      *
955      * Params:
956      *  dg = The supplied code as a delegate.
957      *
958      * Returns:
959      *  Zero if all elemented are visited, nonzero if not.
960      */
961     static int opApply( int delegate( inout Thread ) dg )
962     {
963         synchronized( slock )
964         {
965             int ret = 0;
966
967             for( Thread t = sm_tbeg; t; t = t.next )
968             {
969                 ret = dg( t );
970                 if( ret )
971                     break;
972             }
973             return ret;
974         }
975     }
976
977
978     ///////////////////////////////////////////////////////////////////////////
979     // Local Storage Actions
980     ///////////////////////////////////////////////////////////////////////////
981
982
983     /**
984      * Indicates the number of local storage pointers available at program
985      * startup.  It is recommended that this number be at least 64.
986      */
987     static const uint LOCAL_MAX = 64;
988
989
990     /**
991      * Reserves a local storage pointer for use and initializes this location
992      * to null for all running threads.
993      *
994      * Returns:
995      *  A key representing the array offset of this memory location.
996      */
997     static uint createLocal()
998     {
999         synchronized( slock )
1000         {
1001             foreach( uint key, inout bool set; sm_local )
1002             {
1003                 if( !set )
1004                 {
1005                     //foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
1006                     for( Thread t = sm_tbeg; t; t = t.next )
1007                     {
1008                         t.m_local[key] = null;
1009                     }
1010                     set = true;
1011                     return key;
1012                 }
1013             }
1014             throw new ThreadException( "No more local storage slots available" );
1015         }
1016     }
1017
1018
1019     /**
1020      * Marks the supplied key as available and sets the associated location
1021      * to null for all running threads.  It is assumed that any key passed
1022      * to this function is valid.  The result of calling this function for
1023      * a key which is still in use is undefined.
1024      *
1025      * Params:
1026      *  key = The key to delete.
1027      */
1028     static void deleteLocal( uint key )
1029     {
1030         synchronized( slock )
1031         {
1032             sm_local[key] = false;
1033             // foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
1034             for( Thread t = sm_tbeg; t; t = t.next )
1035             {
1036                 t.m_local[key] = null;
1037             }
1038         }
1039     }
1040
1041
1042     /**
1043      * Loads the value stored at key within a thread-local static array.  It is
1044      * assumed that any key passed to this function is valid.
1045      *
1046      * Params:
1047      *  key = The location which holds the desired data.
1048      *
1049      * Returns:
1050      *  The data associated with the supplied key.
1051      */
1052     static void* getLocal( uint key )
1053     {
1054         return getThis().m_local[key];
1055     }
1056
1057
1058     /**
1059      * Stores the supplied value at key within a thread-local static array.  It
1060      * is assumed that any key passed to this function is valid.
1061      *
1062      * Params:
1063      *  key = The location to store the supplied data.
1064      *  val = The data to store.
1065      *
1066      * Returns:
1067      *  A copy of the data which has just been stored.
1068      */
1069     static void* setLocal( uint key, void* val )
1070     {
1071         return getThis().m_local[key] = val;
1072     }
1073
1074
1075     ///////////////////////////////////////////////////////////////////////////
1076     // Static Initalizer
1077     ///////////////////////////////////////////////////////////////////////////
1078
1079
1080     /**
1081      * This initializer is used to set thread constants.  All functional
1082      * initialization occurs within thread_init().
1083      */
1084     static this()
1085     {
1086         version( Win32 )
1087         {
1088             PRIORITY_MIN = -15;
1089             PRIORITY_MAX =  15;
1090         }
1091         else version( Posix )
1092         {
1093             int         policy;
1094             sched_param param;
1095             pthread_t   self = pthread_self();
1096
1097             int status = pthread_getschedparam( self, &policy, &param );
1098             assert( status == 0 );
1099
1100             PRIORITY_MIN = sched_get_priority_min( policy );
1101             assert( PRIORITY_MIN != -1 );
1102
1103             PRIORITY_MAX = sched_get_priority_max( policy );
1104             assert( PRIORITY_MAX != -1 );
1105         }
1106     }
1107
1108
1109 private:
1110     //
1111     // Initializes a thread object which has no associated executable function.
1112     // This is used for the main thread initialized in thread_init().
1113     //
1114     this()
1115     {
1116         m_call = Call.NO;
1117         m_curr = &m_main;
1118     }
1119
1120
1121     //
1122     // Thread entry point.  Invokes the function or delegate passed on
1123     // construction (if any).
1124     //
1125     final void run()
1126     {
1127         switch( m_call )
1128         {
1129         case Call.FN:
1130             m_fn();
1131             break;
1132         case Call.DG:
1133             m_dg();
1134             break;
1135         default:
1136             break;
1137         }
1138     }
1139
1140
1141 private:
1142     //
1143     // The type of routine passed on thread construction.
1144     //
1145     enum Call
1146     {
1147         NO,
1148         FN,
1149         DG
1150     }
1151
1152
1153     //
1154     // Standard types
1155     //
1156     version( Win32 )
1157     {
1158         alias uint TLSKey;
1159         alias uint ThreadAddr;
1160     }
1161     else version( Posix )
1162     {
1163         alias pthread_key_t TLSKey;
1164         alias pthread_t     ThreadAddr;
1165     }
1166
1167
1168     //
1169     // Local storage
1170     //
1171     static bool[LOCAL_MAX]  sm_local;
1172     static TLSKey           sm_this;
1173
1174     void*[LOCAL_MAX]        m_local;
1175
1176
1177     //
1178     // Standard thread data
1179     //
1180     version( Win32 )
1181     {
1182         HANDLE          m_hndl;
1183     }
1184     ThreadAddr          m_addr;
1185     Call                m_call;
1186     char[]              m_name;
1187     union
1188     {
1189         void function() m_fn;
1190         void delegate() m_dg;
1191     }
1192     size_t              m_sz;
1193     version( Posix )
1194     {
1195         bool            m_isRunning;
1196     }
1197     bool                m_isDaemon;
1198     Object              m_unhandled;
1199
1200
1201 private:
1202     ///////////////////////////////////////////////////////////////////////////
1203     // Storage of Active Thread
1204     ///////////////////////////////////////////////////////////////////////////
1205
1206
1207     //
1208     // Sets a thread-local reference to the current thread object.
1209     //
1210     static void setThis( Thread t )
1211     {
1212         version( Win32 )
1213         {
1214             TlsSetValue( sm_this, cast(void*) t );
1215         }
1216         else version( Posix )
1217         {
1218             pthread_setspecific( sm_this, cast(void*) t );
1219         }
1220     }
1221
1222
1223 private:
1224     ///////////////////////////////////////////////////////////////////////////
1225     // Thread Context and GC Scanning Support
1226     ///////////////////////////////////////////////////////////////////////////
1227
1228
1229     final void pushContext( Context* c )
1230     in
1231     {
1232         assert( !c.within );
1233     }
1234     body
1235     {
1236         c.within = m_curr;
1237         m_curr = c;
1238     }
1239
1240
1241     final void popContext()
1242     in
1243     {
1244         assert( m_curr && m_curr.within );
1245     }
1246     body
1247     {
1248         Context* c = m_curr;
1249         m_curr = c.within;
1250         c.within = null;
1251     }
1252
1253
1254     final Context* topContext()
1255     in
1256     {
1257         assert( m_curr );
1258     }
1259     body
1260     {
1261         return m_curr;
1262     }
1263
1264
1265     static struct Context
1266     {
1267         void*           bstack,
1268                         tstack;
1269         Context*        within;
1270         Context*        next,
1271                         prev;
1272     }
1273
1274
1275     Context             m_main;
1276     Context*            m_curr;
1277     bool                m_lock;
1278
1279     version( Win32 )
1280     {
1281         uint[8]         m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
1282     }
1283
1284
1285 private:
1286     ///////////////////////////////////////////////////////////////////////////
1287     // GC Scanning Support
1288     ///////////////////////////////////////////////////////////////////////////
1289
1290
1291     // NOTE: The GC scanning process works like so:
1292     //
1293     //          1. Suspend all threads.
1294     //          2. Scan the stacks of all suspended threads for roots.
1295     //          3. Resume all threads.
1296     //
1297     //       Step 1 and 3 require a list of all threads in the system, while
1298     //       step 2 requires a list of all thread stacks (each represented by
1299     //       a Context struct).  Traditionally, there was one stack per thread
1300     //       and the Context structs were not necessary.  However, Fibers have
1301     //       changed things so that each thread has its own 'main' stack plus
1302     //       an arbitrary number of nested stacks (normally referenced via
1303     //       m_curr).  Also, there may be 'free-floating' stacks in the system,
1304     //       which are Fibers that are not currently executing on any specific
1305     //       thread but are still being processed and still contain valid
1306     //       roots.
1307     //
1308     //       To support all of this, the Context struct has been created to
1309     //       represent a stack range, and a global list of Context structs has
1310     //       been added to enable scanning of these stack ranges.  The lifetime
1311     //       (and presence in the Context list) of a thread's 'main' stack will
1312     //       be equivalent to the thread's lifetime.  So the Ccontext will be
1313     //       added to the list on thread entry, and removed from the list on
1314     //       thread exit (which is essentially the same as the presence of a
1315     //       Thread object in its own global list).  The lifetime of a Fiber's
1316     //       context, however, will be tied to the lifetime of the Fiber object
1317     //       itself, and Fibers are expected to add/remove their Context struct
1318     //       on construction/deletion.
1319
1320
1321     //
1322     // All use of the global lists should synchronize on this lock.
1323     //
1324     static Object slock()
1325     {
1326         return Thread.classinfo;
1327     }
1328
1329
1330     static Context*     sm_cbeg;
1331     static size_t       sm_clen;
1332
1333     static Thread       sm_tbeg;
1334     static size_t       sm_tlen;
1335
1336     //
1337     // Used for ordering threads in the global thread list.
1338     //
1339     Thread              prev;
1340     Thread              next;
1341
1342
1343     ///////////////////////////////////////////////////////////////////////////
1344     // Global Context List Operations
1345     ///////////////////////////////////////////////////////////////////////////
1346
1347
1348     //
1349     // Add a context to the global context list.
1350     //
1351     static void add( Context* c )
1352     in
1353     {
1354         assert( c );
1355         assert( !c.next && !c.prev );
1356     }
1357     body
1358     {
1359         synchronized( slock )
1360         {
1361             if( sm_cbeg )
1362             {
1363                 c.next = sm_cbeg;
1364                 sm_cbeg.prev = c;
1365             }
1366             sm_cbeg = c;
1367             ++sm_clen;
1368         }
1369     }
1370
1371
1372     //
1373     // Remove a context from the global context list.
1374     //
1375     static void remove( Context* c )
1376     in
1377     {
1378         assert( c );
1379         assert( c.next || c.prev );
1380     }
1381     body
1382     {
1383         synchronized( slock )
1384         {
1385             if( c.prev )
1386                 c.prev.next = c.next;
1387             if( c.next )
1388                 c.next.prev = c.prev;
1389             if( sm_cbeg == c )
1390                 sm_cbeg = c.next;
1391             --sm_clen;
1392         }
1393         // NOTE: Don't null out c.next or c.prev because opApply currently
1394         //       follows c.next after removing a node.  This could be easily
1395         //       addressed by simply returning the next node from this
1396         //       function, however, a context should never be re-added to the
1397         //       list anyway and having next and prev be non-null is a good way
1398         //       to ensure that.
1399     }
1400
1401
1402     ///////////////////////////////////////////////////////////////////////////
1403     // Global Thread List Operations
1404     ///////////////////////////////////////////////////////////////////////////
1405
1406
1407     //
1408     // Add a thread to the global thread list.
1409     //
1410     static void add( Thread t )
1411     in
1412     {
1413         assert( t );
1414         assert( !t.next && !t.prev );
1415         assert( t.isRunning );
1416     }
1417     body
1418     {
1419         synchronized( slock )
1420         {
1421             if( sm_tbeg )
1422             {
1423                 t.next = sm_tbeg;
1424                 sm_tbeg.prev = t;
1425             }
1426             sm_tbeg = t;
1427             ++sm_tlen;
1428         }
1429     }
1430
1431
1432     //
1433     // Remove a thread from the global thread list.
1434     //
1435     static void remove( Thread t )
1436     in
1437     {
1438         assert( t );
1439         assert( t.next || t.prev );
1440         version( Win32 )
1441         {
1442             // NOTE: This doesn't work for Posix as m_isRunning must be set to
1443             //       false after the thread is removed during normal execution.
1444             assert( !t.isRunning );
1445         }
1446     }
1447     body
1448     {
1449         synchronized( slock )
1450         {
1451             // NOTE: When a thread is removed from the global thread list its
1452             //       main context is invalid and should be removed as well.
1453             //       It is possible that t.m_curr could reference more
1454             //       than just the main context if the thread exited abnormally
1455             //       (if it was terminated), but we must assume that the user
1456             //       retains a reference to them and that they may be re-used
1457             //       elsewhere.  Therefore, it is the responsibility of any
1458             //       object that creates contexts to clean them up properly
1459             //       when it is done with them.
1460             remove( &t.m_main );
1461
1462             if( t.prev )
1463                 t.prev.next = t.next;
1464             if( t.next )
1465                 t.next.prev = t.prev;
1466             if( sm_tbeg == t )
1467                 sm_tbeg = t.next;
1468             --sm_tlen;
1469         }
1470         // NOTE: Don't null out t.next or t.prev because opApply currently
1471         //       follows t.next after removing a node.  This could be easily
1472         //       addressed by simply returning the next node from this
1473         //       function, however, a thread should never be re-added to the
1474         //       list anyway and having next and prev be non-null is a good way
1475         //       to ensure that.
1476     }
1477 }
1478
1479
1480 ///////////////////////////////////////////////////////////////////////////////
1481 // GC Support Routines
1482 ///////////////////////////////////////////////////////////////////////////////
1483
1484
1485 /**
1486  * Initializes the thread module.  This function must be called by the
1487  * garbage collector on startup and before any other thread routines
1488  * are called.
1489  */
1490 extern (C) void thread_init()
1491 {
1492     // NOTE: If thread_init itself performs any allocations then the thread
1493     //       routines reserved for garbage collector use may be called while
1494     //       thread_init is being processed.  However, since no memory should
1495     //       exist to be scanned at this point, it is sufficient for these
1496     //       functions to detect the condition and return immediately.
1497
1498     version( Win32 )
1499     {
1500         Thread.sm_this = TlsAlloc();
1501         assert( Thread.sm_this != TLS_OUT_OF_INDEXES );
1502     }
1503     else version( Posix )
1504     {
1505         int         status;
1506         sigaction_t sigusr1 = void;
1507         sigaction_t sigusr2 = void;
1508
1509         // This is a quick way to zero-initialize the structs without using
1510         // memset or creating a link dependency on their static initializer.
1511         (cast(byte*) &sigusr1)[0 .. sigaction_t.sizeof] = 0;
1512         (cast(byte*) &sigusr2)[0 .. sigaction_t.sizeof] = 0;
1513
1514         // NOTE: SA_RESTART indicates that system calls should restart if they
1515         //       are interrupted by a signal, but this is not available on all
1516         //       Posix systems, even those that support multithreading.
1517         static if( is( typeof( SA_RESTART ) ) )
1518             sigusr1.sa_flags = SA_RESTART;
1519         else
1520             sigusr1.sa_flags   = 0;
1521         sigusr1.sa_handler = &thread_suspendHandler;
1522         // NOTE: We want to ignore all signals while in this handler, so fill
1523         //       sa_mask to indicate this.
1524         status = sigfillset( &sigusr1.sa_mask );
1525         assert( status == 0 );
1526
1527         // NOTE: Since SIGUSR2 should only be issued for threads within the
1528         //       suspend handler, we don't want this signal to trigger a
1529         //       restart.
1530         sigusr2.sa_flags   = 0;
1531         sigusr2.sa_handler = &thread_resumeHandler;
1532         // NOTE: We want to ignore all signals while in this handler, so fill
1533         //       sa_mask to indicate this.
1534         status = sigfillset( &sigusr2.sa_mask );
1535         assert( status == 0 );
1536
1537         status = sigaction( SIGUSR1, &sigusr1, null );
1538         assert( status == 0 );
1539
1540         status = sigaction( SIGUSR2, &sigusr2, null );
1541         assert( status == 0 );
1542
1543         status = sem_init( &suspendCount, 0, 0 );
1544         assert( status == 0 );
1545
1546         status = pthread_key_create( &Thread.sm_this, null );
1547         assert( status == 0 );
1548     }
1549
1550     thread_attachThis();
1551 }
1552
1553
1554 /**
1555  * Registers the calling thread for use with the D Runtime.  If this routine
1556  * is called for a thread which is already registered, the result is undefined.
1557  */
1558 extern (C) void thread_attachThis()
1559 {
1560     version( Win32 )
1561     {
1562         Thread          thisThread  = new Thread();
1563         Thread.Context* thisContext = &thisThread.m_main;
1564         assert( thisContext == thisThread.m_curr );
1565
1566         thisThread.m_addr  = GetCurrentThreadId();
1567         thisThread.m_hndl  = GetCurrentThreadHandle();
1568         thisContext.bstack = getStackBottom();
1569         thisContext.tstack = thisContext.bstack;
1570
1571         thisThread.m_isDaemon = true;
1572
1573         Thread.setThis( thisThread );
1574     }
1575     else version( Posix )
1576     {
1577         Thread          thisThread  = new Thread();
1578         Thread.Context* thisContext = thisThread.m_curr;
1579         assert( thisContext == &thisThread.m_main );
1580
1581         thisThread.m_addr  = pthread_self();
1582         thisContext.bstack = getStackBottom();
1583         thisContext.tstack = thisContext.bstack;
1584
1585         thisThread.m_isRunning = true;
1586         thisThread.m_isDaemon  = true;
1587
1588         Thread.setThis( thisThread );
1589     }
1590
1591     Thread.add( thisThread );
1592     Thread.add( thisContext );
1593 }
1594
1595
1596 /**
1597  * Deregisters the calling thread from use with the runtime.  If this routine
1598  * is called for a thread which is already registered, the result is undefined.
1599  */
1600 extern (C) void thread_detachThis()
1601 {
1602     Thread.remove( Thread.getThis() );
1603 }
1604
1605
1606 /**
1607  * Joins all non-daemon threads that are currently running.  This is done by
1608  * performing successive scans through the thread list until a scan consists
1609  * of only daemon threads.
1610  */
1611 extern (C) void thread_joinAll()
1612 {
1613
1614     while( true )
1615     {
1616         Thread nonDaemon = null;
1617
1618         foreach( t; Thread )
1619         {
1620             if( !t.isDaemon )
1621             {
1622                 nonDaemon = t;
1623                 break;
1624             }
1625         }
1626         if( nonDaemon is null )
1627             return;
1628         nonDaemon.join();
1629     }
1630 }
1631
1632
1633 /**
1634  * Performs intermediate shutdown of the thread module.
1635  */
1636 static ~this()
1637 {
1638     // NOTE: The functionality related to garbage collection must be minimally
1639     //       operable after this dtor completes.  Therefore, only minimal
1640     //       cleanup may occur.
1641
1642     for( Thread t = Thread.sm_tbeg; t; t = t.next )
1643     {
1644         if( !t.isRunning )
1645             Thread.remove( t );
1646     }
1647 }
1648
1649
1650 // Used for needLock below
1651 private bool multiThreadedFlag = false;
1652
1653
1654 /**
1655  * This function is used to determine whether the the process is
1656  * multi-threaded.  Optimizations may only be performed on this
1657  * value if the programmer can guarantee that no path from the
1658  * enclosed code will start a thread.
1659  *
1660  * Returns:
1661  *  True if Thread.start() has been called in this process.
1662  */
1663 extern (C) bool thread_needLock()
1664 {
1665     return multiThreadedFlag;
1666 }
1667
1668
1669 // Used for suspendAll/resumeAll below
1670 private uint suspendDepth = 0;
1671
1672
1673 /**
1674  * Suspend all threads but the calling thread for "stop the world" garbage
1675  * collection runs.  This function may be called multiple times, and must
1676  * be followed by a matching number of calls to thread_resumeAll before
1677  * processing is resumed.
1678  *
1679  * Throws:
1680  *  ThreadException if the suspend operation fails for a running thread.
1681  */
1682 extern (C) void thread_suspendAll()
1683 {
1684     /**
1685      * Suspend the specified thread and load stack and register information for
1686      * use by thread_scanAll.  If the supplied thread is the calling thread,
1687      * stack and register information will be loaded but the thread will not
1688      * be suspended.  If the suspend operation fails and the thread is not
1689      * running then it will be removed from the global thread list, otherwise
1690      * an exception will be thrown.
1691      *
1692      * Params:
1693      *  t = The thread to suspend.
1694      *
1695      * Throws:
1696      *  ThreadException if the suspend operation fails for a running thread.
1697      */
1698     void suspend( Thread t )
1699     {
1700         version( Win32 )
1701         {
1702             if( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF )
1703             {
1704                 if( !t.isRunning )
1705                 {
1706                     Thread.remove( t );
1707                     return;
1708                 }
1709                 throw new ThreadException( "Unable to suspend thread" );
1710             }
1711
1712             CONTEXT context = void;
1713             context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
1714
1715             if( !GetThreadContext( t.m_hndl, &context ) )
1716                 throw new ThreadException( "Unable to load thread context" );
1717             if( !t.m_lock )
1718                 t.m_curr.tstack = cast(void*) context.Esp;
1719             // edi,esi,ebp,esp,ebx,edx,ecx,eax
1720             t.m_reg[0] = context.Edi;
1721             t.m_reg[1] = context.Esi;
1722             t.m_reg[2] = context.Ebp;
1723             t.m_reg[3] = context.Esp;
1724             t.m_reg[4] = context.Ebx;
1725             t.m_reg[5] = context.Edx;
1726             t.m_reg[6] = context.Ecx;
1727             t.m_reg[7] = context.Eax;
1728         }
1729         else version( Posix )
1730         {
1731             if( t.m_addr != pthread_self() )
1732             {
1733                 if( pthread_kill( t.m_addr, SIGUSR1 ) != 0 )
1734                 {
1735                     if( !t.isRunning )
1736                     {
1737                         Thread.remove( t );
1738                         return;
1739                     }
1740                     throw new ThreadException( "Unable to suspend thread" );
1741                 }
1742                 // NOTE: It's really not ideal to wait for each thread to
1743                 //       signal individually -- rather, it would be better to
1744                 //       suspend them all and wait once at the end.  However,
1745                 //       semaphores don't really work this way, and the obvious
1746                 //       alternative (looping on an atomic suspend count)
1747                 //       requires either the atomic module (which only works on
1748                 //       x86) or other specialized functionality.  It would
1749                 //       also be possible to simply loop on sem_wait at the
1750                 //       end, but I'm not convinced that this would be much
1751                 //       faster than the current approach.
1752                 sem_wait( &suspendCount );
1753             }
1754             else if( !t.m_lock )
1755             {
1756                 t.m_curr.tstack = getStackTop();
1757             }
1758         }
1759     }
1760
1761
1762     // NOTE: We've got an odd chicken & egg problem here, because while the GC
1763     //       is required to call thread_init before calling any other thread
1764     //       routines, thread_init may allocate memory which could in turn
1765     //       trigger a collection.  Thus, thread_suspendAll, thread_scanAll,
1766     //       and thread_resumeAll must be callable before thread_init
1767     //       completes, with the assumption that no other GC memory has yet
1768     //       been allocated by the system, and thus there is no risk of losing
1769     //       data if the global thread list is empty.  The check of
1770     //       Thread.sm_tbeg below is done to ensure thread_init has completed,
1771     //       and therefore that calling Thread.getThis will not result in an
1772     //       error.  For the short time when Thread.sm_tbeg is null, there is
1773     //       no reason not to simply call the multithreaded code below, with
1774     //       the expectation that the foreach loop will never be entered.
1775     if( !multiThreadedFlag && Thread.sm_tbeg )
1776     {
1777         if( ++suspendDepth == 1 )
1778             suspend( Thread.getThis() );
1779         return;
1780     }
1781     synchronized( Thread.slock )
1782     {
1783         if( ++suspendDepth > 1 )
1784             return;
1785
1786         // NOTE: I'd really prefer not to check isRunning within this loop but
1787         //       not doing so could be problematic if threads are termianted
1788         //       abnormally and a new thread is created with the same thread
1789         //       address before the next GC run.  This situation might cause
1790         //       the same thread to be suspended twice, which would likely
1791         //       cause the second suspend to fail, the garbage collection to
1792         //       abort, and Bad Things to occur.
1793         for( Thread t = Thread.sm_tbeg; t; t = t.next )
1794         {
1795             if( t.isRunning )
1796                 suspend( t );
1797             else
1798                 Thread.remove( t );
1799         }
1800
1801         version( Posix )
1802         {
1803             // wait on semaphore -- see note in suspend for
1804             // why this is currently not implemented
1805         }
1806     }
1807 }
1808
1809
1810 /**
1811  * Resume all threads but the calling thread for "stop the world" garbage
1812  * collection runs.  This function must be called once for each preceding
1813  * call to thread_suspendAll before the threads are actually resumed.
1814  *
1815  * In:
1816  *  This routine must be preceded by a call to thread_suspendAll.
1817  *
1818  * Throws:
1819  *  ThreadException if the resume operation fails for a running thread.
1820  */
1821 extern (C) void thread_resumeAll()
1822 in
1823 {
1824     assert( suspendDepth > 0 );
1825 }
1826 body
1827 {
1828     /**
1829      * Resume the specified thread and unload stack and register information.
1830      * If the supplied thread is the calling thread, stack and register
1831      * information will be unloaded but the thread will not be resumed.  If
1832      * the resume operation fails and the thread is not running then it will
1833      * be removed from the global thread list, otherwise an exception will be
1834      * thrown.
1835      *
1836      * Params:
1837      *  t = The thread to resume.
1838      *
1839      * Throws:
1840      *  ThreadException if the resume fails for a running thread.
1841      */
1842     void resume( Thread t )
1843     {
1844         version( Win32 )
1845         {
1846             if( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF )
1847             {
1848                 if( !t.isRunning )
1849                 {
1850                     Thread.remove( t );
1851                     return;
1852                 }
1853                 throw new ThreadException( "Unable to resume thread" );
1854             }
1855
1856             if( !t.m_lock )
1857                 t.m_curr.tstack = t.m_curr.bstack;
1858             t.m_reg[0 .. $] = 0;
1859         }
1860         else version( Posix )
1861         {
1862             if( t.m_addr != pthread_self() )
1863             {
1864                 if( pthread_kill( t.m_addr, SIGUSR2 ) != 0 )
1865                 {
1866                     if( !t.isRunning )
1867                     {
1868                         Thread.remove( t );
1869                         return;
1870                     }
1871                     throw new ThreadException( "Unable to resume thread" );
1872                 }
1873             }
1874             else if( !t.m_lock )
1875             {
1876                 t.m_curr.tstack = t.m_curr.bstack;
1877             }
1878         }
1879     }
1880
1881
1882     // NOTE: See thread_suspendAll for the logic behind this.
1883     if( !multiThreadedFlag && Thread.sm_tbeg )
1884     {
1885         if( --suspendDepth == 0 )
1886             resume( Thread.getThis() );
1887         return;
1888     }
1889     synchronized( Thread.slock )
1890     {
1891         if( --suspendDepth > 0 )
1892             return;
1893
1894         for( Thread t = Thread.sm_tbeg; t; t = t.next )
1895         {
1896             resume( t );
1897         }
1898     }
1899 }
1900
1901
1902 private alias void delegate( void*, void* ) scanAllThreadsFn;
1903
1904
1905 /**
1906  * The main entry point for garbage collection.  The supplied delegate
1907  * will be passed ranges representing both stack and register values.
1908  *
1909  * Params:
1910  *  scan        = The scanner function.  It should scan from p1 through p2 - 1.
1911  *  curStackTop = An optional pointer to the top of the calling thread's stack.
1912  *
1913  * In:
1914  *  This routine must be preceded by a call to thread_suspendAll.
1915  */
1916 extern (C) void thread_scanAll( scanAllThreadsFn scan, void* curStackTop = null )
1917 in
1918 {
1919     assert( suspendDepth > 0 );
1920 }
1921 body
1922 {
1923     Thread  thisThread  = null;
1924     void*   oldStackTop = null;
1925
1926     if( curStackTop && Thread.sm_tbeg )
1927     {
1928         thisThread  = Thread.getThis();
1929         if( !thisThread.m_lock )
1930         {
1931             oldStackTop = thisThread.m_curr.tstack;
1932             thisThread.m_curr.tstack = curStackTop;
1933         }
1934     }
1935
1936     scope( exit )
1937     {
1938         if( curStackTop && Thread.sm_tbeg )
1939         {
1940             if( !thisThread.m_lock )
1941             {
1942                 thisThread.m_curr.tstack = oldStackTop;
1943             }
1944         }
1945     }
1946
1947     // NOTE: Synchronizing on Thread.slock is not needed because this
1948     //       function may only be called after all other threads have
1949     //       been suspended from within the same lock.
1950     for( Thread.Context* c = Thread.sm_cbeg; c; c = c.next )
1951     {
1952         version( StackGrowsDown )
1953         {
1954             // NOTE: We can't index past the bottom of the stack
1955             //       so don't do the "+1" for StackGrowsDown.
1956             if( c.tstack && c.tstack < c.bstack )
1957                 scan( c.tstack, c.bstack );
1958         }
1959         else
1960         {
1961             if( c.bstack && c.bstack < c.tstack )
1962                 scan( c.bstack, c.tstack + 1 );
1963         }
1964     }
1965     version( Win32 )
1966     {
1967         for( Thread t = Thread.sm_tbeg; t; t = t.next )
1968         {
1969             scan( &t.m_reg[0], &t.m_reg[0] + t.m_reg.length );
1970         }
1971     }
1972 }
1973
1974
1975 ///////////////////////////////////////////////////////////////////////////////
1976 // Thread Local
1977 ///////////////////////////////////////////////////////////////////////////////
1978
1979
1980 /**
1981  * This class encapsulates the operations required to initialize, access, and
1982  * destroy thread local data.
1983  */
1984 class ThreadLocal( T )
1985 {
1986     ///////////////////////////////////////////////////////////////////////////
1987     // Initialization
1988     ///////////////////////////////////////////////////////////////////////////
1989
1990
1991     /**
1992      * Initializes thread local storage for the indicated value which will be
1993      * initialized to def for all threads.
1994      *
1995      * Params:
1996      *  def = The default value to return if no value has been explicitly set.
1997      */
1998     this( T def = T.init )
1999     {
2000         m_def = def;
2001         m_key = Thread.createLocal();
2002     }
2003
2004
2005     ~this()
2006     {
2007         Thread.deleteLocal( m_key );
2008     }
2009
2010
2011     ///////////////////////////////////////////////////////////////////////////
2012     // Accessors
2013     ///////////////////////////////////////////////////////////////////////////
2014
2015
2016     /**
2017      * Gets the value last set by the calling thread, or def if no such value
2018      * has been set.
2019      *
2020      * Returns:
2021      *  The stored value or def if no value is stored.
2022      */
2023     T val()
2024     {
2025         Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
2026
2027         return wrap ? wrap.val : m_def;
2028     }
2029
2030
2031     /**
2032      * Copies newval to a location specific to the calling thread, and returns
2033      * newval.
2034      *
2035      * Params:
2036      *  newval = The value to set.
2037      *
2038      * Returns:
2039      *  The value passed to this function.
2040      */
2041     T val( T newval )
2042     {
2043         Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
2044
2045         if( wrap is null )
2046         {
2047             wrap = new Wrap;
2048             Thread.setLocal( m_key, wrap );
2049         }
2050         wrap.val = newval;
2051         return newval;
2052     }
2053
2054
2055 private:
2056     //
2057     // A wrapper for the stored data.  This is needed for determining whether
2058     // set has ever been called for this thread (and therefore whether the
2059     // default value should be returned) and also to flatten the differences
2060     // between data that is smaller and larger than (void*).sizeof.  The
2061     // obvious tradeoff here is an extra per-thread allocation for each
2062     // ThreadLocal value as compared to calling the Thread routines directly.
2063     //
2064     struct Wrap
2065     {
2066         T   val;
2067     }
2068
2069
2070     T       m_def;
2071     uint    m_key;
2072 }
2073
2074
2075 ///////////////////////////////////////////////////////////////////////////////
2076 // Thread Group
2077 ///////////////////////////////////////////////////////////////////////////////
2078
2079
2080 /**
2081  * This class is intended to simplify certain common programming techniques.
2082  */
2083 class ThreadGroup
2084 {
2085     /**
2086      * Creates and starts a new Thread object that executes fn and adds it to
2087      * the list of tracked threads.
2088      *
2089      * Params:
2090      *  fn = The thread function.
2091      *
2092      * Returns:
2093      *  A reference to the newly created thread.
2094      */
2095     final Thread create( void function() fn )
2096     {
2097         Thread t = new Thread( fn );
2098
2099         t.start();
2100         synchronized( this )
2101         {
2102             m_all[t] = t;
2103         }
2104         return t;
2105     }
2106
2107
2108     /**
2109      * Creates and starts a new Thread object that executes dg and adds it to
2110      * the list of tracked threads.
2111      *
2112      * Params:
2113      *  dg = The thread function.
2114      *
2115      * Returns:
2116      *  A reference to the newly created thread.
2117      */
2118     final Thread create( void delegate() dg )
2119     {
2120         Thread t = new Thread( dg );
2121
2122         t.start();
2123         synchronized( this )
2124         {
2125             m_all[t] = t;
2126         }
2127         return t;
2128     }
2129
2130
2131     /**
2132      * Add t to the list of tracked threads if it is not already being tracked.
2133      *
2134      * Params:
2135      *  t = The thread to add.
2136      *
2137      * In:
2138      *  t must not be null.
2139      */
2140     final void add( Thread t )
2141     in
2142     {
2143         assert( t );
2144     }
2145     body
2146     {
2147         synchronized( this )
2148         {
2149             m_all[t] = t;
2150         }
2151     }
2152
2153
2154     /**
2155      * Removes t from the list of tracked threads.  No operation will be
2156      * performed if t is not currently being tracked by this object.
2157      *
2158      * Params:
2159      *  t = The thread to remove.
2160      *
2161      * In:
2162      *  t must not be null.
2163      */
2164     final void remove( Thread t )
2165     in
2166     {
2167         assert( t );
2168     }
2169     body
2170     {
2171         synchronized( this )
2172         {
2173             m_all.remove( t );
2174         }
2175     }
2176
2177
2178     /**
2179      * Operates on all threads currently tracked by this object.
2180      */
2181     final int opApply( int delegate( inout Thread ) dg )
2182     {
2183         synchronized( this )
2184         {
2185             int ret = 0;
2186
2187             // NOTE: This loop relies on the knowledge that m_all uses the
2188             //       Thread object for both the key and the mapped value.
2189             foreach( Thread t; m_all.keys )
2190             {
2191                 ret = dg( t );
2192                 if( ret )
2193                     break;
2194             }
2195             return ret;
2196         }
2197     }
2198
2199
2200     /**
2201      * Iteratively joins all tracked threads.  This function will block add,
2202      * remove, and opApply until it completes.
2203      *
2204      * Params:
2205      *  rethrow = Rethrow any unhandled exception which may have caused the
2206      *            current thread to terminate.
2207      *
2208      * Throws:
2209      *  Any exception not handled by the joined threads.
2210      */
2211     final void joinAll( bool rethrow = true )
2212     {
2213         synchronized( this )
2214         {
2215             // NOTE: This loop relies on the knowledge that m_all uses the
2216             //       Thread object for both the key and the mapped value.
2217             foreach( Thread t; m_all.keys )
2218             {
2219                 t.join( rethrow );
2220             }
2221         }
2222     }
2223
2224
2225 private:
2226     Thread[Thread]  m_all;
2227 }
2228
2229
2230 ///////////////////////////////////////////////////////////////////////////////
2231 // Fiber Platform Detection and Memory Allocation
2232 ///////////////////////////////////////////////////////////////////////////////
2233
2234
2235 private
2236 {
2237     version( D_InlineAsm_X86 )
2238     {
2239         version( X86_64 )
2240         {
2241
2242         }
2243         else
2244         {
2245             version( Win32 )
2246                 version = AsmX86_Win32;
2247             else version( Posix )
2248                 version = AsmX86_Posix;
2249         }
2250     }
2251     else version( PPC )
2252     {
2253         version( Posix )
2254             version = AsmPPC_Posix;
2255     }
2256
2257
2258     version( Posix )
2259     {
2260         import core.sys.posix.unistd;   // for sysconf
2261         import core.sys.posix.sys.mman; // for mmap
2262         import core.sys.posix.stdlib;   // for malloc, valloc, free
2263
2264         version( AsmX86_Win32 ) {} else
2265         version( AsmX86_Posix ) {} else
2266         version( AsmPPC_Posix ) {} else
2267         {
2268             // NOTE: The ucontext implementation requires architecture specific
2269             //       data definitions to operate so testing for it must be done
2270             //       by checking for the existence of ucontext_t rather than by
2271             //       a version identifier.  Please note that this is considered
2272             //       an obsolescent feature according to the POSIX spec, so a
2273             //       custom solution is still preferred.
2274             import core.sys.posix.ucontext;
2275         }
2276     }
2277
2278     const size_t PAGESIZE;
2279 }
2280
2281
2282 static this()
2283 {
2284     static if( is( typeof( GetSystemInfo ) ) )
2285     {
2286         SYSTEM_INFO info;
2287         GetSystemInfo( &info );
2288
2289         PAGESIZE = info.dwPageSize;
2290         assert( PAGESIZE < int.max );
2291     }
2292     else static if( is( typeof( sysconf ) ) &&
2293                     is( typeof( _SC_PAGESIZE ) ) )
2294     {
2295         PAGESIZE = cast(size_t) sysconf( _SC_PAGESIZE );
2296         assert( PAGESIZE < int.max );
2297     }
2298     else
2299     {
2300         version( PPC )
2301             PAGESIZE = 8192;
2302         else
2303             PAGESIZE = 4096;
2304     }
2305 }
2306
2307
2308 ///////////////////////////////////////////////////////////////////////////////
2309 // Fiber Entry Point and Context Switch
2310 ///////////////////////////////////////////////////////////////////////////////
2311
2312
2313 private
2314 {
2315     extern (C) void fiber_entryPoint()
2316     {
2317         Fiber   obj = Fiber.getThis();
2318         assert( obj );
2319
2320         assert( Thread.getThis().m_curr is obj.m_ctxt );
2321         volatile Thread.getThis().m_lock = false;
2322         obj.m_ctxt.tstack = obj.m_ctxt.bstack;
2323         obj.m_state = Fiber.State.EXEC;
2324
2325         try
2326         {
2327             obj.run();
2328         }
2329         catch( Object o )
2330         {
2331             obj.m_unhandled = o;
2332         }
2333
2334         static if( is( ucontext_t ) )
2335           obj.m_ucur = &obj.m_utxt;
2336
2337         obj.m_state = Fiber.State.TERM;
2338         obj.switchOut();
2339     }
2340
2341
2342   // NOTE: If AsmPPC_Posix is defined then the context switch routine will
2343   //       be defined externally until GDC supports inline PPC ASM.
2344   version( AsmPPC_Posix )
2345     extern (C) void fiber_switchContext( void** oldp, void* newp );
2346   else
2347     extern (C) void fiber_switchContext( void** oldp, void* newp )
2348     {
2349         // NOTE: The data pushed and popped in this routine must match the
2350         //       default stack created by Fiber.initStack or the initial
2351         //       switch into a new context will fail.
2352
2353         version( AsmX86_Win32 )
2354         {
2355             asm
2356             {
2357                 naked;
2358
2359                 // save current stack state
2360                 push EBP;
2361                 mov  EBP, ESP;
2362                 push EAX;
2363                 push dword ptr FS:[0];
2364                 push dword ptr FS:[4];
2365                 push dword ptr FS:[8];
2366                 push EBX;
2367                 push ESI;
2368                 push EDI;
2369
2370                 // store oldp again with more accurate address
2371                 mov EAX, dword ptr 8[EBP];
2372                 mov [EAX], ESP;
2373                 // load newp to begin context switch
2374                 mov ESP, dword ptr 12[EBP];
2375
2376                 // load saved state from new stack
2377                 pop EDI;
2378                 pop ESI;
2379                 pop EBX;
2380                 pop dword ptr FS:[8];
2381                 pop dword ptr FS:[4];
2382                 pop dword ptr FS:[0];
2383                 pop EAX;
2384                 pop EBP;
2385
2386                 // 'return' to complete switch
2387                 ret;
2388             }
2389         }
2390         else version( AsmX86_Posix )
2391         {
2392             asm
2393             {
2394                 naked;
2395
2396                 // save current stack state
2397                 push EBP;
2398                 mov  EBP, ESP;
2399                 push EAX;
2400                 push EBX;
2401                 push ESI;
2402                 push EDI;
2403
2404                 // store oldp again with more accurate address
2405                 mov EAX, dword ptr 8[EBP];
2406                 mov [EAX], ESP;
2407                 // load newp to begin context switch
2408                 mov ESP, dword ptr 12[EBP];
2409
2410                 // load saved state from new stack
2411                 pop EDI;
2412                 pop ESI;
2413                 pop EBX;
2414                 pop EAX;
2415                 pop EBP;
2416
2417                 // 'return' to complete switch
2418                 ret;
2419             }
2420         }
2421         else static if( is( ucontext_t ) )
2422         {
2423             Fiber   cfib = Fiber.getThis();
2424             void*   ucur = cfib.m_ucur;
2425
2426             *oldp = &ucur;
2427             swapcontext( **(cast(ucontext_t***) oldp),
2428                           *(cast(ucontext_t**)  newp) );
2429         }
2430     }
2431 }
2432
2433
2434 ///////////////////////////////////////////////////////////////////////////////
2435 // Fiber
2436 ///////////////////////////////////////////////////////////////////////////////
2437
2438
2439 /**
2440  * This class provides a cooperative concurrency mechanism integrated with the
2441  * threading and garbage collection functionality.  Calling a fiber may be
2442  * considered a blocking operation that returns when the fiber yields (via
2443  * Fiber.yield()).  Execution occurs within the context of the calling thread
2444  * so synchronization is not necessary to guarantee memory visibility so long
2445  * as the same thread calls the fiber each time.  Please note that there is no
2446  * requirement that a fiber be bound to one specific thread.  Rather, fibers
2447  * may be freely passed between threads so long as they are not currently
2448  * executing.  Like threads, a new fiber thread may be created using either
2449  * derivation or composition, as in the following example.
2450  *
2451  * Example:
2452  * ----------------------------------------------------------------------
2453  *
2454  * class DerivedFiber : Fiber
2455  * {
2456  *     this()
2457  *     {
2458  *         super( &run );
2459  *     }
2460  *
2461  * private :
2462  *     void run()
2463  *     {
2464  *         printf( "Derived fiber running.\n" );
2465  *     }
2466  * }
2467  *
2468  * void fiberFunc()
2469  * {
2470  *     printf( "Composed fiber running.\n" );
2471  *     Fiber.yield();
2472  *     printf( "Composed fiber running.\n" );
2473  * }
2474  *
2475  * // create instances of each type
2476  * Fiber derived = new DerivedFiber();
2477  * Fiber composed = new Fiber( &fiberFunc );
2478  *
2479  * // call both fibers once
2480  * derived.call();
2481  * composed.call();
2482  * printf( "Execution returned to calling context.\n" );
2483  * composed.call();
2484  *
2485  * // since each fiber has run to completion, each should have state TERM
2486  * assert( derived.state == Fiber.State.TERM );
2487  * assert( composed.state == Fiber.State.TERM );
2488  *
2489  * ----------------------------------------------------------------------
2490  *
2491  * Authors: Based on a design by Mikola Lysenko.
2492  */
2493 class Fiber
2494 {
2495     ///////////////////////////////////////////////////////////////////////////
2496     // Initialization
2497     ///////////////////////////////////////////////////////////////////////////
2498
2499
2500     /**
2501      * Initializes a fiber object which is associated with a static
2502      * D function.
2503      *
2504      * Params:
2505      *  fn = The thread function.
2506      *  sz = The stack size for this fiber.
2507      *
2508      * In:
2509      *  fn must not be null.
2510      */
2511     this( void function() fn, size_t sz = PAGESIZE )
2512     in
2513     {
2514         assert( fn );
2515     }
2516     body
2517     {
2518         m_fn    = fn;
2519         m_call  = Call.FN;
2520         m_state = State.HOLD;
2521         allocStack( sz );
2522         initStack();
2523     }
2524
2525
2526     /**
2527      * Initializes a fiber object which is associated with a dynamic
2528      * D function.
2529      *
2530      * Params:
2531      *  dg = The thread function.
2532      *  sz = The stack size for this fiber.
2533      *
2534      * In:
2535      *  dg must not be null.
2536      */
2537     this( void delegate() dg, size_t sz = PAGESIZE )
2538     in
2539     {
2540         assert( dg );
2541     }
2542     body
2543     {
2544         m_dg    = dg;
2545         m_call  = Call.DG;
2546         m_state = State.HOLD;
2547         allocStack( sz );
2548         initStack();
2549     }
2550
2551
2552     /**
2553      * Cleans up any remaining resources used by this object.
2554      */
2555     ~this()
2556     {
2557         // NOTE: A live reference to this object will exist on its associated
2558         //       stack from the first time its call() method has been called
2559         //       until its execution completes with State.TERM.  Thus, the only
2560         //       times this dtor should be called are either if the fiber has
2561         //       terminated (and therefore has no active stack) or if the user
2562         //       explicitly deletes this object.  The latter case is an error
2563         //       but is not easily tested for, since State.HOLD may imply that
2564         //       the fiber was just created but has never been run.  There is
2565         //       not a compelling case to create a State.INIT just to offer a
2566         //       means of ensuring the user isn't violating this object's
2567         //       contract, so for now this requirement will be enforced by
2568         //       documentation only.
2569         freeStack();
2570     }
2571
2572
2573     ///////////////////////////////////////////////////////////////////////////
2574     // General Actions
2575     ///////////////////////////////////////////////////////////////////////////
2576
2577
2578     /**
2579      * Transfers execution to this fiber object.  The calling context will be
2580      * suspended until the fiber calls Fiber.yield() or until it terminates
2581      * via an unhandled exception.
2582      *
2583      * Params:
2584      *  rethrow = Rethrow any unhandled exception which may have caused this
2585      *            fiber to terminate.
2586      *
2587      * In:
2588      *  This fiber must be in state HOLD.
2589      *
2590      * Throws:
2591      *  Any exception not handled by the joined thread.
2592      *
2593      * Returns:
2594      *  Any exception not handled by this fiber if rethrow = false, null
2595      *  otherwise.
2596      */
2597     final Object call( bool rethrow = true )
2598     in
2599     {
2600         assert( m_state == State.HOLD );
2601     }
2602     body
2603     {
2604         Fiber   cur = getThis();
2605
2606         static if( is( ucontext_t ) )
2607           m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt;
2608
2609         setThis( this );
2610         this.switchIn();
2611         setThis( cur );
2612
2613         static if( is( ucontext_t ) )
2614           m_ucur = null;
2615
2616         // NOTE: If the fiber has terminated then the stack pointers must be
2617         //       reset.  This ensures that the stack for this fiber is not
2618         //       scanned if the fiber has terminated.  This is necessary to
2619         //       prevent any references lingering on the stack from delaying
2620         //       the collection of otherwise dead objects.  The most notable
2621         //       being the current object, which is referenced at the top of
2622         //       fiber_entryPoint.
2623         if( m_state == State.TERM )
2624         {
2625             m_ctxt.tstack = m_ctxt.bstack;
2626         }
2627         if( m_unhandled )
2628         {
2629             Object obj  = m_unhandled;
2630             m_unhandled = null;
2631             if( rethrow )
2632                 throw obj;
2633             return obj;
2634         }
2635         return null;
2636     }
2637
2638
2639     /**
2640      * Resets this fiber so that it may be re-used.  This routine may only be
2641      * called for fibers that have terminated, as doing otherwise could result
2642      * in scope-dependent functionality that is not executed.  Stack-based
2643      * classes, for example, may not be cleaned up properly if a fiber is reset
2644      * before it has terminated.
2645      *
2646      * In:
2647      *  This fiber must be in state TERM.
2648      */
2649     final void reset()
2650     in
2651     {
2652         assert( m_state == State.TERM );
2653         assert( m_ctxt.tstack == m_ctxt.bstack );
2654     }
2655     body
2656     {
2657         m_state = State.HOLD;
2658         initStack();
2659         m_unhandled = null;
2660     }
2661
2662
2663     ///////////////////////////////////////////////////////////////////////////
2664     // General Properties
2665     ///////////////////////////////////////////////////////////////////////////
2666
2667
2668     /**
2669      * A fiber may occupy one of three states: HOLD, EXEC, and TERM.  The HOLD
2670      * state applies to any fiber that is suspended and ready to be called.
2671      * The EXEC state will be set for any fiber that is currently executing.
2672      * And the TERM state is set when a fiber terminates.  Once a fiber
2673      * terminates, it must be reset before it may be called again.
2674      */
2675     enum State
2676     {
2677         HOLD,   ///
2678         EXEC,   ///
2679         TERM    ///
2680     }
2681
2682
2683     /**
2684      * Gets the current state of this fiber.
2685      *
2686      * Returns:
2687      *  The state of this fiber as an enumerated value.
2688      */
2689     final State state()
2690     {
2691         return m_state;
2692     }
2693
2694
2695     ///////////////////////////////////////////////////////////////////////////
2696     // Actions on Calling Fiber
2697     ///////////////////////////////////////////////////////////////////////////
2698
2699
2700     /**
2701      * Forces a context switch to occur away from the calling fiber.
2702      */
2703     static void yield()
2704     {
2705         Fiber   cur = getThis();
2706         assert( cur, "Fiber.yield() called with no active fiber" );
2707         assert( cur.m_state == State.EXEC );
2708
2709         static if( is( ucontext_t ) )
2710           cur.m_ucur = &cur.m_utxt;
2711
2712         cur.m_state = State.HOLD;
2713         cur.switchOut();
2714         cur.m_state = State.EXEC;
2715     }
2716
2717
2718     /**
2719      * Forces a context switch to occur away from the calling fiber and then
2720      * throws obj in the calling fiber.
2721      *
2722      * Params:
2723      *  obj = The object to throw.
2724      *
2725      * In:
2726      *  obj must not be null.
2727      */
2728     static void yieldAndThrow( Object obj )
2729     in
2730     {
2731         assert( obj );
2732     }
2733     body
2734     {
2735         Fiber   cur = getThis();
2736         assert( cur, "Fiber.yield() called with no active fiber" );
2737         assert( cur.m_state == State.EXEC );
2738
2739         static if( is( ucontext_t ) )
2740           cur.m_ucur = &cur.m_utxt;
2741
2742         cur.m_unhandled = obj;
2743         cur.m_state = State.HOLD;
2744         cur.switchOut();
2745         cur.m_state = State.EXEC;
2746     }
2747
2748
2749     ///////////////////////////////////////////////////////////////////////////
2750     // Fiber Accessors
2751     ///////////////////////////////////////////////////////////////////////////
2752
2753
2754     /**
2755      * Provides a reference to the calling fiber or null if no fiber is
2756      * currently active.
2757      *
2758      * Returns:
2759      *  The fiber object representing the calling fiber or null if no fiber
2760      *  is currently active.  The result of deleting this object is undefined.
2761      */
2762     static Fiber getThis()
2763     {
2764         version( Win32 )
2765         {
2766             return cast(Fiber) TlsGetValue( sm_this );
2767         }
2768         else version( Posix )
2769         {
2770             return cast(Fiber) pthread_getspecific( sm_this );
2771         }
2772     }
2773
2774
2775     ///////////////////////////////////////////////////////////////////////////
2776     // Static Initialization
2777     ///////////////////////////////////////////////////////////////////////////
2778
2779
2780     static this()
2781     {
2782         version( Win32 )
2783         {
2784             sm_this = TlsAlloc();
2785             assert( sm_this != TLS_OUT_OF_INDEXES );
2786         }
2787         else version( Posix )
2788         {
2789             int status;
2790
2791             status = pthread_key_create( &sm_this, null );
2792             assert( status == 0 );
2793
2794           static if( is( ucontext_t ) )
2795           {
2796             status = getcontext( &sm_utxt );
2797             assert( status == 0 );
2798           }
2799         }
2800     }
2801
2802
2803 private:
2804     //
2805     // Initializes a fiber object which has no associated executable function.
2806     //
2807     this()
2808     {
2809         m_call = Call.NO;
2810     }
2811
2812
2813     //
2814     // Fiber entry point.  Invokes the function or delegate passed on
2815     // construction (if any).
2816     //
2817     final void run()
2818     {
2819         switch( m_call )
2820         {
2821         case Call.FN:
2822             m_fn();
2823             break;
2824         case Call.DG:
2825             m_dg();
2826             break;
2827         default:
2828             break;
2829         }
2830     }
2831
2832
2833 private:
2834     //
2835     // The type of routine passed on fiber construction.
2836     //
2837     enum Call
2838     {
2839         NO,
2840         FN,
2841         DG
2842     }
2843
2844
2845     //
2846     // Standard fiber data
2847     //
2848     Call                m_call;
2849     union
2850     {
2851         void function() m_fn;
2852         void delegate() m_dg;
2853     }
2854     bool                m_isRunning;
2855     Object              m_unhandled;
2856     State               m_state;
2857
2858
2859 private:
2860     ///////////////////////////////////////////////////////////////////////////
2861     // Stack Management
2862     ///////////////////////////////////////////////////////////////////////////
2863
2864
2865     //
2866     // Allocate a new stack for this fiber.
2867     //
2868     final void allocStack( size_t sz )
2869     in
2870     {
2871         assert( !m_pmem && !m_ctxt );
2872     }
2873     body
2874     {
2875         // adjust alloc size to a multiple of PAGESIZE
2876         sz += PAGESIZE - 1;
2877         sz -= sz % PAGESIZE;
2878
2879         // NOTE: This instance of Thread.Context is dynamic so Fiber objects
2880         //       can be collected by the GC so long as no user level references
2881         //       to the object exist.  If m_ctxt were not dynamic then its
2882         //       presence in the global context list would be enough to keep
2883         //       this object alive indefinitely.  An alternative to allocating
2884         //       room for this struct explicitly would be to mash it into the
2885         //       base of the stack being allocated below.  However, doing so
2886         //       requires too much special logic to be worthwhile.
2887         m_ctxt = new Thread.Context;
2888
2889         static if( is( typeof( VirtualAlloc ) ) )
2890         {
2891             // reserve memory for stack
2892             m_pmem = VirtualAlloc( null,
2893                                    sz + PAGESIZE,
2894                                    MEM_RESERVE,
2895                                    PAGE_NOACCESS );
2896             if( !m_pmem )
2897             {
2898                 throw new FiberException( "Unable to reserve memory for stack" );
2899             }
2900
2901             version( StackGrowsDown )
2902             {
2903                 void* stack = m_pmem + PAGESIZE;
2904                 void* guard = m_pmem;
2905                 void* pbase = stack + sz;
2906             }
2907             else
2908             {
2909                 void* stack = m_pmem;
2910                 void* guard = m_pmem + sz;
2911                 void* pbase = stack;
2912             }
2913
2914             // allocate reserved stack segment
2915             stack = VirtualAlloc( stack,
2916                                   sz,
2917                                   MEM_COMMIT,
2918                                   PAGE_READWRITE );
2919             if( !stack )
2920             {
2921                 throw new FiberException( "Unable to allocate memory for stack" );
2922             }
2923
2924             // allocate reserved guard page
2925             guard = VirtualAlloc( guard,
2926                                   PAGESIZE,
2927                                   MEM_COMMIT,
2928                                   PAGE_READWRITE | PAGE_GUARD );
2929             if( !guard )
2930             {
2931                 throw new FiberException( "Unable to create guard page for stack" );
2932             }
2933
2934             m_ctxt.bstack = pbase;
2935             m_ctxt.tstack = pbase;
2936             m_size = sz;
2937         }
2938         else
2939         {   static if( is( typeof( mmap ) ) )
2940             {
2941                 m_pmem = mmap( null,
2942                                sz,
2943                                PROT_READ | PROT_WRITE,
2944                                MAP_PRIVATE | MAP_ANON,
2945                                -1,
2946                                0 );
2947                 if( m_pmem == MAP_FAILED )
2948                     m_pmem = null;
2949             }
2950             else static if( is( typeof( valloc ) ) )
2951             {
2952                 m_pmem = valloc( sz );
2953             }
2954             else static if( is( typeof( malloc ) ) )
2955             {
2956                 m_pmem = malloc( sz );
2957             }
2958             else
2959             {
2960                 m_pmem = null;
2961             }
2962
2963             if( !m_pmem )
2964             {
2965                 throw new FiberException( "Unable to allocate memory for stack" );
2966             }
2967
2968             version( StackGrowsDown )
2969             {
2970                 m_ctxt.bstack = m_pmem + sz;
2971                 m_ctxt.tstack = m_pmem + sz;
2972             }
2973             else
2974             {
2975                 m_ctxt.bstack = m_pmem;
2976                 m_ctxt.tstack = m_pmem;
2977             }
2978             m_size = sz;
2979         }
2980
2981         Thread.add( m_ctxt );
2982     }
2983
2984
2985     //
2986     // Free this fiber's stack.
2987     //
2988     final void freeStack()
2989     in
2990     {
2991         assert( m_pmem && m_ctxt );
2992     }
2993     body
2994     {
2995         // NOTE: Since this routine is only ever expected to be called from
2996         //       the dtor, pointers to freed data are not set to null.
2997
2998         // NOTE: m_ctxt is guaranteed to be alive because it is held in the
2999         //       global context list.
3000         Thread.remove( m_ctxt );
3001
3002         static if( is( typeof( VirtualAlloc ) ) )
3003         {
3004             VirtualFree( m_pmem, 0, MEM_RELEASE );
3005         }
3006         else static if( is( typeof( mmap ) ) )
3007         {
3008             munmap( m_pmem, m_size );
3009         }
3010         else static if( is( typeof( valloc ) ) )
3011         {
3012             free( m_pmem );
3013         }
3014         else static if( is( typeof( malloc ) ) )
3015         {
3016             free( m_pmem );
3017         }
3018         delete m_ctxt;
3019     }
3020
3021
3022     //
3023     // Initialize the allocated stack.
3024     //
3025     final void initStack()
3026     in
3027     {
3028         assert( m_ctxt.tstack && m_ctxt.tstack == m_ctxt.bstack );
3029         assert( cast(size_t) m_ctxt.bstack % (void*).sizeof == 0 );
3030     }
3031     body
3032     {
3033         void* pstack = m_ctxt.tstack;
3034         scope( exit )  m_ctxt.tstack = pstack;
3035
3036         void push( size_t val )
3037         {
3038             version( StackGrowsDown )
3039             {
3040                 pstack -= size_t.sizeof;
3041                 *(cast(size_t*) pstack) = val;
3042             }
3043             else
3044             {
3045                 pstack += size_t.sizeof;
3046                 *(cast(size_t*) pstack) = val;
3047             }
3048         }
3049
3050         // NOTE: On OS X the stack must be 16-byte aligned according to the
3051         // IA-32 call spec.
3052         version( darwin )
3053         {
3054              pstack = cast(void*)(cast(uint)(pstack) - (cast(uint)(pstack) & 0x0F));
3055         }
3056
3057         version( AsmX86_Win32 )
3058         {
3059             push( cast(size_t) &fiber_entryPoint );                 // EIP
3060             push( 0xFFFFFFFF );                                     // EBP
3061             push( 0x00000000 );                                     // EAX
3062             push( 0xFFFFFFFF );                                     // FS:[0]
3063             version( StackGrowsDown )
3064             {
3065                 push( cast(size_t) m_ctxt.bstack );                 // FS:[4]
3066                 push( cast(size_t) m_ctxt.bstack - m_size );        // FS:[8]
3067             }
3068             else
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             push( 0x00000000 );                                     // EBX
3074             push( 0x00000000 );                                     // ESI
3075             push( 0x00000000 );                                     // EDI
3076         }
3077         else version( AsmX86_Posix )
3078         {
3079             push( cast(size_t) &fiber_entryPoint );                 // EIP
3080             push( 0x00000000 );                                     // EBP
3081             push( 0x00000000 );                                     // EAX
3082             push( 0x00000000 );                                     // EBX
3083             push( 0x00000000 );                                     // ESI
3084             push( 0x00000000 );                                     // EDI
3085         }
3086         else version( AsmPPC_Posix )
3087         {
3088             version( StackGrowsDown )
3089             {
3090                 pstack -= int.sizeof * 5;
3091             }
3092             else
3093             {
3094                 pstack += int.sizeof * 5;
3095             }
3096
3097             push( cast(size_t) &fiber_entryPoint );     // link register
3098             push( 0x00000000 );                         // control register
3099             push( 0x00000000 );                         // old stack pointer
3100
3101             // GPR values
3102             version( StackGrowsDown )
3103             {
3104                 pstack -= int.sizeof * 20;
3105             }
3106             else
3107             {
3108                 pstack += int.sizeof * 20;
3109             }
3110
3111             assert( cast(uint) pstack & 0x0f == 0 );
3112         }
3113         else static if( is( ucontext_t ) )
3114         {
3115             getcontext( &m_utxt );
3116             m_utxt.uc_stack.ss_sp   = m_ctxt.bstack;
3117             m_utxt.uc_stack.ss_size = m_size;
3118             makecontext( &m_utxt, &fiber_entryPoint, 0 );
3119             // NOTE: If ucontext is being used then the top of the stack will
3120             //       be a pointer to the ucontext_t struct for that fiber.
3121             push( cast(size_t) &m_utxt );
3122         }
3123     }
3124
3125
3126     Thread.Context* m_ctxt;
3127     size_t          m_size;
3128     void*           m_pmem;
3129
3130     static if( is( ucontext_t ) )
3131     {
3132         // NOTE: The static ucontext instance is used to represent the context
3133         //       of the main application thread.
3134         static ucontext_t   sm_utxt = void;
3135         ucontext_t          m_utxt  = void;
3136         ucontext_t*         m_ucur  = null;
3137     }
3138
3139
3140 private:
3141     ///////////////////////////////////////////////////////////////////////////
3142     // Storage of Active Fiber
3143     ///////////////////////////////////////////////////////////////////////////
3144
3145
3146     //
3147     // Sets a thread-local reference to the current fiber object.
3148     //
3149     static void setThis( Fiber f )
3150     {
3151         version( Win32 )
3152         {
3153             TlsSetValue( sm_this, cast(void*) f );
3154         }
3155         else version( Posix )
3156         {
3157             pthread_setspecific( sm_this, cast(void*) f );
3158         }
3159     }
3160
3161
3162     static Thread.TLSKey    sm_this;
3163
3164
3165 private:
3166     ///////////////////////////////////////////////////////////////////////////
3167     // Context Switching
3168     ///////////////////////////////////////////////////////////////////////////
3169
3170
3171     //
3172     // Switches into the stack held by this fiber.
3173     //
3174     final void switchIn()
3175     {
3176         Thread  tobj = Thread.getThis();
3177         void**  oldp = &tobj.m_curr.tstack;
3178         void*   newp = m_ctxt.tstack;
3179
3180         // NOTE: The order of operations here is very important.  The current
3181         //       stack top must be stored before m_lock is set, and pushContext
3182         //       must not be called until after m_lock is set.  This process
3183         //       is intended to prevent a race condition with the suspend
3184         //       mechanism used for garbage collection.  If it is not followed,
3185         //       a badly timed collection could cause the GC to scan from the
3186         //       bottom of one stack to the top of another, or to miss scanning
3187         //       a stack that still contains valid data.  The old stack pointer
3188         //       oldp will be set again before the context switch to guarantee
3189         //       that it points to exactly the correct stack location so the
3190         //       successive pop operations will succeed.
3191         *oldp = getStackTop();
3192         volatile tobj.m_lock = true;
3193         tobj.pushContext( m_ctxt );
3194
3195         fiber_switchContext( oldp, newp );
3196
3197         // NOTE: As above, these operations must be performed in a strict order
3198         //       to prevent Bad Things from happening.
3199         tobj.popContext();
3200         volatile tobj.m_lock = false;
3201         tobj.m_curr.tstack = tobj.m_curr.bstack;
3202     }
3203
3204
3205     //
3206     // Switches out of the current stack and into the enclosing stack.
3207     //
3208     final void switchOut()
3209     {
3210         Thread  tobj = Thread.getThis();
3211         void**  oldp = &m_ctxt.tstack;
3212         void*   newp = tobj.m_curr.within.tstack;
3213
3214         // NOTE: The order of operations here is very important.  The current
3215         //       stack top must be stored before m_lock is set, and pushContext
3216         //       must not be called until after m_lock is set.  This process
3217         //       is intended to prevent a race condition with the suspend
3218         //       mechanism used for garbage collection.  If it is not followed,
3219         //       a badly timed collection could cause the GC to scan from the
3220         //       bottom of one stack to the top of another, or to miss scanning
3221         //       a stack that still contains valid data.  The old stack pointer
3222         //       oldp will be set again before the context switch to guarantee
3223         //       that it points to exactly the correct stack location so the
3224         //       successive pop operations will succeed.
3225         *oldp = getStackTop();
3226         volatile tobj.m_lock = true;
3227
3228         fiber_switchContext( oldp, newp );
3229
3230         // NOTE: As above, these operations must be performed in a strict order
3231         //       to prevent Bad Things from happening.
3232         volatile tobj.m_lock = false;
3233         tobj.m_curr.tstack = tobj.m_curr.bstack;
3234     }
3235 }