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