Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Ticket #643: Thread.RegisterExternal.d

File Thread.RegisterExternal.d, 90.4 kB (added by CyberShadow, 5 years ago)

Failed attempt #2

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