root/trunk/src/core/thread.d

Revision 512, 109.4 kB (checked in by braddr, 1 year ago)

Remove another catch(Object)

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