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