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 getErrno();
168 // entry point for POSIX threads
170 extern (C) void* thread_entryPoint( void* arg )
172 Thread obj = cast(Thread) arg;
176 // NOTE: isRunning should be set to false after the thread is
177 // removed or a double-removal could occur between this
178 // function and thread_suspendAll.
179 Thread.remove( obj );
180 obj.m_isRunning = false;
183 static extern (C) void thread_cleanupHandler( void* arg )
185 Thread obj = cast(Thread) arg;
188 // NOTE: If the thread terminated abnormally, just set it as
189 // not running and let thread_suspendAll remove it from
190 // the thread list. This is safer and is consistent
191 // with the Windows thread code.
192 obj.m_isRunning = false;
195 // NOTE: Using void to skip the initialization here relies on
196 // knowledge of how pthread_cleanup is implemented. It may
197 // not be appropriate for all platforms. However, it does
198 // avoid the need to link the pthread module. If any
199 // implementation actually requires default initialization
200 // then pthread_cleanup should be restructured to maintain
201 // the current lack of a link dependency.
202 pthread_cleanup cleanup = void;
203 cleanup.push( &thread_cleanupHandler, cast(void*) obj );
205 // NOTE: For some reason this does not always work for threads.
206 //obj.m_main.bstack = getStackBottom();
207 version( D_InlineAsm_X86 )
209 static void* getBasePtr()
219 obj.m_main.bstack = getBasePtr();
221 else version( StackGrowsDown )
222 obj.m_main.bstack = &obj + 1;
224 obj.m_main.bstack = &obj;
225 obj.m_main.tstack = obj.m_main.bstack;
226 assert( obj.m_curr == &obj.m_main );
227 Thread.add( &obj.m_main );
228 Thread.setThis( obj );
230 // NOTE: No GC allocations may occur until the stack pointers have
231 // been set and Thread.getThis returns a valid reference to
232 // this thread object (this latter condition is not strictly
233 // necessary on Win32 but it should be followed for the sake
236 // TODO: Consider putting an auto exception object here (using
237 // alloca) forOutOfMemoryError plus something to track
238 // whether an exception is in-flight?
253 // used to track the number of suspended threads
258 extern (C) void thread_suspendHandler( int sig )
261 assert( sig == SIGUSR1 );
265 version( D_InlineAsm_X86 )
274 __builtin_unwind_init();
278 static assert( false, "Architecture not supported." );
281 // NOTE: Since registers are being pushed and popped from the
282 // stack, any other stack data used by this function should
283 // be gone before the stack cleanup code is called below.
285 Thread obj = Thread.getThis();
287 // NOTE: The thread reference returned by getThis is set within
288 // the thread startup code, so it is possible that this
289 // handler may be called before the reference is set. In
290 // this case it is safe to simply suspend and not worry
291 // about the stack pointers as the thread will not have
292 // any references to GC-managed data.
293 if( obj && !obj.m_lock )
295 obj.m_curr.tstack = getStackTop();
298 sigset_t sigres = void;
301 status = sigfillset( &sigres );
302 assert( status == 0 );
304 status = sigdelset( &sigres, SIGUSR2 );
305 assert( status == 0 );
307 status = sem_post( &suspendCount );
308 assert( status == 0 );
310 sigsuspend( &sigres );
312 if( obj && !obj.m_lock )
314 obj.m_curr.tstack = obj.m_curr.bstack;
318 version( D_InlineAsm_X86 )
327 // registers will be popped automatically
331 static assert( false, "Architecture not supported." );
336 extern (C) void thread_resumeHandler( int sig )
339 assert( sig == SIGUSR2 );
349 // NOTE: This is the only place threading versions are checked. If a new
350 // version is added, the module code will need to be searched for
351 // places where version-specific code may be required. This can be
352 // easily accomlished by searching for 'Windows' or 'Posix'.
353 static assert( false, "Unknown threading implementation." );
357 ///////////////////////////////////////////////////////////////////////////////
359 ///////////////////////////////////////////////////////////////////////////////
363 * This class encapsulates all threading functionality for the D
364 * programming language. As thread manipulation is a required facility
365 * for garbage collection, all user threads should derive from this
366 * class, and instances of this class should never be explicitly deleted.
367 * A new thread may be created using either derivation or composition, as
368 * in the following example.
371 * ----------------------------------------------------------------------------
373 * class DerivedThread : Thread
383 * printf( "Derived thread running.\n" );
389 * printf( "Composed thread running.\n" );
392 * // create instances of each type
393 * Thread derived = new DerivedThread();
394 * Thread composed = new Thread( &threadFunc );
396 * // start both threads
400 * ----------------------------------------------------------------------------
404 ///////////////////////////////////////////////////////////////////////////
406 ///////////////////////////////////////////////////////////////////////////
410 * Initializes a thread object which is associated with a static
414 * fn = The thread function.
415 * sz = The stack size for this thread.
418 * fn must not be null.
420 this( void function() fn, size_t sz = 0 )
435 * Initializes a thread object which is associated with a dynamic
439 * dg = The thread function.
440 * sz = The stack size for this thread.
443 * dg must not be null.
445 this( void delegate() dg, size_t sz = 0 )
460 * Cleans up any remaining resources used by this object.
464 if( m_addr == m_addr.init )
471 m_addr = m_addr.init;
472 CloseHandle( m_hndl );
473 m_hndl = m_hndl.init;
475 else version( Posix )
477 pthread_detach( m_addr );
478 m_addr = m_addr.init;
483 ///////////////////////////////////////////////////////////////////////////
485 ///////////////////////////////////////////////////////////////////////////
489 * Starts the thread and invokes the function or delegate passed upon
493 * This routine may only be called once per thread instance.
496 * ThreadException if the thread fails to start.
501 assert( !next && !prev );
505 version( Win32 ) {} else
510 if( pthread_attr_init( &attr ) )
511 throw new ThreadException( "Error initializing thread attributes" );
512 if( m_sz && pthread_attr_setstacksize( &attr, m_sz ) )
513 throw new ThreadException( "Error initializing thread stack size" );
514 if( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) )
515 throw new ThreadException( "Error setting thread joinable" );
518 // NOTE: This operation needs to be synchronized to avoid a race
519 // condition with the GC. Without this lock, the thread
520 // could start and allocate memory before being added to
521 // the global thread list, preventing it from being scanned
522 // and causing memory to be collected that is still in use.
523 synchronized( slock )
527 m_hndl = cast(HANDLE) _beginthreadex( null, m_sz, &thread_entryPoint, cast(void*) this, 0, &m_addr );
528 if( cast(size_t) m_hndl == 0 )
529 throw new ThreadException( "Error creating thread" );
531 else version( Posix )
534 scope( failure ) m_isRunning = false;
536 if( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 )
537 throw new ThreadException( "Error creating thread" );
539 multiThreadedFlag = true;
546 * Waits for this thread to complete. If the thread terminated as the
547 * result of an unhandled exception, this exception will be rethrown.
550 * rethrow = Rethrow any unhandled exception which may have caused this
551 * thread to terminate.
554 * ThreadException if the operation fails.
555 * Any exception not handled by the joined thread.
558 * Any exception not handled by this thread if rethrow = false, null
561 final Object join( bool rethrow = true )
565 if( WaitForSingleObject( m_hndl, INFINITE ) != WAIT_OBJECT_0 )
566 throw new ThreadException( "Unable to join thread" );
567 // NOTE: m_addr must be cleared before m_hndl is closed to avoid
568 // a race condition with isRunning. The operation is labeled
569 // volatile to prevent compiler reordering.
570 volatile m_addr = m_addr.init;
571 CloseHandle( m_hndl );
572 m_hndl = m_hndl.init;
574 else version( Posix )
576 if( pthread_join( m_addr, null ) != 0 )
577 throw new ThreadException( "Unable to join thread" );
578 // NOTE: pthread_join acts as a substitute for pthread_detach,
579 // which is normally called by the dtor. Setting m_addr
580 // to zero ensures that pthread_detach will not be called
581 // on object destruction.
582 volatile m_addr = m_addr.init;
594 ///////////////////////////////////////////////////////////////////////////
595 // General Properties
596 ///////////////////////////////////////////////////////////////////////////
600 * Gets the user-readable label for this thread.
603 * The name of this thread.
615 * Sets the user-readable label for this thread.
618 * val = The new name of this thread.
620 final void name( char[] val )
630 * Gets the daemon status for this thread. While the runtime will wait for
631 * all normal threads to complete before tearing down the process, daemon
632 * threads are effectively ignored and thus will not prevent the process
633 * from terminating. In effect, daemon threads will be terminated
634 * automatically by the OS when the process exits.
637 * true if this is a daemon thread.
639 final bool isDaemon()
649 * Sets the daemon status for this thread. While the runtime will wait for
650 * all normal threads to complete before tearing down the process, daemon
651 * threads are effectively ignored and thus will not prevent the process
652 * from terminating. In effect, daemon threads will be terminated
653 * automatically by the OS when the process exits.
656 * val = The new daemon status for this thread.
658 final void isDaemon( bool val )
668 * Tests whether this thread is running.
671 * true if the thread is running, false if not.
673 final bool isRunning()
675 if( m_addr == m_addr.init )
683 GetExitCodeThread( m_hndl, &ecode );
684 return ecode == STILL_ACTIVE;
686 else version( Posix )
688 // NOTE: It should be safe to access this value without
689 // memory barriers because word-tearing and such
690 // really isn't an issue for boolean values.
696 ///////////////////////////////////////////////////////////////////////////
697 // Thread Priority Actions
698 ///////////////////////////////////////////////////////////////////////////
702 * The minimum scheduling priority that may be set for a thread. On
703 * systems where multiple scheduling policies are defined, this value
704 * represents the minimum valid priority for the scheduling policy of
707 static const int PRIORITY_MIN;
711 * The maximum scheduling priority that may be set for a thread. On
712 * systems where multiple scheduling policies are defined, this value
713 * represents the minimum valid priority for the scheduling policy of
716 static const int PRIORITY_MAX;
720 * Gets the scheduling priority for the associated thread.
723 * The scheduling priority of this thread.
729 return GetThreadPriority( m_hndl );
731 else version( Posix )
736 if( pthread_getschedparam( m_addr, &policy, ¶m ) )
737 throw new ThreadException( "Unable to get thread priority" );
738 return param.sched_priority;
744 * Sets the scheduling priority for the associated thread.
747 * val = The new scheduling priority of this thread.
749 final void priority( int val )
753 if( !SetThreadPriority( m_hndl, val ) )
754 throw new ThreadException( "Unable to set thread priority" );
756 else version( Posix )
758 // NOTE: pthread_setschedprio is not implemented on linux, so use
759 // the more complicated get/set sequence below.
760 //if( pthread_setschedprio( m_addr, val ) )
761 // throw new ThreadException( "Unable to set thread priority" );
766 if( pthread_getschedparam( m_addr, &policy, ¶m ) )
767 throw new ThreadException( "Unable to set thread priority" );
768 param.sched_priority = val;
769 if( pthread_setschedparam( m_addr, policy, ¶m ) )
770 throw new ThreadException( "Unable to set thread priority" );
775 ///////////////////////////////////////////////////////////////////////////
776 // Actions on Calling Thread
777 ///////////////////////////////////////////////////////////////////////////
781 * Suspends the calling thread for at least the supplied period. This may
782 * result in multiple OS calls if period is greater than the maximum sleep
783 * duration supported by the operating system.
786 * period = The minimum duration the calling thread should be suspended,
787 * in 100 nanosecond intervals.
790 * period must be non-negative.
793 * ------------------------------------------------------------------------
795 * Thread.sleep( 500 ); // sleep for 50 milliseconds
796 * Thread.sleep( 50_000_000 ); // sleep for 5 seconds
798 * ------------------------------------------------------------------------
800 static void sleep( long period )
803 assert( period >= 0 );
811 TICKS_PER_MILLI = 10_000,
812 MAX_SLEEP_MILLIS = uint.max - 1
815 period = period < TICKS_PER_MILLI ?
817 period / TICKS_PER_MILLI;
818 while( period > MAX_SLEEP_MILLIS )
820 Sleep( MAX_SLEEP_MILLIS );
821 period -= MAX_SLEEP_MILLIS;
823 Sleep( cast(uint) period );
825 else version( Posix )
828 timespec tout = void;
832 NANOS_PER_TICK = 100,
833 TICKS_PER_SECOND = 10_000_000,
835 enum : typeof(period)
837 MAX_SLEEP_TICKS = cast(typeof(period)) tin.tv_sec.max * TICKS_PER_SECOND
842 if( period > MAX_SLEEP_TICKS )
844 tin.tv_sec = tin.tv_sec.max;
849 tin.tv_sec = cast(typeof(tin.tv_sec)) (period / TICKS_PER_SECOND);
850 tin.tv_nsec = cast(typeof(tin.tv_nsec)) (period % TICKS_PER_SECOND) * NANOS_PER_TICK;
854 if( !nanosleep( &tin, &tout ) )
856 if( getErrno() != EINTR )
857 throw new ThreadException( "Unable to sleep for the specified duration" );
860 period -= (cast(typeof(period)) tin.tv_sec) * TICKS_PER_SECOND;
861 period -= (cast(typeof(period)) tin.tv_nsec) / NANOS_PER_TICK;
862 } while( period > 0 );
868 * Forces a context switch to occur away from the calling thread.
874 // NOTE: Sleep(1) is necessary because Sleep(0) does not give
875 // lower priority threads any timeslice, so looping on
876 // Sleep(0) could be resource-intensive in some cases.
879 else version( Posix )
886 ///////////////////////////////////////////////////////////////////////////
888 ///////////////////////////////////////////////////////////////////////////
892 * Provides a reference to the calling thread.
895 * The thread object representing the calling thread. The result of
896 * deleting this object is undefined.
898 static Thread getThis()
900 // NOTE: This function may not be called until thread_init has
901 // completed. See thread_suspendAll for more information
902 // on why this might occur.
905 return cast(Thread) TlsGetValue( sm_this );
907 else version( Posix )
909 return cast(Thread) pthread_getspecific( sm_this );
915 * Provides a list of all threads currently being tracked by the system.
918 * An array containing references to all threads currently being
919 * tracked by the system. The result of deleting any contained
920 * objects is undefined.
922 static Thread[] getAll()
924 synchronized( slock )
927 Thread[] buf = new Thread[sm_tlen];
929 foreach( Thread t; Thread )
939 * Operates on all threads currently being tracked by the system. The
940 * result of deleting any Thread object is undefined.
943 * dg = The supplied code as a delegate.
946 * Zero if all elemented are visited, nonzero if not.
948 static int opApply( int delegate( inout Thread ) dg )
950 synchronized( slock )
954 for( Thread t = sm_tbeg; t; t = t.next )
965 ///////////////////////////////////////////////////////////////////////////
966 // Local Storage Actions
967 ///////////////////////////////////////////////////////////////////////////
971 * Indicates the number of local storage pointers available at program
972 * startup. It is recommended that this number be at least 64.
974 static const uint LOCAL_MAX = 64;
978 * Reserves a local storage pointer for use and initializes this location
979 * to null for all running threads.
982 * A key representing the array offset of this memory location.
984 static uint createLocal()
986 synchronized( slock )
988 foreach( uint key, inout bool set; sm_local )
992 //foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
993 for( Thread t = sm_tbeg; t; t = t.next )
995 t.m_local[key] = null;
1001 throw new ThreadException( "No more local storage slots available" );
1007 * Marks the supplied key as available and sets the associated location
1008 * to null for all running threads. It is assumed that any key passed
1009 * to this function is valid. The result of calling this function for
1010 * a key which is still in use is undefined.
1013 * key = The key to delete.
1015 static void deleteLocal( uint key )
1017 synchronized( slock )
1019 sm_local[key] = false;
1020 // foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
1021 for( Thread t = sm_tbeg; t; t = t.next )
1023 t.m_local[key] = null;
1030 * Loads the value stored at key within a thread-local static array. It is
1031 * assumed that any key passed to this function is valid.
1034 * key = The location which holds the desired data.
1037 * The data associated with the supplied key.
1039 static void* getLocal( uint key )
1041 return getThis().m_local[key];
1046 * Stores the supplied value at key within a thread-local static array. It
1047 * is assumed that any key passed to this function is valid.
1050 * key = The location to store the supplied data.
1051 * val = The data to store.
1054 * A copy of the data which has just been stored.
1056 static void* setLocal( uint key, void* val )
1058 return getThis().m_local[key] = val;
1062 ///////////////////////////////////////////////////////////////////////////
1063 // Static Initalizer
1064 ///////////////////////////////////////////////////////////////////////////
1068 * This initializer is used to set thread constants. All functional
1069 * initialization occurs within thread_init().
1078 else version( Posix )
1082 pthread_t self = pthread_self();
1084 int status = pthread_getschedparam( self, &policy, ¶m );
1085 assert( status == 0 );
1087 PRIORITY_MIN = sched_get_priority_min( policy );
1088 assert( PRIORITY_MIN != -1 );
1090 PRIORITY_MAX = sched_get_priority_max( policy );
1091 assert( PRIORITY_MAX != -1 );
1098 // Initializes a thread object which has no associated executable function.
1099 // This is used for the main thread initialized in thread_init().
1109 // Thread entry point. Invokes the function or delegate passed on
1110 // construction (if any).
1130 // The type of routine passed on thread construction.
1146 alias uint ThreadAddr;
1148 else version( Posix )
1150 alias pthread_key_t TLSKey;
1151 alias pthread_t ThreadAddr;
1158 static bool[LOCAL_MAX] sm_local;
1159 static TLSKey sm_this;
1161 void*[LOCAL_MAX] m_local;
1165 // Standard thread data
1176 void function() m_fn;
1177 void delegate() m_dg;
1189 ///////////////////////////////////////////////////////////////////////////
1190 // Storage of Active Thread
1191 ///////////////////////////////////////////////////////////////////////////
1195 // Sets a thread-local reference to the current thread object.
1197 static void setThis( Thread t )
1201 TlsSetValue( sm_this, cast(void*) t );
1203 else version( Posix )
1205 pthread_setspecific( sm_this, cast(void*) t );
1211 ///////////////////////////////////////////////////////////////////////////
1212 // Thread Context and GC Scanning Support
1213 ///////////////////////////////////////////////////////////////////////////
1216 final void pushContext( Context* c )
1219 assert( !c.within );
1228 final void popContext()
1231 assert( m_curr && m_curr.within );
1235 Context* c = m_curr;
1241 final Context* topContext()
1252 static struct Context
1268 uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
1273 ///////////////////////////////////////////////////////////////////////////
1274 // GC Scanning Support
1275 ///////////////////////////////////////////////////////////////////////////
1278 // NOTE: The GC scanning process works like so:
1280 // 1. Suspend all threads.
1281 // 2. Scan the stacks of all suspended threads for roots.
1282 // 3. Resume all threads.
1284 // Step 1 and 3 require a list of all threads in the system, while
1285 // step 2 requires a list of all thread stacks (each represented by
1286 // a Context struct). Traditionally, there was one stack per thread
1287 // and the Context structs were not necessary. However, Fibers have
1288 // changed things so that each thread has its own 'main' stack plus
1289 // an arbitrary number of nested stacks (normally referenced via
1290 // m_curr). Also, there may be 'free-floating' stacks in the system,
1291 // which are Fibers that are not currently executing on any specific
1292 // thread but are still being processed and still contain valid
1295 // To support all of this, the Context struct has been created to
1296 // represent a stack range, and a global list of Context structs has
1297 // been added to enable scanning of these stack ranges. The lifetime
1298 // (and presence in the Context list) of a thread's 'main' stack will
1299 // be equivalent to the thread's lifetime. So the Ccontext will be
1300 // added to the list on thread entry, and removed from the list on
1301 // thread exit (which is essentially the same as the presence of a
1302 // Thread object in its own global list). The lifetime of a Fiber's
1303 // context, however, will be tied to the lifetime of the Fiber object
1304 // itself, and Fibers are expected to add/remove their Context struct
1305 // on construction/deletion.
1309 // All use of the global lists should synchronize on this lock.
1311 static Object slock()
1313 return Thread.classinfo;
1317 static Context* sm_cbeg;
1318 static size_t sm_clen;
1320 static Thread sm_tbeg;
1321 static size_t sm_tlen;
1324 // Used for ordering threads in the global thread list.
1330 ///////////////////////////////////////////////////////////////////////////
1331 // Global Context List Operations
1332 ///////////////////////////////////////////////////////////////////////////
1336 // Add a context to the global context list.
1338 static void add( Context* c )
1342 assert( !c.next && !c.prev );
1346 synchronized( slock )
1360 // Remove a context from the global context list.
1362 static void remove( Context* c )
1366 assert( c.next || c.prev );
1370 synchronized( slock )
1373 c.prev.next = c.next;
1375 c.next.prev = c.prev;
1380 // NOTE: Don't null out c.next or c.prev because opApply currently
1381 // follows c.next after removing a node. This could be easily
1382 // addressed by simply returning the next node from this
1383 // function, however, a context should never be re-added to the
1384 // list anyway and having next and prev be non-null is a good way
1389 ///////////////////////////////////////////////////////////////////////////
1390 // Global Thread List Operations
1391 ///////////////////////////////////////////////////////////////////////////
1395 // Add a thread to the global thread list.
1397 static void add( Thread t )
1401 assert( !t.next && !t.prev );
1402 assert( t.isRunning );
1406 synchronized( slock )
1420 // Remove a thread from the global thread list.
1422 static void remove( Thread t )
1426 assert( t.next || t.prev );
1429 // NOTE: This doesn't work for Posix as m_isRunning must be set to
1430 // false after the thread is removed during normal execution.
1431 assert( !t.isRunning );
1436 synchronized( slock )
1438 // NOTE: When a thread is removed from the global thread list its
1439 // main context is invalid and should be removed as well.
1440 // It is possible that t.m_curr could reference more
1441 // than just the main context if the thread exited abnormally
1442 // (if it was terminated), but we must assume that the user
1443 // retains a reference to them and that they may be re-used
1444 // elsewhere. Therefore, it is the responsibility of any
1445 // object that creates contexts to clean them up properly
1446 // when it is done with them.
1447 remove( &t.m_main );
1450 t.prev.next = t.next;
1452 t.next.prev = t.prev;
1457 // NOTE: Don't null out t.next or t.prev because opApply currently
1458 // follows t.next after removing a node. This could be easily
1459 // addressed by simply returning the next node from this
1460 // function, however, a thread should never be re-added to the
1461 // list anyway and having next and prev be non-null is a good way
1467 ///////////////////////////////////////////////////////////////////////////////
1468 // GC Support Routines
1469 ///////////////////////////////////////////////////////////////////////////////
1473 * Initializes the thread module. This function must be called by the
1474 * garbage collector on startup and before any other thread routines
1477 extern (C) void thread_init()
1479 // NOTE: If thread_init itself performs any allocations then the thread
1480 // routines reserved for garbage collector use may be called while
1481 // thread_init is being processed. However, since no memory should
1482 // exist to be scanned at this point, it is sufficient for these
1483 // functions to detect the condition and return immediately.
1487 Thread.sm_this = TlsAlloc();
1488 assert( Thread.sm_this != TLS_OUT_OF_INDEXES );
1490 else version( Posix )
1493 sigaction_t sigusr1 = void;
1494 sigaction_t sigusr2 = void;
1496 // This is a quick way to zero-initialize the structs without using
1497 // memset or creating a link dependency on their static initializer.
1498 (cast(byte*) &sigusr1)[0 .. sigaction_t.sizeof] = 0;
1499 (cast(byte*) &sigusr2)[0 .. sigaction_t.sizeof] = 0;
1501 // NOTE: SA_RESTART indicates that system calls should restart if they
1502 // are interrupted by a signal, but this is not available on all
1503 // Posix systems, even those that support multithreading.
1504 static if( is( typeof( SA_RESTART ) ) )
1505 sigusr1.sa_flags = SA_RESTART;
1507 sigusr1.sa_flags = 0;
1508 sigusr1.sa_handler = &thread_suspendHandler;
1509 // NOTE: We want to ignore all signals while in this handler, so fill
1510 // sa_mask to indicate this.
1511 status = sigfillset( &sigusr1.sa_mask );
1512 assert( status == 0 );
1514 // NOTE: Since SIGUSR2 should only be issued for threads within the
1515 // suspend handler, we don't want this signal to trigger a
1517 sigusr2.sa_flags = 0;
1518 sigusr2.sa_handler = &thread_resumeHandler;
1519 // NOTE: We want to ignore all signals while in this handler, so fill
1520 // sa_mask to indicate this.
1521 status = sigfillset( &sigusr2.sa_mask );
1522 assert( status == 0 );
1524 status = sigaction( SIGUSR1, &sigusr1, null );
1525 assert( status == 0 );
1527 status = sigaction( SIGUSR2, &sigusr2, null );
1528 assert( status == 0 );
1530 status = sem_init( &suspendCount, 0, 0 );
1531 assert( status == 0 );
1533 status = pthread_key_create( &Thread.sm_this, null );
1534 assert( status == 0 );
1537 thread_attachThis();
1542 * Registers the calling thread for use with the D Runtime. If this routine
1543 * is called for a thread which is already registered, the result is undefined.
1545 extern (C) void thread_attachThis()
1549 Thread thisThread = new Thread();
1550 Thread.Context* thisContext = &thisThread.m_main;
1551 assert( thisContext == thisThread.m_curr );
1553 thisThread.m_addr = GetCurrentThreadId();
1554 thisThread.m_hndl = GetCurrentThreadHandle();
1555 thisContext.bstack = getStackBottom();
1556 thisContext.tstack = thisContext.bstack;
1558 thisThread.m_isDaemon = true;
1560 Thread.setThis( thisThread );
1562 else version( Posix )
1564 Thread thisThread = new Thread();
1565 Thread.Context* thisContext = thisThread.m_curr;
1566 assert( thisContext == &thisThread.m_main );
1568 thisThread.m_addr = pthread_self();
1569 thisContext.bstack = getStackBottom();
1570 thisContext.tstack = thisContext.bstack;
1572 thisThread.m_isRunning = true;
1573 thisThread.m_isDaemon = true;
1575 Thread.setThis( thisThread );
1578 Thread.add( thisThread );
1579 Thread.add( thisContext );
1584 * Deregisters the calling thread from use with the runtime. If this routine
1585 * is called for a thread which is already registered, the result is undefined.
1587 extern (C) void thread_detachThis()
1589 Thread.remove( Thread.getThis() );
1594 * Joins all non-daemon threads that are currently running. This is done by
1595 * performing successive scans through the thread list until a scan consists
1596 * of only daemon threads.
1598 extern (C) void thread_joinAll()
1603 Thread nonDaemon = null;
1605 foreach( t; Thread )
1613 if( nonDaemon is null )
1621 * Performs intermediate shutdown of the thread module.
1625 // NOTE: The functionality related to garbage collection must be minimally
1626 // operable after this dtor completes. Therefore, only minimal
1627 // cleanup may occur.
1629 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1637 // Used for needLock below
1638 private bool multiThreadedFlag = false;
1642 * This function is used to determine whether the the process is
1643 * multi-threaded. Optimizations may only be performed on this
1644 * value if the programmer can guarantee that no path from the
1645 * enclosed code will start a thread.
1648 * True if Thread.start() has been called in this process.
1650 extern (C) bool thread_needLock()
1652 return multiThreadedFlag;
1656 // Used for suspendAll/resumeAll below
1657 private uint suspendDepth = 0;
1661 * Suspend all threads but the calling thread for "stop the world" garbage
1662 * collection runs. This function may be called multiple times, and must
1663 * be followed by a matching number of calls to thread_resumeAll before
1664 * processing is resumed.
1667 * ThreadException if the suspend operation fails for a running thread.
1669 extern (C) void thread_suspendAll()
1672 * Suspend the specified thread and load stack and register information for
1673 * use by thread_scanAll. If the supplied thread is the calling thread,
1674 * stack and register information will be loaded but the thread will not
1675 * be suspended. If the suspend operation fails and the thread is not
1676 * running then it will be removed from the global thread list, otherwise
1677 * an exception will be thrown.
1680 * t = The thread to suspend.
1683 * ThreadException if the suspend operation fails for a running thread.
1685 void suspend( Thread t )
1689 if( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF )
1696 throw new ThreadException( "Unable to suspend thread" );
1699 CONTEXT context = void;
1700 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
1702 if( !GetThreadContext( t.m_hndl, &context ) )
1703 throw new ThreadException( "Unable to load thread context" );
1705 t.m_curr.tstack = cast(void*) context.Esp;
1706 // edi,esi,ebp,esp,ebx,edx,ecx,eax
1707 t.m_reg[0] = context.Edi;
1708 t.m_reg[1] = context.Esi;
1709 t.m_reg[2] = context.Ebp;
1710 t.m_reg[3] = context.Esp;
1711 t.m_reg[4] = context.Ebx;
1712 t.m_reg[5] = context.Edx;
1713 t.m_reg[6] = context.Ecx;
1714 t.m_reg[7] = context.Eax;
1716 else version( Posix )
1718 if( t.m_addr != pthread_self() )
1720 if( pthread_kill( t.m_addr, SIGUSR1 ) != 0 )
1727 throw new ThreadException( "Unable to suspend thread" );
1729 // NOTE: It's really not ideal to wait for each thread to
1730 // signal individually -- rather, it would be better to
1731 // suspend them all and wait once at the end. However,
1732 // semaphores don't really work this way, and the obvious
1733 // alternative (looping on an atomic suspend count)
1734 // requires either the atomic module (which only works on
1735 // x86) or other specialized functionality. It would
1736 // also be possible to simply loop on sem_wait at the
1737 // end, but I'm not convinced that this would be much
1738 // faster than the current approach.
1739 sem_wait( &suspendCount );
1741 else if( !t.m_lock )
1743 t.m_curr.tstack = getStackTop();
1749 // NOTE: We've got an odd chicken & egg problem here, because while the GC
1750 // is required to call thread_init before calling any other thread
1751 // routines, thread_init may allocate memory which could in turn
1752 // trigger a collection. Thus, thread_suspendAll, thread_scanAll,
1753 // and thread_resumeAll must be callable before thread_init
1754 // completes, with the assumption that no other GC memory has yet
1755 // been allocated by the system, and thus there is no risk of losing
1756 // data if the global thread list is empty. The check of
1757 // Thread.sm_tbeg below is done to ensure thread_init has completed,
1758 // and therefore that calling Thread.getThis will not result in an
1759 // error. For the short time when Thread.sm_tbeg is null, there is
1760 // no reason not to simply call the multithreaded code below, with
1761 // the expectation that the foreach loop will never be entered.
1762 if( !multiThreadedFlag && Thread.sm_tbeg )
1764 if( ++suspendDepth == 1 )
1765 suspend( Thread.getThis() );
1768 synchronized( Thread.slock )
1770 if( ++suspendDepth > 1 )
1773 // NOTE: I'd really prefer not to check isRunning within this loop but
1774 // not doing so could be problematic if threads are termianted
1775 // abnormally and a new thread is created with the same thread
1776 // address before the next GC run. This situation might cause
1777 // the same thread to be suspended twice, which would likely
1778 // cause the second suspend to fail, the garbage collection to
1779 // abort, and Bad Things to occur.
1780 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1790 // wait on semaphore -- see note in suspend for
1791 // why this is currently not implemented
1798 * Resume all threads but the calling thread for "stop the world" garbage
1799 * collection runs. This function must be called once for each preceding
1800 * call to thread_suspendAll before the threads are actually resumed.
1803 * This routine must be preceded by a call to thread_suspendAll.
1806 * ThreadException if the resume operation fails for a running thread.
1808 extern (C) void thread_resumeAll()
1811 assert( suspendDepth > 0 );
1816 * Resume the specified thread and unload stack and register information.
1817 * If the supplied thread is the calling thread, stack and register
1818 * information will be unloaded but the thread will not be resumed. If
1819 * the resume operation fails and the thread is not running then it will
1820 * be removed from the global thread list, otherwise an exception will be
1824 * t = The thread to resume.
1827 * ThreadException if the resume fails for a running thread.
1829 void resume( Thread t )
1833 if( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF )
1840 throw new ThreadException( "Unable to resume thread" );
1844 t.m_curr.tstack = t.m_curr.bstack;
1845 t.m_reg[0 .. $] = 0;
1847 else version( Posix )
1849 if( t.m_addr != pthread_self() )
1851 if( pthread_kill( t.m_addr, SIGUSR2 ) != 0 )
1858 throw new ThreadException( "Unable to resume thread" );
1861 else if( !t.m_lock )
1863 t.m_curr.tstack = t.m_curr.bstack;
1869 // NOTE: See thread_suspendAll for the logic behind this.
1870 if( !multiThreadedFlag && Thread.sm_tbeg )
1872 if( --suspendDepth == 0 )
1873 resume( Thread.getThis() );
1876 synchronized( Thread.slock )
1878 if( --suspendDepth > 0 )
1881 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1889 private alias void delegate( void*, void* ) scanAllThreadsFn;
1893 * The main entry point for garbage collection. The supplied delegate
1894 * will be passed ranges representing both stack and register values.
1897 * scan = The scanner function. It should scan from p1 through p2 - 1.
1898 * curStackTop = An optional pointer to the top of the calling thread's stack.
1901 * This routine must be preceded by a call to thread_suspendAll.
1903 extern (C) void thread_scanAll( scanAllThreadsFn scan, void* curStackTop = null )
1906 assert( suspendDepth > 0 );
1910 Thread thisThread = null;
1911 void* oldStackTop = null;
1913 if( curStackTop && Thread.sm_tbeg )
1915 thisThread = Thread.getThis();
1916 if( !thisThread.m_lock )
1918 oldStackTop = thisThread.m_curr.tstack;
1919 thisThread.m_curr.tstack = curStackTop;
1925 if( curStackTop && Thread.sm_tbeg )
1927 if( !thisThread.m_lock )
1929 thisThread.m_curr.tstack = oldStackTop;
1934 // NOTE: Synchronizing on Thread.slock is not needed because this
1935 // function may only be called after all other threads have
1936 // been suspended from within the same lock.
1937 for( Thread.Context* c = Thread.sm_cbeg; c; c = c.next )
1939 version( StackGrowsDown )
1941 // NOTE: We can't index past the bottom of the stack
1942 // so don't do the "+1" for StackGrowsDown.
1943 if( c.tstack && c.tstack < c.bstack )
1944 scan( c.tstack, c.bstack );
1948 if( c.bstack && c.bstack < c.tstack )
1949 scan( c.bstack, c.tstack + 1 );
1954 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1956 scan( &t.m_reg[0], &t.m_reg[0] + t.m_reg.length );
1962 ///////////////////////////////////////////////////////////////////////////////
1964 ///////////////////////////////////////////////////////////////////////////////
1968 * This class encapsulates the operations required to initialize, access, and
1969 * destroy thread local data.
1971 class ThreadLocal( T )
1973 ///////////////////////////////////////////////////////////////////////////
1975 ///////////////////////////////////////////////////////////////////////////
1979 * Initializes thread local storage for the indicated value which will be
1980 * initialized to def for all threads.
1983 * def = The default value to return if no value has been explicitly set.
1985 this( T def = T.init )
1988 m_key = Thread.createLocal();
1994 Thread.deleteLocal( m_key );
1998 ///////////////////////////////////////////////////////////////////////////
2000 ///////////////////////////////////////////////////////////////////////////
2004 * Gets the value last set by the calling thread, or def if no such value
2008 * The stored value or def if no value is stored.
2012 Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
2014 return wrap ? wrap.val : m_def;
2019 * Copies newval to a location specific to the calling thread, and returns
2023 * newval = The value to set.
2026 * The value passed to this function.
2030 Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
2035 Thread.setLocal( m_key, wrap );
2044 // A wrapper for the stored data. This is needed for determining whether
2045 // set has ever been called for this thread (and therefore whether the
2046 // default value should be returned) and also to flatten the differences
2047 // between data that is smaller and larger than (void*).sizeof. The
2048 // obvious tradeoff here is an extra per-thread allocation for each
2049 // ThreadLocal value as compared to calling the Thread routines directly.
2062 ///////////////////////////////////////////////////////////////////////////////
2064 ///////////////////////////////////////////////////////////////////////////////
2068 * This class is intended to simplify certain common programming techniques.
2073 * Creates and starts a new Thread object that executes fn and adds it to
2074 * the list of tracked threads.
2077 * fn = The thread function.
2080 * A reference to the newly created thread.
2082 final Thread create( void function() fn )
2084 Thread t = new Thread( fn );
2087 synchronized( this )
2096 * Creates and starts a new Thread object that executes dg and adds it to
2097 * the list of tracked threads.
2100 * dg = The thread function.
2103 * A reference to the newly created thread.
2105 final Thread create( void delegate() dg )
2107 Thread t = new Thread( dg );
2110 synchronized( this )
2119 * Add t to the list of tracked threads if it is not already being tracked.
2122 * t = The thread to add.
2125 * t must not be null.
2127 final void add( Thread t )
2134 synchronized( this )
2142 * Removes t from the list of tracked threads. No operation will be
2143 * performed if t is not currently being tracked by this object.
2146 * t = The thread to remove.
2149 * t must not be null.
2151 final void remove( Thread t )
2158 synchronized( this )
2166 * Operates on all threads currently tracked by this object.
2168 final int opApply( int delegate( inout Thread ) dg )
2170 synchronized( this )
2174 // NOTE: This loop relies on the knowledge that m_all uses the
2175 // Thread object for both the key and the mapped value.
2176 foreach( Thread t; m_all.keys )
2188 * Iteratively joins all tracked threads. This function will block add,
2189 * remove, and opApply until it completes.
2192 * rethrow = Rethrow any unhandled exception which may have caused the
2193 * current thread to terminate.
2196 * Any exception not handled by the joined threads.
2198 final void joinAll( bool rethrow = true )
2200 synchronized( this )
2202 // NOTE: This loop relies on the knowledge that m_all uses the
2203 // Thread object for both the key and the mapped value.
2204 foreach( Thread t; m_all.keys )
2213 Thread[Thread] m_all;
2217 ///////////////////////////////////////////////////////////////////////////////
2218 // Fiber Platform Detection and Memory Allocation
2219 ///////////////////////////////////////////////////////////////////////////////
2224 version( D_InlineAsm_X86 )
2233 version = AsmX86_Win32;
2234 else version( Posix )
2235 version = AsmX86_Posix;
2241 version = AsmPPC_Posix;
2247 import stdc.posix.unistd; // for sysconf
2248 import stdc.posix.sys.mman; // for mmap
2249 import stdc.posix.stdlib; // for malloc, valloc, free
2251 version( AsmX86_Win32 ) {} else
2252 version( AsmX86_Posix ) {} else
2253 version( AsmPPC_Posix ) {} else
2255 // NOTE: The ucontext implementation requires architecture specific
2256 // data definitions to operate so testing for it must be done
2257 // by checking for the existence of ucontext_t rather than by
2258 // a version identifier. Please note that this is considered
2259 // an obsolescent feature according to the POSIX spec, so a
2260 // custom solution is still preferred.
2261 import stdc.posix.ucontext;
2265 const size_t PAGESIZE;
2271 static if( is( typeof( GetSystemInfo ) ) )
2274 GetSystemInfo( &info );
2276 PAGESIZE = info.dwPageSize;
2277 assert( PAGESIZE < int.max );
2279 else static if( is( typeof( sysconf ) ) &&
2280 is( typeof( _SC_PAGESIZE ) ) )
2282 PAGESIZE = cast(size_t) sysconf( _SC_PAGESIZE );
2283 assert( PAGESIZE < int.max );
2295 ///////////////////////////////////////////////////////////////////////////////
2296 // Fiber Entry Point and Context Switch
2297 ///////////////////////////////////////////////////////////////////////////////
2302 extern (C) void fiber_entryPoint()
2304 Fiber obj = Fiber.getThis();
2307 assert( Thread.getThis().m_curr is obj.m_ctxt );
2308 volatile Thread.getThis().m_lock = false;
2309 obj.m_ctxt.tstack = obj.m_ctxt.bstack;
2310 obj.m_state = Fiber.State.EXEC;
2318 obj.m_unhandled = o;
2321 static if( is( ucontext_t ) )
2322 obj.m_ucur = &obj.m_utxt;
2324 obj.m_state = Fiber.State.TERM;
2329 // NOTE: If AsmPPC_Posix is defined then the context switch routine will
2330 // be defined externally until GDC supports inline PPC ASM.
2331 version( AsmPPC_Posix )
2332 extern (C) void fiber_switchContext( void** oldp, void* newp );
2334 extern (C) void fiber_switchContext( void** oldp, void* newp )
2336 // NOTE: The data pushed and popped in this routine must match the
2337 // default stack created by Fiber.initStack or the initial
2338 // switch into a new context will fail.
2340 version( AsmX86_Win32 )
2346 // save current stack state
2350 push dword ptr FS:[0];
2351 push dword ptr FS:[4];
2352 push dword ptr FS:[8];
2357 // store oldp again with more accurate address
2358 mov EAX, dword ptr 8[EBP];
2360 // load newp to begin context switch
2361 mov ESP, dword ptr 12[EBP];
2363 // load saved state from new stack
2367 pop dword ptr FS:[8];
2368 pop dword ptr FS:[4];
2369 pop dword ptr FS:[0];
2373 // 'return' to complete switch
2377 else version( AsmX86_Posix )
2383 // save current stack state
2391 // store oldp again with more accurate address
2392 mov EAX, dword ptr 8[EBP];
2394 // load newp to begin context switch
2395 mov ESP, dword ptr 12[EBP];
2397 // load saved state from new stack
2404 // 'return' to complete switch
2408 else static if( is( ucontext_t ) )
2410 Fiber cfib = Fiber.getThis();
2411 void* ucur = cfib.m_ucur;
2414 swapcontext( **(cast(ucontext_t***) oldp),
2415 *(cast(ucontext_t**) newp) );
2421 ///////////////////////////////////////////////////////////////////////////////
2423 ///////////////////////////////////////////////////////////////////////////////
2427 * This class provides a cooperative concurrency mechanism integrated with the
2428 * threading and garbage collection functionality. Calling a fiber may be
2429 * considered a blocking operation that returns when the fiber yields (via
2430 * Fiber.yield()). Execution occurs within the context of the calling thread
2431 * so synchronization is not necessary to guarantee memory visibility so long
2432 * as the same thread calls the fiber each time. Please note that there is no
2433 * requirement that a fiber be bound to one specific thread. Rather, fibers
2434 * may be freely passed between threads so long as they are not currently
2435 * executing. Like threads, a new fiber thread may be created using either
2436 * derivation or composition, as in the following example.
2439 * ----------------------------------------------------------------------
2441 * class DerivedFiber : Fiber
2451 * printf( "Derived fiber running.\n" );
2457 * printf( "Composed fiber running.\n" );
2459 * printf( "Composed fiber running.\n" );
2462 * // create instances of each type
2463 * Fiber derived = new DerivedFiber();
2464 * Fiber composed = new Fiber( &fiberFunc );
2466 * // call both fibers once
2469 * printf( "Execution returned to calling context.\n" );
2472 * // since each fiber has run to completion, each should have state TERM
2473 * assert( derived.state == Fiber.State.TERM );
2474 * assert( composed.state == Fiber.State.TERM );
2476 * ----------------------------------------------------------------------
2478 * Authors: Based on a design by Mikola Lysenko.
2482 ///////////////////////////////////////////////////////////////////////////
2484 ///////////////////////////////////////////////////////////////////////////
2488 * Initializes a fiber object which is associated with a static
2492 * fn = The thread function.
2493 * sz = The stack size for this fiber.
2496 * fn must not be null.
2498 this( void function() fn, size_t sz = PAGESIZE )
2507 m_state = State.HOLD;
2514 * Initializes a fiber object which is associated with a dynamic
2518 * dg = The thread function.
2519 * sz = The stack size for this fiber.
2522 * dg must not be null.
2524 this( void delegate() dg, size_t sz = PAGESIZE )
2533 m_state = State.HOLD;
2540 * Cleans up any remaining resources used by this object.
2544 // NOTE: A live reference to this object will exist on its associated
2545 // stack from the first time its call() method has been called
2546 // until its execution completes with State.TERM. Thus, the only
2547 // times this dtor should be called are either if the fiber has
2548 // terminated (and therefore has no active stack) or if the user
2549 // explicitly deletes this object. The latter case is an error
2550 // but is not easily tested for, since State.HOLD may imply that
2551 // the fiber was just created but has never been run. There is
2552 // not a compelling case to create a State.INIT just to offer a
2553 // means of ensuring the user isn't violating this object's
2554 // contract, so for now this requirement will be enforced by
2555 // documentation only.
2560 ///////////////////////////////////////////////////////////////////////////
2562 ///////////////////////////////////////////////////////////////////////////
2566 * Transfers execution to this fiber object. The calling context will be
2567 * suspended until the fiber calls Fiber.yield() or until it terminates
2568 * via an unhandled exception.
2571 * rethrow = Rethrow any unhandled exception which may have caused this
2572 * fiber to terminate.
2575 * This fiber must be in state HOLD.
2578 * Any exception not handled by the joined thread.
2581 * Any exception not handled by this fiber if rethrow = false, null
2584 final Object call( bool rethrow = true )
2587 assert( m_state == State.HOLD );
2591 Fiber cur = getThis();
2593 static if( is( ucontext_t ) )
2594 m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt;
2600 static if( is( ucontext_t ) )
2603 // NOTE: If the fiber has terminated then the stack pointers must be
2604 // reset. This ensures that the stack for this fiber is not
2605 // scanned if the fiber has terminated. This is necessary to
2606 // prevent any references lingering on the stack from delaying
2607 // the collection of otherwise dead objects. The most notable
2608 // being the current object, which is referenced at the top of
2609 // fiber_entryPoint.
2610 if( m_state == State.TERM )
2612 m_ctxt.tstack = m_ctxt.bstack;
2616 Object obj = m_unhandled;
2627 * Resets this fiber so that it may be re-used. This routine may only be
2628 * called for fibers that have terminated, as doing otherwise could result
2629 * in scope-dependent functionality that is not executed. Stack-based
2630 * classes, for example, may not be cleaned up properly if a fiber is reset
2631 * before it has terminated.
2634 * This fiber must be in state TERM.
2639 assert( m_state == State.TERM );
2640 assert( m_ctxt.tstack == m_ctxt.bstack );
2644 m_state = State.HOLD;
2650 ///////////////////////////////////////////////////////////////////////////
2651 // General Properties
2652 ///////////////////////////////////////////////////////////////////////////
2656 * A fiber may occupy one of three states: HOLD, EXEC, and TERM. The HOLD
2657 * state applies to any fiber that is suspended and ready to be called.
2658 * The EXEC state will be set for any fiber that is currently executing.
2659 * And the TERM state is set when a fiber terminates. Once a fiber
2660 * terminates, it must be reset before it may be called again.
2671 * Gets the current state of this fiber.
2674 * The state of this fiber as an enumerated value.
2682 ///////////////////////////////////////////////////////////////////////////
2683 // Actions on Calling Fiber
2684 ///////////////////////////////////////////////////////////////////////////
2688 * Forces a context switch to occur away from the calling fiber.
2692 Fiber cur = getThis();
2693 assert( cur, "Fiber.yield() called with no active fiber" );
2694 assert( cur.m_state == State.EXEC );
2696 static if( is( ucontext_t ) )
2697 cur.m_ucur = &cur.m_utxt;
2699 cur.m_state = State.HOLD;
2701 cur.m_state = State.EXEC;
2706 * Forces a context switch to occur away from the calling fiber and then
2707 * throws obj in the calling fiber.
2710 * obj = The object to throw.
2713 * obj must not be null.
2715 static void yieldAndThrow( Object obj )
2722 Fiber cur = getThis();
2723 assert( cur, "Fiber.yield() called with no active fiber" );
2724 assert( cur.m_state == State.EXEC );
2726 static if( is( ucontext_t ) )
2727 cur.m_ucur = &cur.m_utxt;
2729 cur.m_unhandled = obj;
2730 cur.m_state = State.HOLD;
2732 cur.m_state = State.EXEC;
2736 ///////////////////////////////////////////////////////////////////////////
2738 ///////////////////////////////////////////////////////////////////////////
2742 * Provides a reference to the calling fiber or null if no fiber is
2746 * The fiber object representing the calling fiber or null if no fiber
2747 * is currently active. The result of deleting this object is undefined.
2749 static Fiber getThis()
2753 return cast(Fiber) TlsGetValue( sm_this );
2755 else version( Posix )
2757 return cast(Fiber) pthread_getspecific( sm_this );
2762 ///////////////////////////////////////////////////////////////////////////
2763 // Static Initialization
2764 ///////////////////////////////////////////////////////////////////////////
2771 sm_this = TlsAlloc();
2772 assert( sm_this != TLS_OUT_OF_INDEXES );
2774 else version( Posix )
2778 status = pthread_key_create( &sm_this, null );
2779 assert( status == 0 );
2781 static if( is( ucontext_t ) )
2783 status = getcontext( &sm_utxt );
2784 assert( status == 0 );
2792 // Initializes a fiber object which has no associated executable function.
2801 // Fiber entry point. Invokes the function or delegate passed on
2802 // construction (if any).
2822 // The type of routine passed on fiber construction.
2833 // Standard fiber data
2838 void function() m_fn;
2839 void delegate() m_dg;
2847 ///////////////////////////////////////////////////////////////////////////
2849 ///////////////////////////////////////////////////////////////////////////
2853 // Allocate a new stack for this fiber.
2855 final void allocStack( size_t sz )
2858 assert( !m_pmem && !m_ctxt );
2862 // adjust alloc size to a multiple of PAGESIZE
2864 sz -= sz % PAGESIZE;
2866 // NOTE: This instance of Thread.Context is dynamic so Fiber objects
2867 // can be collected by the GC so long as no user level references
2868 // to the object exist. If m_ctxt were not dynamic then its
2869 // presence in the global context list would be enough to keep
2870 // this object alive indefinitely. An alternative to allocating
2871 // room for this struct explicitly would be to mash it into the
2872 // base of the stack being allocated below. However, doing so
2873 // requires too much special logic to be worthwhile.
2874 m_ctxt = new Thread.Context;
2876 static if( is( typeof( VirtualAlloc ) ) )
2878 // reserve memory for stack
2879 m_pmem = VirtualAlloc( null,
2885 throw new FiberException( "Unable to reserve memory for stack" );
2888 version( StackGrowsDown )
2890 void* stack = m_pmem + PAGESIZE;
2891 void* guard = m_pmem;
2892 void* pbase = stack + sz;
2896 void* stack = m_pmem;
2897 void* guard = m_pmem + sz;
2898 void* pbase = stack;
2901 // allocate reserved stack segment
2902 stack = VirtualAlloc( stack,
2908 throw new FiberException( "Unable to allocate memory for stack" );
2911 // allocate reserved guard page
2912 guard = VirtualAlloc( guard,
2915 PAGE_READWRITE | PAGE_GUARD );
2918 throw new FiberException( "Unable to create guard page for stack" );
2921 m_ctxt.bstack = pbase;
2922 m_ctxt.tstack = pbase;
2926 { static if( is( typeof( mmap ) ) )
2928 m_pmem = mmap( null,
2930 PROT_READ | PROT_WRITE,
2931 MAP_PRIVATE | MAP_ANON,
2934 if( m_pmem == MAP_FAILED )
2937 else static if( is( typeof( valloc ) ) )
2939 m_pmem = valloc( sz );
2941 else static if( is( typeof( malloc ) ) )
2943 m_pmem = malloc( sz );
2952 throw new FiberException( "Unable to allocate memory for stack" );
2955 version( StackGrowsDown )
2957 m_ctxt.bstack = m_pmem + sz;
2958 m_ctxt.tstack = m_pmem + sz;
2962 m_ctxt.bstack = m_pmem;
2963 m_ctxt.tstack = m_pmem;
2968 Thread.add( m_ctxt );
2973 // Free this fiber's stack.
2975 final void freeStack()
2978 assert( m_pmem && m_ctxt );
2982 // NOTE: Since this routine is only ever expected to be called from
2983 // the dtor, pointers to freed data are not set to null.
2985 // NOTE: m_ctxt is guaranteed to be alive because it is held in the
2986 // global context list.
2987 Thread.remove( m_ctxt );
2989 static if( is( typeof( VirtualAlloc ) ) )
2991 VirtualFree( m_pmem, 0, MEM_RELEASE );
2993 else static if( is( typeof( mmap ) ) )
2995 munmap( m_pmem, m_size );
2997 else static if( is( typeof( valloc ) ) )
3001 else static if( is( typeof( malloc ) ) )
3010 // Initialize the allocated stack.
3012 final void initStack()
3015 assert( m_ctxt.tstack && m_ctxt.tstack == m_ctxt.bstack );
3016 assert( cast(size_t) m_ctxt.bstack % (void*).sizeof == 0 );
3020 void* pstack = m_ctxt.tstack;
3021 scope( exit ) m_ctxt.tstack = pstack;
3023 void push( size_t val )
3025 version( StackGrowsDown )
3027 pstack -= size_t.sizeof;
3028 *(cast(size_t*) pstack) = val;
3032 pstack += size_t.sizeof;
3033 *(cast(size_t*) pstack) = val;
3037 // NOTE: On OS X the stack must be 16-byte aligned according to the
3041 pstack = cast(void*)(cast(uint)(pstack) - (cast(uint)(pstack) & 0x0F));
3044 version( AsmX86_Win32 )
3046 push( cast(size_t) &fiber_entryPoint ); // EIP
3047 push( 0xFFFFFFFF ); // EBP
3048 push( 0x00000000 ); // EAX
3049 push( 0xFFFFFFFF ); // FS:[0]
3050 version( StackGrowsDown )
3052 push( cast(size_t) m_ctxt.bstack ); // FS:[4]
3053 push( cast(size_t) m_ctxt.bstack - m_size ); // FS:[8]
3057 push( cast(size_t) m_ctxt.bstack ); // FS:[4]
3058 push( cast(size_t) m_ctxt.bstack + m_size ); // FS:[8]
3060 push( 0x00000000 ); // EBX
3061 push( 0x00000000 ); // ESI
3062 push( 0x00000000 ); // EDI
3064 else version( AsmX86_Posix )
3066 push( cast(size_t) &fiber_entryPoint ); // EIP
3067 push( 0x00000000 ); // EBP
3068 push( 0x00000000 ); // EAX
3069 push( 0x00000000 ); // EBX
3070 push( 0x00000000 ); // ESI
3071 push( 0x00000000 ); // EDI
3073 else version( AsmPPC_Posix )
3075 version( StackGrowsDown )
3077 pstack -= int.sizeof * 5;
3081 pstack += int.sizeof * 5;
3084 push( cast(size_t) &fiber_entryPoint ); // link register
3085 push( 0x00000000 ); // control register
3086 push( 0x00000000 ); // old stack pointer
3089 version( StackGrowsDown )
3091 pstack -= int.sizeof * 20;
3095 pstack += int.sizeof * 20;
3098 assert( cast(uint) pstack & 0x0f == 0 );
3100 else static if( is( ucontext_t ) )
3102 getcontext( &m_utxt );
3103 m_utxt.uc_stack.ss_sp = m_ctxt.bstack;
3104 m_utxt.uc_stack.ss_size = m_size;
3105 makecontext( &m_utxt, &fiber_entryPoint, 0 );
3106 // NOTE: If ucontext is being used then the top of the stack will
3107 // be a pointer to the ucontext_t struct for that fiber.
3108 push( cast(size_t) &m_utxt );
3113 Thread.Context* m_ctxt;
3117 static if( is( ucontext_t ) )
3119 // NOTE: The static ucontext instance is used to represent the context
3120 // of the main application thread.
3121 static ucontext_t sm_utxt = void;
3122 ucontext_t m_utxt = void;
3123 ucontext_t* m_ucur = null;
3128 ///////////////////////////////////////////////////////////////////////////
3129 // Storage of Active Fiber
3130 ///////////////////////////////////////////////////////////////////////////
3134 // Sets a thread-local reference to the current fiber object.
3136 static void setThis( Fiber f )
3140 TlsSetValue( sm_this, cast(void*) f );
3142 else version( Posix )
3144 pthread_setspecific( sm_this, cast(void*) f );
3149 static Thread.TLSKey sm_this;
3153 ///////////////////////////////////////////////////////////////////////////
3154 // Context Switching
3155 ///////////////////////////////////////////////////////////////////////////
3159 // Switches into the stack held by this fiber.
3161 final void switchIn()
3163 Thread tobj = Thread.getThis();
3164 void** oldp = &tobj.m_curr.tstack;
3165 void* newp = m_ctxt.tstack;
3167 // NOTE: The order of operations here is very important. The current
3168 // stack top must be stored before m_lock is set, and pushContext
3169 // must not be called until after m_lock is set. This process
3170 // is intended to prevent a race condition with the suspend
3171 // mechanism used for garbage collection. If it is not followed,
3172 // a badly timed collection could cause the GC to scan from the
3173 // bottom of one stack to the top of another, or to miss scanning
3174 // a stack that still contains valid data. The old stack pointer
3175 // oldp will be set again before the context switch to guarantee
3176 // that it points to exactly the correct stack location so the
3177 // successive pop operations will succeed.
3178 *oldp = getStackTop();
3179 volatile tobj.m_lock = true;
3180 tobj.pushContext( m_ctxt );
3182 fiber_switchContext( oldp, newp );
3184 // NOTE: As above, these operations must be performed in a strict order
3185 // to prevent Bad Things from happening.
3187 volatile tobj.m_lock = false;
3188 tobj.m_curr.tstack = tobj.m_curr.bstack;
3193 // Switches out of the current stack and into the enclosing stack.
3195 final void switchOut()
3197 Thread tobj = Thread.getThis();
3198 void** oldp = &m_ctxt.tstack;
3199 void* newp = tobj.m_curr.within.tstack;
3201 // NOTE: The order of operations here is very important. The current
3202 // stack top must be stored before m_lock is set, and pushContext
3203 // must not be called until after m_lock is set. This process
3204 // is intended to prevent a race condition with the suspend
3205 // mechanism used for garbage collection. If it is not followed,
3206 // a badly timed collection could cause the GC to scan from the
3207 // bottom of one stack to the top of another, or to miss scanning
3208 // a stack that still contains valid data. The old stack pointer
3209 // oldp will be set again before the context switch to guarantee
3210 // that it points to exactly the correct stack location so the
3211 // successive pop operations will succeed.
3212 *oldp = getStackTop();
3213 volatile tobj.m_lock = true;
3215 fiber_switchContext( oldp, newp );
3217 // NOTE: As above, these operations must be performed in a strict order
3218 // to prevent Bad Things from happening.
3219 volatile tobj.m_lock = false;
3220 tobj.m_curr.tstack = tobj.m_curr.bstack;