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