2 * The thread module provides support for thread creation and management.
4 * Copyright: Copyright (c) 2005-2008, The D Runtime Project
5 * License: BSD Style, see LICENSE
11 // this should be true for most architectures
12 version = StackGrowsDown;
15 ///////////////////////////////////////////////////////////////////////////////
16 // Thread and Fiber Exceptions
17 ///////////////////////////////////////////////////////////////////////////////
21 * Base class for thread exceptions.
23 class ThreadException : Exception
33 * Base class for fiber exceptions.
35 class FiberException : Exception
47 // exposed by compiler runtime
49 extern (C) void* rt_stackBottom();
50 extern (C) void* rt_stackTop();
53 void* getStackBottom()
55 return rt_stackBottom();
61 version( D_InlineAsm_X86 )
78 ///////////////////////////////////////////////////////////////////////////////
79 // Thread Entry Point and Signal Handlers
80 ///////////////////////////////////////////////////////////////////////////////
87 import stdc.stdint : uintptr_t; // for _beginthreadex decl below
88 import sys.windows.windows;
90 const DWORD TLS_OUT_OF_INDEXES = 0xFFFFFFFF;
92 extern (Windows) alias uint function(void*) btex_fptr;
93 extern (C) uintptr_t _beginthreadex(void*, uint, btex_fptr, void*, uint, uint*);
97 // entry point for Windows threads
99 extern (Windows) uint thread_entryPoint( void* arg )
101 Thread obj = cast(Thread) arg;
103 scope( exit ) Thread.remove( obj );
105 assert( obj.m_curr is &obj.m_main );
106 obj.m_main.bstack = getStackBottom();
107 obj.m_main.tstack = obj.m_main.bstack;
108 Thread.add( &obj.m_main );
109 Thread.setThis( obj );
111 // NOTE: No GC allocations may occur until the stack pointers have
112 // been set and Thread.getThis returns a valid reference to
113 // this thread object (this latter condition is not strictly
114 // necessary on Win32 but it should be followed for the sake
117 // TODO: Consider putting an auto exception object here (using
118 // alloca) forOutOfMemoryError plus something to track
119 // whether an exception is in-flight?
134 // copy of the same-named function in phobos.std.thread--it uses the
135 // Windows naming convention to be consistent with GetCurrentThreadId
137 HANDLE GetCurrentThreadHandle()
139 const uint DUPLICATE_SAME_ACCESS = 0x00000002;
141 HANDLE curr = GetCurrentThread(),
142 proc = GetCurrentProcess(),
145 DuplicateHandle( proc, curr, proc, &hndl, 0, TRUE, DUPLICATE_SAME_ACCESS );
150 else version( Posix )
154 import stdc.posix.semaphore;
155 import stdc.posix.pthread;
156 import stdc.posix.signal;
157 import stdc.posix.time;
160 extern (C) int _d_getErrno();
161 alias _d_getErrno getErrno;
170 // entry point for POSIX threads
172 extern (C) void* thread_entryPoint( void* arg )
174 Thread obj = cast(Thread) arg;
178 // NOTE: isRunning should be set to false after the thread is
179 // removed or a double-removal could occur between this
180 // function and thread_suspendAll.
181 Thread.remove( obj );
182 obj.m_isRunning = false;
185 static extern (C) void thread_cleanupHandler( void* arg )
187 Thread obj = cast(Thread) arg;
190 // NOTE: If the thread terminated abnormally, just set it as
191 // not running and let thread_suspendAll remove it from
192 // the thread list. This is safer and is consistent
193 // with the Windows thread code.
194 obj.m_isRunning = false;
197 // NOTE: Using void to skip the initialization here relies on
198 // knowledge of how pthread_cleanup is implemented. It may
199 // not be appropriate for all platforms. However, it does
200 // avoid the need to link the pthread module. If any
201 // implementation actually requires default initialization
202 // then pthread_cleanup should be restructured to maintain
203 // the current lack of a link dependency.
204 pthread_cleanup cleanup = void;
205 cleanup.push( &thread_cleanupHandler, cast(void*) obj );
207 // NOTE: For some reason this does not always work for threads.
208 //obj.m_main.bstack = getStackBottom();
209 version( D_InlineAsm_X86 )
211 static void* getBasePtr()
221 obj.m_main.bstack = getBasePtr();
223 else version( StackGrowsDown )
224 obj.m_main.bstack = &obj + 1;
226 obj.m_main.bstack = &obj;
227 obj.m_main.tstack = obj.m_main.bstack;
228 assert( obj.m_curr == &obj.m_main );
229 Thread.add( &obj.m_main );
230 Thread.setThis( obj );
232 // NOTE: No GC allocations may occur until the stack pointers have
233 // been set and Thread.getThis returns a valid reference to
234 // this thread object (this latter condition is not strictly
235 // necessary on Win32 but it should be followed for the sake
238 // TODO: Consider putting an auto exception object here (using
239 // alloca) forOutOfMemoryError plus something to track
240 // whether an exception is in-flight?
255 // used to track the number of suspended threads
260 extern (C) void thread_suspendHandler( int sig )
263 assert( sig == SIGUSR1 );
267 version( D_InlineAsm_X86 )
276 __builtin_unwind_init();
280 static assert( false, "Architecture not supported." );
283 // NOTE: Since registers are being pushed and popped from the
284 // stack, any other stack data used by this function should
285 // be gone before the stack cleanup code is called below.
287 Thread obj = Thread.getThis();
289 // NOTE: The thread reference returned by getThis is set within
290 // the thread startup code, so it is possible that this
291 // handler may be called before the reference is set. In
292 // this case it is safe to simply suspend and not worry
293 // about the stack pointers as the thread will not have
294 // any references to GC-managed data.
295 if( obj && !obj.m_lock )
297 obj.m_curr.tstack = getStackTop();
300 sigset_t sigres = void;
303 status = sigfillset( &sigres );
304 assert( status == 0 );
306 status = sigdelset( &sigres, SIGUSR2 );
307 assert( status == 0 );
309 status = sem_post( &suspendCount );
310 assert( status == 0 );
312 sigsuspend( &sigres );
314 if( obj && !obj.m_lock )
316 obj.m_curr.tstack = obj.m_curr.bstack;
320 version( D_InlineAsm_X86 )
329 // registers will be popped automatically
333 static assert( false, "Architecture not supported." );
338 extern (C) void thread_resumeHandler( int sig )
341 assert( sig == SIGUSR2 );
351 // NOTE: This is the only place threading versions are checked. If a new
352 // version is added, the module code will need to be searched for
353 // places where version-specific code may be required. This can be
354 // easily accomlished by searching for 'Windows' or 'Posix'.
355 static assert( false, "Unknown threading implementation." );
359 ///////////////////////////////////////////////////////////////////////////////
361 ///////////////////////////////////////////////////////////////////////////////
365 * This class encapsulates all threading functionality for the D
366 * programming language. As thread manipulation is a required facility
367 * for garbage collection, all user threads should derive from this
368 * class, and instances of this class should never be explicitly deleted.
369 * A new thread may be created using either derivation or composition, as
370 * in the following example.
373 * ----------------------------------------------------------------------------
375 * class DerivedThread : Thread
385 * printf( "Derived thread running.\n" );
391 * printf( "Composed thread running.\n" );
394 * // create instances of each type
395 * Thread derived = new DerivedThread();
396 * Thread composed = new Thread( &threadFunc );
398 * // start both threads
402 * ----------------------------------------------------------------------------
406 ///////////////////////////////////////////////////////////////////////////
408 ///////////////////////////////////////////////////////////////////////////
412 * Initializes a thread object which is associated with a static
416 * fn = The thread function.
417 * sz = The stack size for this thread.
420 * fn must not be null.
422 this( void function() fn, size_t sz = 0 )
437 * Initializes a thread object which is associated with a dynamic
441 * dg = The thread function.
442 * sz = The stack size for this thread.
445 * dg must not be null.
447 this( void delegate() dg, size_t sz = 0 )
462 * Cleans up any remaining resources used by this object.
466 if( m_addr == m_addr.init )
473 m_addr = m_addr.init;
474 CloseHandle( m_hndl );
475 m_hndl = m_hndl.init;
477 else version( Posix )
479 pthread_detach( m_addr );
480 m_addr = m_addr.init;
485 ///////////////////////////////////////////////////////////////////////////
487 ///////////////////////////////////////////////////////////////////////////
491 * Starts the thread and invokes the function or delegate passed upon
495 * This routine may only be called once per thread instance.
498 * ThreadException if the thread fails to start.
503 assert( !next && !prev );
507 version( Win32 ) {} else
512 if( pthread_attr_init( &attr ) )
513 throw new ThreadException( "Error initializing thread attributes" );
514 if( m_sz && pthread_attr_setstacksize( &attr, m_sz ) )
515 throw new ThreadException( "Error initializing thread stack size" );
516 if( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) )
517 throw new ThreadException( "Error setting thread joinable" );
520 // NOTE: This operation needs to be synchronized to avoid a race
521 // condition with the GC. Without this lock, the thread
522 // could start and allocate memory before being added to
523 // the global thread list, preventing it from being scanned
524 // and causing memory to be collected that is still in use.
525 synchronized( slock )
529 m_hndl = cast(HANDLE) _beginthreadex( null, m_sz, &thread_entryPoint, cast(void*) this, 0, &m_addr );
530 if( cast(size_t) m_hndl == 0 )
531 throw new ThreadException( "Error creating thread" );
533 else version( Posix )
536 scope( failure ) m_isRunning = false;
538 if( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 )
539 throw new ThreadException( "Error creating thread" );
541 multiThreadedFlag = true;
548 * Waits for this thread to complete. If the thread terminated as the
549 * result of an unhandled exception, this exception will be rethrown.
552 * rethrow = Rethrow any unhandled exception which may have caused this
553 * thread to terminate.
556 * ThreadException if the operation fails.
557 * Any exception not handled by the joined thread.
560 * Any exception not handled by this thread if rethrow = false, null
563 final Object join( bool rethrow = true )
567 if( WaitForSingleObject( m_hndl, INFINITE ) != WAIT_OBJECT_0 )
568 throw new ThreadException( "Unable to join thread" );
569 // NOTE: m_addr must be cleared before m_hndl is closed to avoid
570 // a race condition with isRunning. The operation is labeled
571 // volatile to prevent compiler reordering.
572 volatile m_addr = m_addr.init;
573 CloseHandle( m_hndl );
574 m_hndl = m_hndl.init;
576 else version( Posix )
578 if( pthread_join( m_addr, null ) != 0 )
579 throw new ThreadException( "Unable to join thread" );
580 // NOTE: pthread_join acts as a substitute for pthread_detach,
581 // which is normally called by the dtor. Setting m_addr
582 // to zero ensures that pthread_detach will not be called
583 // on object destruction.
584 volatile m_addr = m_addr.init;
596 ///////////////////////////////////////////////////////////////////////////
597 // General Properties
598 ///////////////////////////////////////////////////////////////////////////
602 * Gets the user-readable label for this thread.
605 * The name of this thread.
617 * Sets the user-readable label for this thread.
620 * val = The new name of this thread.
622 final void name( char[] val )
632 * Gets the daemon status for this thread. While the runtime will wait for
633 * all normal threads to complete before tearing down the process, daemon
634 * threads are effectively ignored and thus will not prevent the process
635 * from terminating. In effect, daemon threads will be terminated
636 * automatically by the OS when the process exits.
639 * true if this is a daemon thread.
641 final bool isDaemon()
651 * Sets the daemon status for this thread. While the runtime will wait for
652 * all normal threads to complete before tearing down the process, daemon
653 * threads are effectively ignored and thus will not prevent the process
654 * from terminating. In effect, daemon threads will be terminated
655 * automatically by the OS when the process exits.
658 * val = The new daemon status for this thread.
660 final void isDaemon( bool val )
670 * Tests whether this thread is running.
673 * true if the thread is running, false if not.
675 final bool isRunning()
677 if( m_addr == m_addr.init )
685 GetExitCodeThread( m_hndl, &ecode );
686 return ecode == STILL_ACTIVE;
688 else version( Posix )
690 // NOTE: It should be safe to access this value without
691 // memory barriers because word-tearing and such
692 // really isn't an issue for boolean values.
698 ///////////////////////////////////////////////////////////////////////////
699 // Thread Priority Actions
700 ///////////////////////////////////////////////////////////////////////////
704 * The minimum scheduling priority that may be set for a thread. On
705 * systems where multiple scheduling policies are defined, this value
706 * represents the minimum valid priority for the scheduling policy of
709 static const int PRIORITY_MIN;
713 * The maximum scheduling priority that may be set for a thread. On
714 * systems where multiple scheduling policies are defined, this value
715 * represents the minimum valid priority for the scheduling policy of
718 static const int PRIORITY_MAX;
722 * Gets the scheduling priority for the associated thread.
725 * The scheduling priority of this thread.
731 return GetThreadPriority( m_hndl );
733 else version( Posix )
738 if( pthread_getschedparam( m_addr, &policy, ¶m ) )
739 throw new ThreadException( "Unable to get thread priority" );
740 return param.sched_priority;
746 * Sets the scheduling priority for the associated thread.
749 * val = The new scheduling priority of this thread.
751 final void priority( int val )
755 if( !SetThreadPriority( m_hndl, val ) )
756 throw new ThreadException( "Unable to set thread priority" );
758 else version( Posix )
760 // NOTE: pthread_setschedprio is not implemented on linux, so use
761 // the more complicated get/set sequence below.
762 //if( pthread_setschedprio( m_addr, val ) )
763 // throw new ThreadException( "Unable to set thread priority" );
768 if( pthread_getschedparam( m_addr, &policy, ¶m ) )
769 throw new ThreadException( "Unable to set thread priority" );
770 param.sched_priority = val;
771 if( pthread_setschedparam( m_addr, policy, ¶m ) )
772 throw new ThreadException( "Unable to set thread priority" );
777 ///////////////////////////////////////////////////////////////////////////
778 // Actions on Calling Thread
779 ///////////////////////////////////////////////////////////////////////////
783 * Suspends the calling thread for at least the supplied time, up to a
784 * maximum of (uint.max - 1) milliseconds.
787 * period = The minimum duration the calling thread should be suspended,
788 * in seconds. Sub-second durations are specified as fractional
792 * period must be less than (uint.max - 1) milliseconds.
795 * ------------------------------------------------------------------------
797 * Thread.sleep( 0.05 ); // sleep for 50 milliseconds
798 * Thread.sleep( 5 ); // sleep for 5 seconds
800 * ------------------------------------------------------------------------
802 static void sleep( double period )
805 // NOTE: The fractional value added to period is to correct fp error.
806 assert( period * 1000 + 0.1 < uint.max - 1 );
812 Sleep( cast(uint)( period * 1000 + 0.1 ) );
814 else version( Posix )
817 timespec tout = void;
819 period += 0.000_000_000_1;
821 if( tin.tv_sec.max < period )
823 tin.tv_sec = tin.tv_sec.max;
828 tin.tv_sec = cast(typeof(tin.tv_sec)) period;
829 tin.tv_nsec = cast(typeof(tin.tv_nsec)) ((period % 1.0) * 1_000_000_000);
834 if( !nanosleep( &tin, &tout ) )
836 if( getErrno() != EINTR )
837 throw new ThreadException( "Unable to sleep for specified duration" );
845 * Forces a context switch to occur away from the calling thread.
851 // NOTE: Sleep(1) is necessary because Sleep(0) does not give
852 // lower priority threads any timeslice, so looping on
853 // Sleep(0) could be resource-intensive in some cases.
856 else version( Posix )
863 ///////////////////////////////////////////////////////////////////////////
865 ///////////////////////////////////////////////////////////////////////////
869 * Provides a reference to the calling thread.
872 * The thread object representing the calling thread. The result of
873 * deleting this object is undefined.
875 static Thread getThis()
877 // NOTE: This function may not be called until thread_init has
878 // completed. See thread_suspendAll for more information
879 // on why this might occur.
882 return cast(Thread) TlsGetValue( sm_this );
884 else version( Posix )
886 return cast(Thread) pthread_getspecific( sm_this );
892 * Provides a list of all threads currently being tracked by the system.
895 * An array containing references to all threads currently being
896 * tracked by the system. The result of deleting any contained
897 * objects is undefined.
899 static Thread[] getAll()
901 synchronized( slock )
904 Thread[] buf = new Thread[sm_tlen];
906 foreach( Thread t; Thread )
916 * Operates on all threads currently being tracked by the system. The
917 * result of deleting any Thread object is undefined.
920 * dg = The supplied code as a delegate.
923 * Zero if all elemented are visited, nonzero if not.
925 static int opApply( int delegate( inout Thread ) dg )
927 synchronized( slock )
931 for( Thread t = sm_tbeg; t; t = t.next )
942 ///////////////////////////////////////////////////////////////////////////
943 // Local Storage Actions
944 ///////////////////////////////////////////////////////////////////////////
948 * Indicates the number of local storage pointers available at program
949 * startup. It is recommended that this number be at least 64.
951 static const uint LOCAL_MAX = 64;
955 * Reserves a local storage pointer for use and initializes this location
956 * to null for all running threads.
959 * A key representing the array offset of this memory location.
961 static uint createLocal()
963 synchronized( slock )
965 foreach( uint key, inout bool set; sm_local )
969 //foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
970 for( Thread t = sm_tbeg; t; t = t.next )
972 t.m_local[key] = null;
978 throw new ThreadException( "No more local storage slots available" );
984 * Marks the supplied key as available and sets the associated location
985 * to null for all running threads. It is assumed that any key passed
986 * to this function is valid. The result of calling this function for
987 * a key which is still in use is undefined.
990 * key = The key to delete.
992 static void deleteLocal( uint key )
994 synchronized( slock )
996 sm_local[key] = false;
997 // foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
998 for( Thread t = sm_tbeg; t; t = t.next )
1000 t.m_local[key] = null;
1007 * Loads the value stored at key within a thread-local static array. It is
1008 * assumed that any key passed to this function is valid.
1011 * key = The location which holds the desired data.
1014 * The data associated with the supplied key.
1016 static void* getLocal( uint key )
1018 return getThis().m_local[key];
1023 * Stores the supplied value at key within a thread-local static array. It
1024 * is assumed that any key passed to this function is valid.
1027 * key = The location to store the supplied data.
1028 * val = The data to store.
1031 * A copy of the data which has just been stored.
1033 static void* setLocal( uint key, void* val )
1035 return getThis().m_local[key] = val;
1039 ///////////////////////////////////////////////////////////////////////////
1040 // Static Initalizer
1041 ///////////////////////////////////////////////////////////////////////////
1045 * This initializer is used to set thread constants. All functional
1046 * initialization occurs within thread_init().
1055 else version( Posix )
1059 pthread_t self = pthread_self();
1061 int status = pthread_getschedparam( self, &policy, ¶m );
1062 assert( status == 0 );
1064 PRIORITY_MIN = sched_get_priority_min( policy );
1065 assert( PRIORITY_MIN != -1 );
1067 PRIORITY_MAX = sched_get_priority_max( policy );
1068 assert( PRIORITY_MAX != -1 );
1075 // Initializes a thread object which has no associated executable function.
1076 // This is used for the main thread initialized in thread_init().
1086 // Thread entry point. Invokes the function or delegate passed on
1087 // construction (if any).
1107 // The type of routine passed on thread construction.
1123 alias uint ThreadAddr;
1125 else version( Posix )
1127 alias pthread_key_t TLSKey;
1128 alias pthread_t ThreadAddr;
1135 static bool[LOCAL_MAX] sm_local;
1136 static TLSKey sm_this;
1138 void*[LOCAL_MAX] m_local;
1142 // Standard thread data
1153 void function() m_fn;
1154 void delegate() m_dg;
1166 ///////////////////////////////////////////////////////////////////////////
1167 // Storage of Active Thread
1168 ///////////////////////////////////////////////////////////////////////////
1172 // Sets a thread-local reference to the current thread object.
1174 static void setThis( Thread t )
1178 TlsSetValue( sm_this, cast(void*) t );
1180 else version( Posix )
1182 pthread_setspecific( sm_this, cast(void*) t );
1188 ///////////////////////////////////////////////////////////////////////////
1189 // Thread Context and GC Scanning Support
1190 ///////////////////////////////////////////////////////////////////////////
1193 final void pushContext( Context* c )
1196 assert( !c.within );
1205 final void popContext()
1208 assert( m_curr && m_curr.within );
1212 Context* c = m_curr;
1218 final Context* topContext()
1229 static struct Context
1245 uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
1250 ///////////////////////////////////////////////////////////////////////////
1251 // GC Scanning Support
1252 ///////////////////////////////////////////////////////////////////////////
1255 // NOTE: The GC scanning process works like so:
1257 // 1. Suspend all threads.
1258 // 2. Scan the stacks of all suspended threads for roots.
1259 // 3. Resume all threads.
1261 // Step 1 and 3 require a list of all threads in the system, while
1262 // step 2 requires a list of all thread stacks (each represented by
1263 // a Context struct). Traditionally, there was one stack per thread
1264 // and the Context structs were not necessary. However, Fibers have
1265 // changed things so that each thread has its own 'main' stack plus
1266 // an arbitrary number of nested stacks (normally referenced via
1267 // m_curr). Also, there may be 'free-floating' stacks in the system,
1268 // which are Fibers that are not currently executing on any specific
1269 // thread but are still being processed and still contain valid
1272 // To support all of this, the Context struct has been created to
1273 // represent a stack range, and a global list of Context structs has
1274 // been added to enable scanning of these stack ranges. The lifetime
1275 // (and presence in the Context list) of a thread's 'main' stack will
1276 // be equivalent to the thread's lifetime. So the Ccontext will be
1277 // added to the list on thread entry, and removed from the list on
1278 // thread exit (which is essentially the same as the presence of a
1279 // Thread object in its own global list). The lifetime of a Fiber's
1280 // context, however, will be tied to the lifetime of the Fiber object
1281 // itself, and Fibers are expected to add/remove their Context struct
1282 // on construction/deletion.
1286 // All use of the global lists should synchronize on this lock.
1288 static Object slock()
1290 return Thread.classinfo;
1294 static Context* sm_cbeg;
1295 static size_t sm_clen;
1297 static Thread sm_tbeg;
1298 static size_t sm_tlen;
1301 // Used for ordering threads in the global thread list.
1307 ///////////////////////////////////////////////////////////////////////////
1308 // Global Context List Operations
1309 ///////////////////////////////////////////////////////////////////////////
1313 // Add a context to the global context list.
1315 static void add( Context* c )
1319 assert( !c.next && !c.prev );
1323 synchronized( slock )
1337 // Remove a context from the global context list.
1339 static void remove( Context* c )
1343 assert( c.next || c.prev );
1347 synchronized( slock )
1350 c.prev.next = c.next;
1352 c.next.prev = c.prev;
1357 // NOTE: Don't null out c.next or c.prev because opApply currently
1358 // follows c.next after removing a node. This could be easily
1359 // addressed by simply returning the next node from this
1360 // function, however, a context should never be re-added to the
1361 // list anyway and having next and prev be non-null is a good way
1366 ///////////////////////////////////////////////////////////////////////////
1367 // Global Thread List Operations
1368 ///////////////////////////////////////////////////////////////////////////
1372 // Add a thread to the global thread list.
1374 static void add( Thread t )
1378 assert( !t.next && !t.prev );
1379 assert( t.isRunning );
1383 synchronized( slock )
1397 // Remove a thread from the global thread list.
1399 static void remove( Thread t )
1403 assert( t.next || t.prev );
1406 // NOTE: This doesn't work for Posix as m_isRunning must be set to
1407 // false after the thread is removed during normal execution.
1408 assert( !t.isRunning );
1413 synchronized( slock )
1415 // NOTE: When a thread is removed from the global thread list its
1416 // main context is invalid and should be removed as well.
1417 // It is possible that t.m_curr could reference more
1418 // than just the main context if the thread exited abnormally
1419 // (if it was terminated), but we must assume that the user
1420 // retains a reference to them and that they may be re-used
1421 // elsewhere. Therefore, it is the responsibility of any
1422 // object that creates contexts to clean them up properly
1423 // when it is done with them.
1424 remove( &t.m_main );
1427 t.prev.next = t.next;
1429 t.next.prev = t.prev;
1434 // NOTE: Don't null out t.next or t.prev because opApply currently
1435 // follows t.next after removing a node. This could be easily
1436 // addressed by simply returning the next node from this
1437 // function, however, a thread should never be re-added to the
1438 // list anyway and having next and prev be non-null is a good way
1444 ///////////////////////////////////////////////////////////////////////////////
1445 // GC Support Routines
1446 ///////////////////////////////////////////////////////////////////////////////
1450 * Initializes the thread module. This function must be called by the
1451 * garbage collector on startup and before any other thread routines
1454 extern (C) void thread_init()
1456 // NOTE: If thread_init itself performs any allocations then the thread
1457 // routines reserved for garbage collector use may be called while
1458 // thread_init is being processed. However, since no memory should
1459 // exist to be scanned at this point, it is sufficient for these
1460 // functions to detect the condition and return immediately.
1464 Thread.sm_this = TlsAlloc();
1465 assert( Thread.sm_this != TLS_OUT_OF_INDEXES );
1467 else version( Posix )
1470 sigaction_t sigusr1 = void;
1471 sigaction_t sigusr2 = void;
1473 // This is a quick way to zero-initialize the structs without using
1474 // memset or creating a link dependency on their static initializer.
1475 (cast(byte*) &sigusr1)[0 .. sigaction_t.sizeof] = 0;
1476 (cast(byte*) &sigusr2)[0 .. sigaction_t.sizeof] = 0;
1478 // NOTE: SA_RESTART indicates that system calls should restart if they
1479 // are interrupted by a signal, but this is not available on all
1480 // Posix systems, even those that support multithreading.
1481 static if( is( typeof( SA_RESTART ) ) )
1482 sigusr1.sa_flags = SA_RESTART;
1484 sigusr1.sa_flags = 0;
1485 sigusr1.sa_handler = &thread_suspendHandler;
1486 // NOTE: We want to ignore all signals while in this handler, so fill
1487 // sa_mask to indicate this.
1488 status = sigfillset( &sigusr1.sa_mask );
1489 assert( status == 0 );
1491 // NOTE: Since SIGUSR2 should only be issued for threads within the
1492 // suspend handler, we don't want this signal to trigger a
1494 sigusr2.sa_flags = 0;
1495 sigusr2.sa_handler = &thread_resumeHandler;
1496 // NOTE: We want to ignore all signals while in this handler, so fill
1497 // sa_mask to indicate this.
1498 status = sigfillset( &sigusr2.sa_mask );
1499 assert( status == 0 );
1501 status = sigaction( SIGUSR1, &sigusr1, null );
1502 assert( status == 0 );
1504 status = sigaction( SIGUSR2, &sigusr2, null );
1505 assert( status == 0 );
1507 status = sem_init( &suspendCount, 0, 0 );
1508 assert( status == 0 );
1510 status = pthread_key_create( &Thread.sm_this, null );
1511 assert( status == 0 );
1514 thread_attachThis();
1519 * Registers the calling thread for use with the D Runtime. If this routine
1520 * is called for a thread which is already registered, the result is undefined.
1522 extern (C) void thread_attachThis()
1526 Thread thisThread = new Thread();
1527 Thread.Context* thisContext = &thisThread.m_main;
1528 assert( thisContext == thisThread.m_curr );
1530 thisThread.m_addr = GetCurrentThreadId();
1531 thisThread.m_hndl = GetCurrentThreadHandle();
1532 thisContext.bstack = getStackBottom();
1533 thisContext.tstack = thisContext.bstack;
1535 thisThread.m_isDaemon = true;
1537 Thread.setThis( thisThread );
1539 else version( Posix )
1541 Thread thisThread = new Thread();
1542 Thread.Context* thisContext = thisThread.m_curr;
1543 assert( thisContext == &thisThread.m_main );
1545 thisThread.m_addr = pthread_self();
1546 thisContext.bstack = getStackBottom();
1547 thisContext.tstack = thisContext.bstack;
1549 thisThread.m_isRunning = true;
1550 thisThread.m_isDaemon = true;
1552 Thread.setThis( thisThread );
1555 Thread.add( thisThread );
1556 Thread.add( thisContext );
1561 * Deregisters the calling thread from use with the runtime. If this routine
1562 * is called for a thread which is already registered, the result is undefined.
1564 extern (C) void thread_detachThis()
1566 Thread.remove( Thread.getThis() );
1571 * Joins all non-daemon threads that are currently running. This is done by
1572 * performing successive scans through the thread list until a scan consists
1573 * of only daemon threads.
1575 extern (C) void thread_joinAll()
1580 Thread nonDaemon = null;
1582 foreach( t; Thread )
1590 if( nonDaemon is null )
1598 * Performs intermediate shutdown of the thread module.
1602 // NOTE: The functionality related to garbage collection must be minimally
1603 // operable after this dtor completes. Therefore, only minimal
1604 // cleanup may occur.
1606 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1614 // Used for needLock below
1615 private bool multiThreadedFlag = false;
1619 * This function is used to determine whether the the process is
1620 * multi-threaded. Optimizations may only be performed on this
1621 * value if the programmer can guarantee that no path from the
1622 * enclosed code will start a thread.
1625 * True if Thread.start() has been called in this process.
1627 extern (C) bool thread_needLock()
1629 return multiThreadedFlag;
1633 // Used for suspendAll/resumeAll below
1634 private uint suspendDepth = 0;
1638 * Suspend all threads but the calling thread for "stop the world" garbage
1639 * collection runs. This function may be called multiple times, and must
1640 * be followed by a matching number of calls to thread_resumeAll before
1641 * processing is resumed.
1644 * ThreadException if the suspend operation fails for a running thread.
1646 extern (C) void thread_suspendAll()
1649 * Suspend the specified thread and load stack and register information for
1650 * use by thread_scanAll. If the supplied thread is the calling thread,
1651 * stack and register information will be loaded but the thread will not
1652 * be suspended. If the suspend operation fails and the thread is not
1653 * running then it will be removed from the global thread list, otherwise
1654 * an exception will be thrown.
1657 * t = The thread to suspend.
1660 * ThreadException if the suspend operation fails for a running thread.
1662 void suspend( Thread t )
1666 if( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF )
1673 throw new ThreadException( "Unable to suspend thread" );
1676 CONTEXT context = void;
1677 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
1679 if( !GetThreadContext( t.m_hndl, &context ) )
1680 throw new ThreadException( "Unable to load thread context" );
1682 t.m_curr.tstack = cast(void*) context.Esp;
1683 // edi,esi,ebp,esp,ebx,edx,ecx,eax
1684 t.m_reg[0] = context.Edi;
1685 t.m_reg[1] = context.Esi;
1686 t.m_reg[2] = context.Ebp;
1687 t.m_reg[3] = context.Esp;
1688 t.m_reg[4] = context.Ebx;
1689 t.m_reg[5] = context.Edx;
1690 t.m_reg[6] = context.Ecx;
1691 t.m_reg[7] = context.Eax;
1693 else version( Posix )
1695 if( t.m_addr != pthread_self() )
1697 if( pthread_kill( t.m_addr, SIGUSR1 ) != 0 )
1704 throw new ThreadException( "Unable to suspend thread" );
1706 // NOTE: It's really not ideal to wait for each thread to
1707 // signal individually -- rather, it would be better to
1708 // suspend them all and wait once at the end. However,
1709 // semaphores don't really work this way, and the obvious
1710 // alternative (looping on an atomic suspend count)
1711 // requires either the atomic module (which only works on
1712 // x86) or other specialized functionality. It would
1713 // also be possible to simply loop on sem_wait at the
1714 // end, but I'm not convinced that this would be much
1715 // faster than the current approach.
1716 sem_wait( &suspendCount );
1718 else if( !t.m_lock )
1720 t.m_curr.tstack = getStackTop();
1726 // NOTE: We've got an odd chicken & egg problem here, because while the GC
1727 // is required to call thread_init before calling any other thread
1728 // routines, thread_init may allocate memory which could in turn
1729 // trigger a collection. Thus, thread_suspendAll, thread_scanAll,
1730 // and thread_resumeAll must be callable before thread_init
1731 // completes, with the assumption that no other GC memory has yet
1732 // been allocated by the system, and thus there is no risk of losing
1733 // data if the global thread list is empty. The check of
1734 // Thread.sm_tbeg below is done to ensure thread_init has completed,
1735 // and therefore that calling Thread.getThis will not result in an
1736 // error. For the short time when Thread.sm_tbeg is null, there is
1737 // no reason not to simply call the multithreaded code below, with
1738 // the expectation that the foreach loop will never be entered.
1739 if( !multiThreadedFlag && Thread.sm_tbeg )
1741 if( ++suspendDepth == 1 )
1742 suspend( Thread.getThis() );
1745 synchronized( Thread.slock )
1747 if( ++suspendDepth > 1 )
1750 // NOTE: I'd really prefer not to check isRunning within this loop but
1751 // not doing so could be problematic if threads are termianted
1752 // abnormally and a new thread is created with the same thread
1753 // address before the next GC run. This situation might cause
1754 // the same thread to be suspended twice, which would likely
1755 // cause the second suspend to fail, the garbage collection to
1756 // abort, and Bad Things to occur.
1757 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1767 // wait on semaphore -- see note in suspend for
1768 // why this is currently not implemented
1775 * Resume all threads but the calling thread for "stop the world" garbage
1776 * collection runs. This function must be called once for each preceding
1777 * call to thread_suspendAll before the threads are actually resumed.
1780 * This routine must be preceded by a call to thread_suspendAll.
1783 * ThreadException if the resume operation fails for a running thread.
1785 extern (C) void thread_resumeAll()
1788 assert( suspendDepth > 0 );
1793 * Resume the specified thread and unload stack and register information.
1794 * If the supplied thread is the calling thread, stack and register
1795 * information will be unloaded but the thread will not be resumed. If
1796 * the resume operation fails and the thread is not running then it will
1797 * be removed from the global thread list, otherwise an exception will be
1801 * t = The thread to resume.
1804 * ThreadException if the resume fails for a running thread.
1806 void resume( Thread t )
1810 if( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF )
1817 throw new ThreadException( "Unable to resume thread" );
1821 t.m_curr.tstack = t.m_curr.bstack;
1822 t.m_reg[0 .. $] = 0;
1824 else version( Posix )
1826 if( t.m_addr != pthread_self() )
1828 if( pthread_kill( t.m_addr, SIGUSR2 ) != 0 )
1835 throw new ThreadException( "Unable to resume thread" );
1838 else if( !t.m_lock )
1840 t.m_curr.tstack = t.m_curr.bstack;
1846 // NOTE: See thread_suspendAll for the logic behind this.
1847 if( !multiThreadedFlag && Thread.sm_tbeg )
1849 if( --suspendDepth == 0 )
1850 resume( Thread.getThis() );
1853 synchronized( Thread.slock )
1855 if( --suspendDepth > 0 )
1858 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1866 private alias void delegate( void*, void* ) scanAllThreadsFn;
1870 * The main entry point for garbage collection. The supplied delegate
1871 * will be passed ranges representing both stack and register values.
1874 * scan = The scanner function. It should scan from p1 through p2 - 1.
1875 * curStackTop = An optional pointer to the top of the calling thread's stack.
1878 * This routine must be preceded by a call to thread_suspendAll.
1880 extern (C) void thread_scanAll( scanAllThreadsFn scan, void* curStackTop = null )
1883 assert( suspendDepth > 0 );
1887 Thread thisThread = null;
1888 void* oldStackTop = null;
1890 if( curStackTop && Thread.sm_tbeg )
1892 thisThread = Thread.getThis();
1893 if( !thisThread.m_lock )
1895 oldStackTop = thisThread.m_curr.tstack;
1896 thisThread.m_curr.tstack = curStackTop;
1902 if( curStackTop && Thread.sm_tbeg )
1904 if( !thisThread.m_lock )
1906 thisThread.m_curr.tstack = oldStackTop;
1911 // NOTE: Synchronizing on Thread.slock is not needed because this
1912 // function may only be called after all other threads have
1913 // been suspended from within the same lock.
1914 for( Thread.Context* c = Thread.sm_cbeg; c; c = c.next )
1916 version( StackGrowsDown )
1918 // NOTE: We can't index past the bottom of the stack
1919 // so don't do the "+1" for StackGrowsDown.
1920 if( c.tstack && c.tstack < c.bstack )
1921 scan( c.tstack, c.bstack );
1925 if( c.bstack && c.bstack < c.tstack )
1926 scan( c.bstack, c.tstack + 1 );
1931 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1933 scan( &t.m_reg[0], &t.m_reg[0] + t.m_reg.length );
1939 ///////////////////////////////////////////////////////////////////////////////
1941 ///////////////////////////////////////////////////////////////////////////////
1945 * This class encapsulates the operations required to initialize, access, and
1946 * destroy thread local data.
1948 class ThreadLocal( T )
1950 ///////////////////////////////////////////////////////////////////////////
1952 ///////////////////////////////////////////////////////////////////////////
1956 * Initializes thread local storage for the indicated value which will be
1957 * initialized to def for all threads.
1960 * def = The default value to return if no value has been explicitly set.
1962 this( T def = T.init )
1965 m_key = Thread.createLocal();
1971 Thread.deleteLocal( m_key );
1975 ///////////////////////////////////////////////////////////////////////////
1977 ///////////////////////////////////////////////////////////////////////////
1981 * Gets the value last set by the calling thread, or def if no such value
1985 * The stored value or def if no value is stored.
1989 Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
1991 return wrap ? wrap.val : m_def;
1996 * Copies newval to a location specific to the calling thread, and returns
2000 * newval = The value to set.
2003 * The value passed to this function.
2007 Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
2012 Thread.setLocal( m_key, wrap );
2021 // A wrapper for the stored data. This is needed for determining whether
2022 // set has ever been called for this thread (and therefore whether the
2023 // default value should be returned) and also to flatten the differences
2024 // between data that is smaller and larger than (void*).sizeof. The
2025 // obvious tradeoff here is an extra per-thread allocation for each
2026 // ThreadLocal value as compared to calling the Thread routines directly.
2039 ///////////////////////////////////////////////////////////////////////////////
2041 ///////////////////////////////////////////////////////////////////////////////
2045 * This class is intended to simplify certain common programming techniques.
2050 * Creates and starts a new Thread object that executes fn and adds it to
2051 * the list of tracked threads.
2054 * fn = The thread function.
2057 * A reference to the newly created thread.
2059 final Thread create( void function() fn )
2061 Thread t = new Thread( fn );
2064 synchronized( this )
2073 * Creates and starts a new Thread object that executes dg and adds it to
2074 * the list of tracked threads.
2077 * dg = The thread function.
2080 * A reference to the newly created thread.
2082 final Thread create( void delegate() dg )
2084 Thread t = new Thread( dg );
2087 synchronized( this )
2096 * Add t to the list of tracked threads if it is not already being tracked.
2099 * t = The thread to add.
2102 * t must not be null.
2104 final void add( Thread t )
2111 synchronized( this )
2119 * Removes t from the list of tracked threads. No operation will be
2120 * performed if t is not currently being tracked by this object.
2123 * t = The thread to remove.
2126 * t must not be null.
2128 final void remove( Thread t )
2135 synchronized( this )
2143 * Operates on all threads currently tracked by this object.
2145 final int opApply( int delegate( inout Thread ) dg )
2147 synchronized( this )
2151 // NOTE: This loop relies on the knowledge that m_all uses the
2152 // Thread object for both the key and the mapped value.
2153 foreach( Thread t; m_all.keys )
2165 * Iteratively joins all tracked threads. This function will block add,
2166 * remove, and opApply until it completes.
2169 * rethrow = Rethrow any unhandled exception which may have caused the
2170 * current thread to terminate.
2173 * Any exception not handled by the joined threads.
2175 final void joinAll( bool rethrow = true )
2177 synchronized( this )
2179 // NOTE: This loop relies on the knowledge that m_all uses the
2180 // Thread object for both the key and the mapped value.
2181 foreach( Thread t; m_all.keys )
2190 Thread[Thread] m_all;
2194 ///////////////////////////////////////////////////////////////////////////////
2195 // Fiber Platform Detection and Memory Allocation
2196 ///////////////////////////////////////////////////////////////////////////////
2201 version( D_InlineAsm_X86 )
2210 version = AsmX86_Win32;
2211 else version( Posix )
2212 version = AsmX86_Posix;
2218 version = AsmPPC_Posix;
2224 import stdc.posix.unistd; // for sysconf
2225 import stdc.posix.sys.mman; // for mmap
2226 import stdc.posix.stdlib; // for malloc, valloc, free
2228 version( AsmX86_Win32 ) {} else
2229 version( AsmX86_Posix ) {} else
2230 version( AsmPPC_Posix ) {} else
2232 // NOTE: The ucontext implementation requires architecture specific
2233 // data definitions to operate so testing for it must be done
2234 // by checking for the existence of ucontext_t rather than by
2235 // a version identifier. Please note that this is considered
2236 // an obsolescent feature according to the POSIX spec, so a
2237 // custom solution is still preferred.
2238 import stdc.posix.ucontext;
2242 const size_t PAGESIZE;
2248 static if( is( typeof( GetSystemInfo ) ) )
2251 GetSystemInfo( &info );
2253 PAGESIZE = info.dwPageSize;
2254 assert( PAGESIZE < int.max );
2256 else static if( is( typeof( sysconf ) ) &&
2257 is( typeof( _SC_PAGESIZE ) ) )
2259 PAGESIZE = cast(size_t) sysconf( _SC_PAGESIZE );
2260 assert( PAGESIZE < int.max );
2272 ///////////////////////////////////////////////////////////////////////////////
2273 // Fiber Entry Point and Context Switch
2274 ///////////////////////////////////////////////////////////////////////////////
2279 extern (C) void fiber_entryPoint()
2281 Fiber obj = Fiber.getThis();
2284 assert( Thread.getThis().m_curr is obj.m_ctxt );
2285 volatile Thread.getThis().m_lock = false;
2286 obj.m_ctxt.tstack = obj.m_ctxt.bstack;
2287 obj.m_state = Fiber.State.EXEC;
2295 obj.m_unhandled = o;
2298 static if( is( ucontext_t ) )
2299 obj.m_ucur = &obj.m_utxt;
2301 obj.m_state = Fiber.State.TERM;
2306 // NOTE: If AsmPPC_Posix is defined then the context switch routine will
2307 // be defined externally until GDC supports inline PPC ASM.
2308 version( AsmPPC_Posix )
2309 extern (C) void fiber_switchContext( void** oldp, void* newp );
2311 extern (C) void fiber_switchContext( void** oldp, void* newp )
2313 // NOTE: The data pushed and popped in this routine must match the
2314 // default stack created by Fiber.initStack or the initial
2315 // switch into a new context will fail.
2317 version( AsmX86_Win32 )
2323 // save current stack state
2327 push dword ptr FS:[0];
2328 push dword ptr FS:[4];
2329 push dword ptr FS:[8];
2334 // store oldp again with more accurate address
2335 mov EAX, dword ptr 8[EBP];
2337 // load newp to begin context switch
2338 mov ESP, dword ptr 12[EBP];
2340 // load saved state from new stack
2344 pop dword ptr FS:[8];
2345 pop dword ptr FS:[4];
2346 pop dword ptr FS:[0];
2350 // 'return' to complete switch
2354 else version( AsmX86_Posix )
2360 // save current stack state
2368 // store oldp again with more accurate address
2369 mov EAX, dword ptr 8[EBP];
2371 // load newp to begin context switch
2372 mov ESP, dword ptr 12[EBP];
2374 // load saved state from new stack
2381 // 'return' to complete switch
2385 else static if( is( ucontext_t ) )
2387 Fiber cfib = Fiber.getThis();
2388 void* ucur = cfib.m_ucur;
2391 swapcontext( **(cast(ucontext_t***) oldp),
2392 *(cast(ucontext_t**) newp) );
2398 ///////////////////////////////////////////////////////////////////////////////
2400 ///////////////////////////////////////////////////////////////////////////////
2404 * This class provides a cooperative concurrency mechanism integrated with the
2405 * threading and garbage collection functionality. Calling a fiber may be
2406 * considered a blocking operation that returns when the fiber yields (via
2407 * Fiber.yield()). Execution occurs within the context of the calling thread
2408 * so synchronization is not necessary to guarantee memory visibility so long
2409 * as the same thread calls the fiber each time. Please note that there is no
2410 * requirement that a fiber be bound to one specific thread. Rather, fibers
2411 * may be freely passed between threads so long as they are not currently
2412 * executing. Like threads, a new fiber thread may be created using either
2413 * derivation or composition, as in the following example.
2416 * ----------------------------------------------------------------------
2418 * class DerivedFiber : Fiber
2428 * printf( "Derived fiber running.\n" );
2434 * printf( "Composed fiber running.\n" );
2436 * printf( "Composed fiber running.\n" );
2439 * // create instances of each type
2440 * Fiber derived = new DerivedFiber();
2441 * Fiber composed = new Fiber( &fiberFunc );
2443 * // call both fibers once
2446 * printf( "Execution returned to calling context.\n" );
2449 * // since each fiber has run to completion, each should have state TERM
2450 * assert( derived.state == Fiber.State.TERM );
2451 * assert( composed.state == Fiber.State.TERM );
2453 * ----------------------------------------------------------------------
2455 * Authors: Based on a design by Mikola Lysenko.
2459 ///////////////////////////////////////////////////////////////////////////
2461 ///////////////////////////////////////////////////////////////////////////
2465 * Initializes a fiber object which is associated with a static
2469 * fn = The thread function.
2470 * sz = The stack size for this fiber.
2473 * fn must not be null.
2475 this( void function() fn, size_t sz = PAGESIZE )
2484 m_state = State.HOLD;
2491 * Initializes a fiber object which is associated with a dynamic
2495 * dg = The thread function.
2496 * sz = The stack size for this fiber.
2499 * dg must not be null.
2501 this( void delegate() dg, size_t sz = PAGESIZE )
2510 m_state = State.HOLD;
2517 * Cleans up any remaining resources used by this object.
2521 // NOTE: A live reference to this object will exist on its associated
2522 // stack from the first time its call() method has been called
2523 // until its execution completes with State.TERM. Thus, the only
2524 // times this dtor should be called are either if the fiber has
2525 // terminated (and therefore has no active stack) or if the user
2526 // explicitly deletes this object. The latter case is an error
2527 // but is not easily tested for, since State.HOLD may imply that
2528 // the fiber was just created but has never been run. There is
2529 // not a compelling case to create a State.INIT just to offer a
2530 // means of ensuring the user isn't violating this object's
2531 // contract, so for now this requirement will be enforced by
2532 // documentation only.
2537 ///////////////////////////////////////////////////////////////////////////
2539 ///////////////////////////////////////////////////////////////////////////
2543 * Transfers execution to this fiber object. The calling context will be
2544 * suspended until the fiber calls Fiber.yield() or until it terminates
2545 * via an unhandled exception.
2548 * rethrow = Rethrow any unhandled exception which may have caused this
2549 * fiber to terminate.
2552 * This fiber must be in state HOLD.
2555 * Any exception not handled by the joined thread.
2558 * Any exception not handled by this fiber if rethrow = false, null
2561 final Object call( bool rethrow = true )
2564 assert( m_state == State.HOLD );
2568 Fiber cur = getThis();
2570 static if( is( ucontext_t ) )
2571 m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt;
2577 static if( is( ucontext_t ) )
2580 // NOTE: If the fiber has terminated then the stack pointers must be
2581 // reset. This ensures that the stack for this fiber is not
2582 // scanned if the fiber has terminated. This is necessary to
2583 // prevent any references lingering on the stack from delaying
2584 // the collection of otherwise dead objects. The most notable
2585 // being the current object, which is referenced at the top of
2586 // fiber_entryPoint.
2587 if( m_state == State.TERM )
2589 m_ctxt.tstack = m_ctxt.bstack;
2593 Object obj = m_unhandled;
2604 * Resets this fiber so that it may be re-used. This routine may only be
2605 * called for fibers that have terminated, as doing otherwise could result
2606 * in scope-dependent functionality that is not executed. Stack-based
2607 * classes, for example, may not be cleaned up properly if a fiber is reset
2608 * before it has terminated.
2611 * This fiber must be in state TERM.
2616 assert( m_state == State.TERM );
2617 assert( m_ctxt.tstack == m_ctxt.bstack );
2621 m_state = State.HOLD;
2627 ///////////////////////////////////////////////////////////////////////////
2628 // General Properties
2629 ///////////////////////////////////////////////////////////////////////////
2633 * A fiber may occupy one of three states: HOLD, EXEC, and TERM. The HOLD
2634 * state applies to any fiber that is suspended and ready to be called.
2635 * The EXEC state will be set for any fiber that is currently executing.
2636 * And the TERM state is set when a fiber terminates. Once a fiber
2637 * terminates, it must be reset before it may be called again.
2648 * Gets the current state of this fiber.
2651 * The state of this fiber as an enumerated value.
2659 ///////////////////////////////////////////////////////////////////////////
2660 // Actions on Calling Fiber
2661 ///////////////////////////////////////////////////////////////////////////
2665 * Forces a context switch to occur away from the calling fiber.
2669 Fiber cur = getThis();
2670 assert( cur, "Fiber.yield() called with no active fiber" );
2671 assert( cur.m_state == State.EXEC );
2673 static if( is( ucontext_t ) )
2674 cur.m_ucur = &cur.m_utxt;
2676 cur.m_state = State.HOLD;
2678 cur.m_state = State.EXEC;
2683 * Forces a context switch to occur away from the calling fiber and then
2684 * throws obj in the calling fiber.
2687 * obj = The object to throw.
2690 * obj must not be null.
2692 static void yieldAndThrow( Object obj )
2699 Fiber cur = getThis();
2700 assert( cur, "Fiber.yield() called with no active fiber" );
2701 assert( cur.m_state == State.EXEC );
2703 static if( is( ucontext_t ) )
2704 cur.m_ucur = &cur.m_utxt;
2706 cur.m_unhandled = obj;
2707 cur.m_state = State.HOLD;
2709 cur.m_state = State.EXEC;
2713 ///////////////////////////////////////////////////////////////////////////
2715 ///////////////////////////////////////////////////////////////////////////
2719 * Provides a reference to the calling fiber or null if no fiber is
2723 * The fiber object representing the calling fiber or null if no fiber
2724 * is currently active. The result of deleting this object is undefined.
2726 static Fiber getThis()
2730 return cast(Fiber) TlsGetValue( sm_this );
2732 else version( Posix )
2734 return cast(Fiber) pthread_getspecific( sm_this );
2739 ///////////////////////////////////////////////////////////////////////////
2740 // Static Initialization
2741 ///////////////////////////////////////////////////////////////////////////
2748 sm_this = TlsAlloc();
2749 assert( sm_this != TLS_OUT_OF_INDEXES );
2751 else version( Posix )
2755 status = pthread_key_create( &sm_this, null );
2756 assert( status == 0 );
2758 static if( is( ucontext_t ) )
2760 status = getcontext( &sm_utxt );
2761 assert( status == 0 );
2769 // Initializes a fiber object which has no associated executable function.
2778 // Fiber entry point. Invokes the function or delegate passed on
2779 // construction (if any).
2799 // The type of routine passed on fiber construction.
2810 // Standard fiber data
2815 void function() m_fn;
2816 void delegate() m_dg;
2824 ///////////////////////////////////////////////////////////////////////////
2826 ///////////////////////////////////////////////////////////////////////////
2830 // Allocate a new stack for this fiber.
2832 final void allocStack( size_t sz )
2835 assert( !m_pmem && !m_ctxt );
2839 // adjust alloc size to a multiple of PAGESIZE
2841 sz -= sz % PAGESIZE;
2843 // NOTE: This instance of Thread.Context is dynamic so Fiber objects
2844 // can be collected by the GC so long as no user level references
2845 // to the object exist. If m_ctxt were not dynamic then its
2846 // presence in the global context list would be enough to keep
2847 // this object alive indefinitely. An alternative to allocating
2848 // room for this struct explicitly would be to mash it into the
2849 // base of the stack being allocated below. However, doing so
2850 // requires too much special logic to be worthwhile.
2851 m_ctxt = new Thread.Context;
2853 static if( is( typeof( VirtualAlloc ) ) )
2855 // reserve memory for stack
2856 m_pmem = VirtualAlloc( null,
2862 throw new FiberException( "Unable to reserve memory for stack" );
2865 version( StackGrowsDown )
2867 void* stack = m_pmem + PAGESIZE;
2868 void* guard = m_pmem;
2869 void* pbase = stack + sz;
2873 void* stack = m_pmem;
2874 void* guard = m_pmem + sz;
2875 void* pbase = stack;
2878 // allocate reserved stack segment
2879 stack = VirtualAlloc( stack,
2885 throw new FiberException( "Unable to allocate memory for stack" );
2888 // allocate reserved guard page
2889 guard = VirtualAlloc( guard,
2892 PAGE_READWRITE | PAGE_GUARD );
2895 throw new FiberException( "Unable to create guard page for stack" );
2898 m_ctxt.bstack = pbase;
2899 m_ctxt.tstack = pbase;
2903 { static if( is( typeof( mmap ) ) )
2905 m_pmem = mmap( null,
2907 PROT_READ | PROT_WRITE,
2908 MAP_PRIVATE | MAP_ANON,
2911 if( m_pmem == MAP_FAILED )
2914 else static if( is( typeof( valloc ) ) )
2916 m_pmem = valloc( sz );
2918 else static if( is( typeof( malloc ) ) )
2920 m_pmem = malloc( sz );
2929 throw new FiberException( "Unable to allocate memory for stack" );
2932 version( StackGrowsDown )
2934 m_ctxt.bstack = m_pmem + sz;
2935 m_ctxt.tstack = m_pmem + sz;
2939 m_ctxt.bstack = m_pmem;
2940 m_ctxt.tstack = m_pmem;
2945 Thread.add( m_ctxt );
2950 // Free this fiber's stack.
2952 final void freeStack()
2955 assert( m_pmem && m_ctxt );
2959 // NOTE: Since this routine is only ever expected to be called from
2960 // the dtor, pointers to freed data are not set to null.
2962 // NOTE: m_ctxt is guaranteed to be alive because it is held in the
2963 // global context list.
2964 Thread.remove( m_ctxt );
2966 static if( is( typeof( VirtualAlloc ) ) )
2968 VirtualFree( m_pmem, 0, MEM_RELEASE );
2970 else static if( is( typeof( mmap ) ) )
2972 munmap( m_pmem, m_size );
2974 else static if( is( typeof( valloc ) ) )
2978 else static if( is( typeof( malloc ) ) )
2987 // Initialize the allocated stack.
2989 final void initStack()
2992 assert( m_ctxt.tstack && m_ctxt.tstack == m_ctxt.bstack );
2993 assert( cast(size_t) m_ctxt.bstack % (void*).sizeof == 0 );
2997 void* pstack = m_ctxt.tstack;
2998 scope( exit ) m_ctxt.tstack = pstack;
3000 void push( size_t val )
3002 version( StackGrowsDown )
3004 pstack -= size_t.sizeof;
3005 *(cast(size_t*) pstack) = val;
3009 pstack += size_t.sizeof;
3010 *(cast(size_t*) pstack) = val;
3014 // NOTE: On OS X the stack must be 16-byte aligned according to the
3018 pstack = cast(void*)(cast(uint)(pstack) - (cast(uint)(pstack) & 0x0F));
3021 version( AsmX86_Win32 )
3023 push( cast(size_t) &fiber_entryPoint ); // EIP
3024 push( 0xFFFFFFFF ); // EBP
3025 push( 0x00000000 ); // EAX
3026 push( 0xFFFFFFFF ); // FS:[0]
3027 version( StackGrowsDown )
3029 push( cast(size_t) m_ctxt.bstack ); // FS:[4]
3030 push( cast(size_t) m_ctxt.bstack - m_size ); // FS:[8]
3034 push( cast(size_t) m_ctxt.bstack ); // FS:[4]
3035 push( cast(size_t) m_ctxt.bstack + m_size ); // FS:[8]
3037 push( 0x00000000 ); // EBX
3038 push( 0x00000000 ); // ESI
3039 push( 0x00000000 ); // EDI
3041 else version( AsmX86_Posix )
3043 push( cast(size_t) &fiber_entryPoint ); // EIP
3044 push( 0x00000000 ); // EBP
3045 push( 0x00000000 ); // EAX
3046 push( 0x00000000 ); // EBX
3047 push( 0x00000000 ); // ESI
3048 push( 0x00000000 ); // EDI
3050 else version( AsmPPC_Posix )
3052 version( StackGrowsDown )
3054 pstack -= int.sizeof * 5;
3058 pstack += int.sizeof * 5;
3061 push( cast(size_t) &fiber_entryPoint ); // link register
3062 push( 0x00000000 ); // control register
3063 push( 0x00000000 ); // old stack pointer
3066 version( StackGrowsDown )
3068 pstack -= int.sizeof * 20;
3072 pstack += int.sizeof * 20;
3075 assert( cast(uint) pstack & 0x0f == 0 );
3077 else static if( is( ucontext_t ) )
3079 getcontext( &m_utxt );
3080 m_utxt.uc_stack.ss_sp = m_ctxt.bstack;
3081 m_utxt.uc_stack.ss_size = m_size;
3082 makecontext( &m_utxt, &fiber_entryPoint, 0 );
3083 // NOTE: If ucontext is being used then the top of the stack will
3084 // be a pointer to the ucontext_t struct for that fiber.
3085 push( cast(size_t) &m_utxt );
3090 Thread.Context* m_ctxt;
3094 static if( is( ucontext_t ) )
3096 // NOTE: The static ucontext instance is used to represent the context
3097 // of the main application thread.
3098 static ucontext_t sm_utxt = void;
3099 ucontext_t m_utxt = void;
3100 ucontext_t* m_ucur = null;
3105 ///////////////////////////////////////////////////////////////////////////
3106 // Storage of Active Fiber
3107 ///////////////////////////////////////////////////////////////////////////
3111 // Sets a thread-local reference to the current fiber object.
3113 static void setThis( Fiber f )
3117 TlsSetValue( sm_this, cast(void*) f );
3119 else version( Posix )
3121 pthread_setspecific( sm_this, cast(void*) f );
3126 static Thread.TLSKey sm_this;
3130 ///////////////////////////////////////////////////////////////////////////
3131 // Context Switching
3132 ///////////////////////////////////////////////////////////////////////////
3136 // Switches into the stack held by this fiber.
3138 final void switchIn()
3140 Thread tobj = Thread.getThis();
3141 void** oldp = &tobj.m_curr.tstack;
3142 void* newp = m_ctxt.tstack;
3144 // NOTE: The order of operations here is very important. The current
3145 // stack top must be stored before m_lock is set, and pushContext
3146 // must not be called until after m_lock is set. This process
3147 // is intended to prevent a race condition with the suspend
3148 // mechanism used for garbage collection. If it is not followed,
3149 // a badly timed collection could cause the GC to scan from the
3150 // bottom of one stack to the top of another, or to miss scanning
3151 // a stack that still contains valid data. The old stack pointer
3152 // oldp will be set again before the context switch to guarantee
3153 // that it points to exactly the correct stack location so the
3154 // successive pop operations will succeed.
3155 *oldp = getStackTop();
3156 volatile tobj.m_lock = true;
3157 tobj.pushContext( m_ctxt );
3159 fiber_switchContext( oldp, newp );
3161 // NOTE: As above, these operations must be performed in a strict order
3162 // to prevent Bad Things from happening.
3164 volatile tobj.m_lock = false;
3165 tobj.m_curr.tstack = tobj.m_curr.bstack;
3170 // Switches out of the current stack and into the enclosing stack.
3172 final void switchOut()
3174 Thread tobj = Thread.getThis();
3175 void** oldp = &m_ctxt.tstack;
3176 void* newp = tobj.m_curr.within.tstack;
3178 // NOTE: The order of operations here is very important. The current
3179 // stack top must be stored before m_lock is set, and pushContext
3180 // must not be called until after m_lock is set. This process
3181 // is intended to prevent a race condition with the suspend
3182 // mechanism used for garbage collection. If it is not followed,
3183 // a badly timed collection could cause the GC to scan from the
3184 // bottom of one stack to the top of another, or to miss scanning
3185 // a stack that still contains valid data. The old stack pointer
3186 // oldp will be set again before the context switch to guarantee
3187 // that it points to exactly the correct stack location so the
3188 // successive pop operations will succeed.
3189 *oldp = getStackTop();
3190 volatile tobj.m_lock = true;
3192 fiber_switchContext( oldp, newp );
3194 // NOTE: As above, these operations must be performed in a strict order
3195 // to prevent Bad Things from happening.
3196 volatile tobj.m_lock = false;
3197 tobj.m_curr.tstack = tobj.m_curr.bstack;