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

root/tags/releases/0.99.9/tango/core/Thread.d

Revision 5330, 100.9 kB (checked in by kris, 2 years ago)

made Win32 HANDLE a void* rather than an int, in order to be 64bit compatible

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