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 core.stdc.stdint : uintptr_t; // for _beginthreadex decl below
88 import core.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 core.sys.posix.semaphore;
155 import core.sys.posix.pthread;
156 import core.sys.posix.signal;
157 import core.sys.posix.time;
158 import core.stdc.errno;
160 extern (C) int getErrno();
169 // entry point for POSIX threads
171 extern (C) void* thread_entryPoint( void* arg )
173 Thread obj = cast(Thread) arg;
177 // NOTE: isRunning should be set to false after the thread is
178 // removed or a double-removal could occur between this
179 // function and thread_suspendAll.
180 Thread.remove( obj );
181 obj.m_isRunning = false;
184 static extern (C) void thread_cleanupHandler( void* arg )
186 Thread obj = cast(Thread) arg;
189 // NOTE: If the thread terminated abnormally, just set it as
190 // not running and let thread_suspendAll remove it from
191 // the thread list. This is safer and is consistent
192 // with the Windows thread code.
193 obj.m_isRunning = false;
196 // NOTE: Using void to skip the initialization here relies on
197 // knowledge of how pthread_cleanup is implemented. It may
198 // not be appropriate for all platforms. However, it does
199 // avoid the need to link the pthread module. If any
200 // implementation actually requires default initialization
201 // then pthread_cleanup should be restructured to maintain
202 // the current lack of a link dependency.
205 pthread_cleanup cleanup = void;
206 cleanup.push( &thread_cleanupHandler, cast(void*) obj );
208 else version( darwin )
210 pthread_cleanup cleanup = void;
211 cleanup.push( &thread_cleanupHandler, cast(void*) obj );
215 pthread_cleanup_push( &thread_cleanupHandler, cast(void*) obj );
218 // NOTE: For some reason this does not always work for threads.
219 //obj.m_main.bstack = getStackBottom();
220 version( D_InlineAsm_X86 )
222 static void* getBasePtr()
232 obj.m_main.bstack = getBasePtr();
234 else version( StackGrowsDown )
235 obj.m_main.bstack = &obj + 1;
237 obj.m_main.bstack = &obj;
238 obj.m_main.tstack = obj.m_main.bstack;
239 assert( obj.m_curr == &obj.m_main );
240 Thread.add( &obj.m_main );
241 Thread.setThis( obj );
243 // NOTE: No GC allocations may occur until the stack pointers have
244 // been set and Thread.getThis returns a valid reference to
245 // this thread object (this latter condition is not strictly
246 // necessary on Win32 but it should be followed for the sake
249 // TODO: Consider putting an auto exception object here (using
250 // alloca) forOutOfMemoryError plus something to track
251 // whether an exception is in-flight?
266 // used to track the number of suspended threads
271 extern (C) void thread_suspendHandler( int sig )
274 assert( sig == SIGUSR1 );
278 version( D_InlineAsm_X86 )
287 __builtin_unwind_init();
291 static assert( false, "Architecture not supported." );
294 // NOTE: Since registers are being pushed and popped from the
295 // stack, any other stack data used by this function should
296 // be gone before the stack cleanup code is called below.
298 Thread obj = Thread.getThis();
300 // NOTE: The thread reference returned by getThis is set within
301 // the thread startup code, so it is possible that this
302 // handler may be called before the reference is set. In
303 // this case it is safe to simply suspend and not worry
304 // about the stack pointers as the thread will not have
305 // any references to GC-managed data.
306 if( obj && !obj.m_lock )
308 obj.m_curr.tstack = getStackTop();
311 sigset_t sigres = void;
314 status = sigfillset( &sigres );
315 assert( status == 0 );
317 status = sigdelset( &sigres, SIGUSR2 );
318 assert( status == 0 );
320 status = sem_post( &suspendCount );
321 assert( status == 0 );
323 sigsuspend( &sigres );
325 if( obj && !obj.m_lock )
327 obj.m_curr.tstack = obj.m_curr.bstack;
331 version( D_InlineAsm_X86 )
340 // registers will be popped automatically
344 static assert( false, "Architecture not supported." );
349 extern (C) void thread_resumeHandler( int sig )
352 assert( sig == SIGUSR2 );
362 // NOTE: This is the only place threading versions are checked. If a new
363 // version is added, the module code will need to be searched for
364 // places where version-specific code may be required. This can be
365 // easily accomlished by searching for 'Windows' or 'Posix'.
366 static assert( false, "Unknown threading implementation." );
370 ///////////////////////////////////////////////////////////////////////////////
372 ///////////////////////////////////////////////////////////////////////////////
376 * This class encapsulates all threading functionality for the D
377 * programming language. As thread manipulation is a required facility
378 * for garbage collection, all user threads should derive from this
379 * class, and instances of this class should never be explicitly deleted.
380 * A new thread may be created using either derivation or composition, as
381 * in the following example.
384 * ----------------------------------------------------------------------------
386 * class DerivedThread : Thread
396 * printf( "Derived thread running.\n" );
402 * printf( "Composed thread running.\n" );
405 * // create instances of each type
406 * Thread derived = new DerivedThread();
407 * Thread composed = new Thread( &threadFunc );
409 * // start both threads
413 * ----------------------------------------------------------------------------
417 ///////////////////////////////////////////////////////////////////////////
419 ///////////////////////////////////////////////////////////////////////////
423 * Initializes a thread object which is associated with a static
427 * fn = The thread function.
428 * sz = The stack size for this thread.
431 * fn must not be null.
433 this( void function() fn, size_t sz = 0 )
448 * Initializes a thread object which is associated with a dynamic
452 * dg = The thread function.
453 * sz = The stack size for this thread.
456 * dg must not be null.
458 this( void delegate() dg, size_t sz = 0 )
473 * Cleans up any remaining resources used by this object.
477 if( m_addr == m_addr.init )
484 m_addr = m_addr.init;
485 CloseHandle( m_hndl );
486 m_hndl = m_hndl.init;
488 else version( Posix )
490 pthread_detach( m_addr );
491 m_addr = m_addr.init;
496 ///////////////////////////////////////////////////////////////////////////
498 ///////////////////////////////////////////////////////////////////////////
502 * Starts the thread and invokes the function or delegate passed upon
506 * This routine may only be called once per thread instance.
509 * ThreadException if the thread fails to start.
514 assert( !next && !prev );
518 version( Win32 ) {} else
523 if( pthread_attr_init( &attr ) )
524 throw new ThreadException( "Error initializing thread attributes" );
525 if( m_sz && pthread_attr_setstacksize( &attr, m_sz ) )
526 throw new ThreadException( "Error initializing thread stack size" );
527 if( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) )
528 throw new ThreadException( "Error setting thread joinable" );
531 // NOTE: This operation needs to be synchronized to avoid a race
532 // condition with the GC. Without this lock, the thread
533 // could start and allocate memory before being added to
534 // the global thread list, preventing it from being scanned
535 // and causing memory to be collected that is still in use.
536 synchronized( slock )
540 m_hndl = cast(HANDLE) _beginthreadex( null, m_sz, &thread_entryPoint, cast(void*) this, 0, &m_addr );
541 if( cast(size_t) m_hndl == 0 )
542 throw new ThreadException( "Error creating thread" );
544 else version( Posix )
547 scope( failure ) m_isRunning = false;
549 if( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 )
550 throw new ThreadException( "Error creating thread" );
552 multiThreadedFlag = true;
559 * Waits for this thread to complete. If the thread terminated as the
560 * result of an unhandled exception, this exception will be rethrown.
563 * rethrow = Rethrow any unhandled exception which may have caused this
564 * thread to terminate.
567 * ThreadException if the operation fails.
568 * Any exception not handled by the joined thread.
571 * Any exception not handled by this thread if rethrow = false, null
574 final Object join( bool rethrow = true )
578 if( WaitForSingleObject( m_hndl, INFINITE ) != WAIT_OBJECT_0 )
579 throw new ThreadException( "Unable to join thread" );
580 // NOTE: m_addr must be cleared before m_hndl is closed to avoid
581 // a race condition with isRunning. The operation is labeled
582 // volatile to prevent compiler reordering.
583 volatile m_addr = m_addr.init;
584 CloseHandle( m_hndl );
585 m_hndl = m_hndl.init;
587 else version( Posix )
589 if( pthread_join( m_addr, null ) != 0 )
590 throw new ThreadException( "Unable to join thread" );
591 // NOTE: pthread_join acts as a substitute for pthread_detach,
592 // which is normally called by the dtor. Setting m_addr
593 // to zero ensures that pthread_detach will not be called
594 // on object destruction.
595 volatile m_addr = m_addr.init;
607 ///////////////////////////////////////////////////////////////////////////
608 // General Properties
609 ///////////////////////////////////////////////////////////////////////////
613 * Gets the user-readable label for this thread.
616 * The name of this thread.
628 * Sets the user-readable label for this thread.
631 * val = The new name of this thread.
633 final void name( char[] val )
643 * Gets the daemon status for this thread. While the runtime will wait for
644 * all normal threads to complete before tearing down the process, daemon
645 * threads are effectively ignored and thus will not prevent the process
646 * from terminating. In effect, daemon threads will be terminated
647 * automatically by the OS when the process exits.
650 * true if this is a daemon thread.
652 final bool isDaemon()
662 * Sets the daemon status for this thread. While the runtime will wait for
663 * all normal threads to complete before tearing down the process, daemon
664 * threads are effectively ignored and thus will not prevent the process
665 * from terminating. In effect, daemon threads will be terminated
666 * automatically by the OS when the process exits.
669 * val = The new daemon status for this thread.
671 final void isDaemon( bool val )
681 * Tests whether this thread is running.
684 * true if the thread is running, false if not.
686 final bool isRunning()
688 if( m_addr == m_addr.init )
696 GetExitCodeThread( m_hndl, &ecode );
697 return ecode == STILL_ACTIVE;
699 else version( Posix )
701 // NOTE: It should be safe to access this value without
702 // memory barriers because word-tearing and such
703 // really isn't an issue for boolean values.
709 ///////////////////////////////////////////////////////////////////////////
710 // Thread Priority Actions
711 ///////////////////////////////////////////////////////////////////////////
715 * The minimum scheduling priority that may be set for a thread. On
716 * systems where multiple scheduling policies are defined, this value
717 * represents the minimum valid priority for the scheduling policy of
720 static const int PRIORITY_MIN;
724 * The maximum scheduling priority that may be set for a thread. On
725 * systems where multiple scheduling policies are defined, this value
726 * represents the minimum valid priority for the scheduling policy of
729 static const int PRIORITY_MAX;
733 * Gets the scheduling priority for the associated thread.
736 * The scheduling priority of this thread.
742 return GetThreadPriority( m_hndl );
744 else version( Posix )
749 if( pthread_getschedparam( m_addr, &policy, ¶m ) )
750 throw new ThreadException( "Unable to get thread priority" );
751 return param.sched_priority;
757 * Sets the scheduling priority for the associated thread.
760 * val = The new scheduling priority of this thread.
762 final void priority( int val )
766 if( !SetThreadPriority( m_hndl, val ) )
767 throw new ThreadException( "Unable to set thread priority" );
769 else version( Posix )
771 // NOTE: pthread_setschedprio is not implemented on linux, so use
772 // the more complicated get/set sequence below.
773 //if( pthread_setschedprio( m_addr, val ) )
774 // throw new ThreadException( "Unable to set thread priority" );
779 if( pthread_getschedparam( m_addr, &policy, ¶m ) )
780 throw new ThreadException( "Unable to set thread priority" );
781 param.sched_priority = val;
782 if( pthread_setschedparam( m_addr, policy, ¶m ) )
783 throw new ThreadException( "Unable to set thread priority" );
788 ///////////////////////////////////////////////////////////////////////////
789 // Actions on Calling Thread
790 ///////////////////////////////////////////////////////////////////////////
794 * Suspends the calling thread for at least the supplied period. This may
795 * result in multiple OS calls if period is greater than the maximum sleep
796 * duration supported by the operating system.
799 * period = The minimum duration the calling thread should be suspended,
800 * in 100 nanosecond intervals.
803 * period must be non-negative.
806 * ------------------------------------------------------------------------
808 * Thread.sleep( 500 ); // sleep for 50 milliseconds
809 * Thread.sleep( 50_000_000 ); // sleep for 5 seconds
811 * ------------------------------------------------------------------------
813 static void sleep( long period )
816 assert( period >= 0 );
824 TICKS_PER_MILLI = 10_000,
825 MAX_SLEEP_MILLIS = uint.max - 1
828 period = period < TICKS_PER_MILLI ?
830 period / TICKS_PER_MILLI;
831 while( period > MAX_SLEEP_MILLIS )
833 Sleep( MAX_SLEEP_MILLIS );
834 period -= MAX_SLEEP_MILLIS;
836 Sleep( cast(uint) period );
838 else version( Posix )
841 timespec tout = void;
845 NANOS_PER_TICK = 100,
846 TICKS_PER_SECOND = 10_000_000,
848 enum : typeof(period)
850 MAX_SLEEP_TICKS = cast(typeof(period)) tin.tv_sec.max * TICKS_PER_SECOND
855 if( period > MAX_SLEEP_TICKS )
857 tin.tv_sec = tin.tv_sec.max;
862 tin.tv_sec = cast(typeof(tin.tv_sec)) (period / TICKS_PER_SECOND);
863 tin.tv_nsec = cast(typeof(tin.tv_nsec)) (period % TICKS_PER_SECOND) * NANOS_PER_TICK;
867 if( !nanosleep( &tin, &tout ) )
869 if( getErrno() != EINTR )
870 throw new ThreadException( "Unable to sleep for the specified duration" );
873 period -= (cast(typeof(period)) tin.tv_sec) * TICKS_PER_SECOND;
874 period -= (cast(typeof(period)) tin.tv_nsec) / NANOS_PER_TICK;
875 } while( period > 0 );
881 * Forces a context switch to occur away from the calling thread.
887 // NOTE: Sleep(1) is necessary because Sleep(0) does not give
888 // lower priority threads any timeslice, so looping on
889 // Sleep(0) could be resource-intensive in some cases.
892 else version( Posix )
899 ///////////////////////////////////////////////////////////////////////////
901 ///////////////////////////////////////////////////////////////////////////
905 * Provides a reference to the calling thread.
908 * The thread object representing the calling thread. The result of
909 * deleting this object is undefined.
911 static Thread getThis()
913 // NOTE: This function may not be called until thread_init has
914 // completed. See thread_suspendAll for more information
915 // on why this might occur.
918 return cast(Thread) TlsGetValue( sm_this );
920 else version( Posix )
922 return cast(Thread) pthread_getspecific( sm_this );
928 * Provides a list of all threads currently being tracked by the system.
931 * An array containing references to all threads currently being
932 * tracked by the system. The result of deleting any contained
933 * objects is undefined.
935 static Thread[] getAll()
937 synchronized( slock )
940 Thread[] buf = new Thread[sm_tlen];
942 foreach( Thread t; Thread )
952 * Operates on all threads currently being tracked by the system. The
953 * result of deleting any Thread object is undefined.
956 * dg = The supplied code as a delegate.
959 * Zero if all elemented are visited, nonzero if not.
961 static int opApply( int delegate( inout Thread ) dg )
963 synchronized( slock )
967 for( Thread t = sm_tbeg; t; t = t.next )
978 ///////////////////////////////////////////////////////////////////////////
979 // Local Storage Actions
980 ///////////////////////////////////////////////////////////////////////////
984 * Indicates the number of local storage pointers available at program
985 * startup. It is recommended that this number be at least 64.
987 static const uint LOCAL_MAX = 64;
991 * Reserves a local storage pointer for use and initializes this location
992 * to null for all running threads.
995 * A key representing the array offset of this memory location.
997 static uint createLocal()
999 synchronized( slock )
1001 foreach( uint key, inout bool set; sm_local )
1005 //foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
1006 for( Thread t = sm_tbeg; t; t = t.next )
1008 t.m_local[key] = null;
1014 throw new ThreadException( "No more local storage slots available" );
1020 * Marks the supplied key as available and sets the associated location
1021 * to null for all running threads. It is assumed that any key passed
1022 * to this function is valid. The result of calling this function for
1023 * a key which is still in use is undefined.
1026 * key = The key to delete.
1028 static void deleteLocal( uint key )
1030 synchronized( slock )
1032 sm_local[key] = false;
1033 // foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
1034 for( Thread t = sm_tbeg; t; t = t.next )
1036 t.m_local[key] = null;
1043 * Loads the value stored at key within a thread-local static array. It is
1044 * assumed that any key passed to this function is valid.
1047 * key = The location which holds the desired data.
1050 * The data associated with the supplied key.
1052 static void* getLocal( uint key )
1054 return getThis().m_local[key];
1059 * Stores the supplied value at key within a thread-local static array. It
1060 * is assumed that any key passed to this function is valid.
1063 * key = The location to store the supplied data.
1064 * val = The data to store.
1067 * A copy of the data which has just been stored.
1069 static void* setLocal( uint key, void* val )
1071 return getThis().m_local[key] = val;
1075 ///////////////////////////////////////////////////////////////////////////
1076 // Static Initalizer
1077 ///////////////////////////////////////////////////////////////////////////
1081 * This initializer is used to set thread constants. All functional
1082 * initialization occurs within thread_init().
1091 else version( Posix )
1095 pthread_t self = pthread_self();
1097 int status = pthread_getschedparam( self, &policy, ¶m );
1098 assert( status == 0 );
1100 PRIORITY_MIN = sched_get_priority_min( policy );
1101 assert( PRIORITY_MIN != -1 );
1103 PRIORITY_MAX = sched_get_priority_max( policy );
1104 assert( PRIORITY_MAX != -1 );
1111 // Initializes a thread object which has no associated executable function.
1112 // This is used for the main thread initialized in thread_init().
1122 // Thread entry point. Invokes the function or delegate passed on
1123 // construction (if any).
1143 // The type of routine passed on thread construction.
1159 alias uint ThreadAddr;
1161 else version( Posix )
1163 alias pthread_key_t TLSKey;
1164 alias pthread_t ThreadAddr;
1171 static bool[LOCAL_MAX] sm_local;
1172 static TLSKey sm_this;
1174 void*[LOCAL_MAX] m_local;
1178 // Standard thread data
1189 void function() m_fn;
1190 void delegate() m_dg;
1202 ///////////////////////////////////////////////////////////////////////////
1203 // Storage of Active Thread
1204 ///////////////////////////////////////////////////////////////////////////
1208 // Sets a thread-local reference to the current thread object.
1210 static void setThis( Thread t )
1214 TlsSetValue( sm_this, cast(void*) t );
1216 else version( Posix )
1218 pthread_setspecific( sm_this, cast(void*) t );
1224 ///////////////////////////////////////////////////////////////////////////
1225 // Thread Context and GC Scanning Support
1226 ///////////////////////////////////////////////////////////////////////////
1229 final void pushContext( Context* c )
1232 assert( !c.within );
1241 final void popContext()
1244 assert( m_curr && m_curr.within );
1248 Context* c = m_curr;
1254 final Context* topContext()
1265 static struct Context
1281 uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
1286 ///////////////////////////////////////////////////////////////////////////
1287 // GC Scanning Support
1288 ///////////////////////////////////////////////////////////////////////////
1291 // NOTE: The GC scanning process works like so:
1293 // 1. Suspend all threads.
1294 // 2. Scan the stacks of all suspended threads for roots.
1295 // 3. Resume all threads.
1297 // Step 1 and 3 require a list of all threads in the system, while
1298 // step 2 requires a list of all thread stacks (each represented by
1299 // a Context struct). Traditionally, there was one stack per thread
1300 // and the Context structs were not necessary. However, Fibers have
1301 // changed things so that each thread has its own 'main' stack plus
1302 // an arbitrary number of nested stacks (normally referenced via
1303 // m_curr). Also, there may be 'free-floating' stacks in the system,
1304 // which are Fibers that are not currently executing on any specific
1305 // thread but are still being processed and still contain valid
1308 // To support all of this, the Context struct has been created to
1309 // represent a stack range, and a global list of Context structs has
1310 // been added to enable scanning of these stack ranges. The lifetime
1311 // (and presence in the Context list) of a thread's 'main' stack will
1312 // be equivalent to the thread's lifetime. So the Ccontext will be
1313 // added to the list on thread entry, and removed from the list on
1314 // thread exit (which is essentially the same as the presence of a
1315 // Thread object in its own global list). The lifetime of a Fiber's
1316 // context, however, will be tied to the lifetime of the Fiber object
1317 // itself, and Fibers are expected to add/remove their Context struct
1318 // on construction/deletion.
1322 // All use of the global lists should synchronize on this lock.
1324 static Object slock()
1326 return Thread.classinfo;
1330 static Context* sm_cbeg;
1331 static size_t sm_clen;
1333 static Thread sm_tbeg;
1334 static size_t sm_tlen;
1337 // Used for ordering threads in the global thread list.
1343 ///////////////////////////////////////////////////////////////////////////
1344 // Global Context List Operations
1345 ///////////////////////////////////////////////////////////////////////////
1349 // Add a context to the global context list.
1351 static void add( Context* c )
1355 assert( !c.next && !c.prev );
1359 synchronized( slock )
1373 // Remove a context from the global context list.
1375 static void remove( Context* c )
1379 assert( c.next || c.prev );
1383 synchronized( slock )
1386 c.prev.next = c.next;
1388 c.next.prev = c.prev;
1393 // NOTE: Don't null out c.next or c.prev because opApply currently
1394 // follows c.next after removing a node. This could be easily
1395 // addressed by simply returning the next node from this
1396 // function, however, a context should never be re-added to the
1397 // list anyway and having next and prev be non-null is a good way
1402 ///////////////////////////////////////////////////////////////////////////
1403 // Global Thread List Operations
1404 ///////////////////////////////////////////////////////////////////////////
1408 // Add a thread to the global thread list.
1410 static void add( Thread t )
1414 assert( !t.next && !t.prev );
1415 assert( t.isRunning );
1419 synchronized( slock )
1433 // Remove a thread from the global thread list.
1435 static void remove( Thread t )
1439 assert( t.next || t.prev );
1442 // NOTE: This doesn't work for Posix as m_isRunning must be set to
1443 // false after the thread is removed during normal execution.
1444 assert( !t.isRunning );
1449 synchronized( slock )
1451 // NOTE: When a thread is removed from the global thread list its
1452 // main context is invalid and should be removed as well.
1453 // It is possible that t.m_curr could reference more
1454 // than just the main context if the thread exited abnormally
1455 // (if it was terminated), but we must assume that the user
1456 // retains a reference to them and that they may be re-used
1457 // elsewhere. Therefore, it is the responsibility of any
1458 // object that creates contexts to clean them up properly
1459 // when it is done with them.
1460 remove( &t.m_main );
1463 t.prev.next = t.next;
1465 t.next.prev = t.prev;
1470 // NOTE: Don't null out t.next or t.prev because opApply currently
1471 // follows t.next after removing a node. This could be easily
1472 // addressed by simply returning the next node from this
1473 // function, however, a thread should never be re-added to the
1474 // list anyway and having next and prev be non-null is a good way
1480 ///////////////////////////////////////////////////////////////////////////////
1481 // GC Support Routines
1482 ///////////////////////////////////////////////////////////////////////////////
1486 * Initializes the thread module. This function must be called by the
1487 * garbage collector on startup and before any other thread routines
1490 extern (C) void thread_init()
1492 // NOTE: If thread_init itself performs any allocations then the thread
1493 // routines reserved for garbage collector use may be called while
1494 // thread_init is being processed. However, since no memory should
1495 // exist to be scanned at this point, it is sufficient for these
1496 // functions to detect the condition and return immediately.
1500 Thread.sm_this = TlsAlloc();
1501 assert( Thread.sm_this != TLS_OUT_OF_INDEXES );
1503 else version( Posix )
1506 sigaction_t sigusr1 = void;
1507 sigaction_t sigusr2 = void;
1509 // This is a quick way to zero-initialize the structs without using
1510 // memset or creating a link dependency on their static initializer.
1511 (cast(byte*) &sigusr1)[0 .. sigaction_t.sizeof] = 0;
1512 (cast(byte*) &sigusr2)[0 .. sigaction_t.sizeof] = 0;
1514 // NOTE: SA_RESTART indicates that system calls should restart if they
1515 // are interrupted by a signal, but this is not available on all
1516 // Posix systems, even those that support multithreading.
1517 static if( is( typeof( SA_RESTART ) ) )
1518 sigusr1.sa_flags = SA_RESTART;
1520 sigusr1.sa_flags = 0;
1521 sigusr1.sa_handler = &thread_suspendHandler;
1522 // NOTE: We want to ignore all signals while in this handler, so fill
1523 // sa_mask to indicate this.
1524 status = sigfillset( &sigusr1.sa_mask );
1525 assert( status == 0 );
1527 // NOTE: Since SIGUSR2 should only be issued for threads within the
1528 // suspend handler, we don't want this signal to trigger a
1530 sigusr2.sa_flags = 0;
1531 sigusr2.sa_handler = &thread_resumeHandler;
1532 // NOTE: We want to ignore all signals while in this handler, so fill
1533 // sa_mask to indicate this.
1534 status = sigfillset( &sigusr2.sa_mask );
1535 assert( status == 0 );
1537 status = sigaction( SIGUSR1, &sigusr1, null );
1538 assert( status == 0 );
1540 status = sigaction( SIGUSR2, &sigusr2, null );
1541 assert( status == 0 );
1543 status = sem_init( &suspendCount, 0, 0 );
1544 assert( status == 0 );
1546 status = pthread_key_create( &Thread.sm_this, null );
1547 assert( status == 0 );
1550 thread_attachThis();
1555 * Registers the calling thread for use with the D Runtime. If this routine
1556 * is called for a thread which is already registered, the result is undefined.
1558 extern (C) void thread_attachThis()
1562 Thread thisThread = new Thread();
1563 Thread.Context* thisContext = &thisThread.m_main;
1564 assert( thisContext == thisThread.m_curr );
1566 thisThread.m_addr = GetCurrentThreadId();
1567 thisThread.m_hndl = GetCurrentThreadHandle();
1568 thisContext.bstack = getStackBottom();
1569 thisContext.tstack = thisContext.bstack;
1571 thisThread.m_isDaemon = true;
1573 Thread.setThis( thisThread );
1575 else version( Posix )
1577 Thread thisThread = new Thread();
1578 Thread.Context* thisContext = thisThread.m_curr;
1579 assert( thisContext == &thisThread.m_main );
1581 thisThread.m_addr = pthread_self();
1582 thisContext.bstack = getStackBottom();
1583 thisContext.tstack = thisContext.bstack;
1585 thisThread.m_isRunning = true;
1586 thisThread.m_isDaemon = true;
1588 Thread.setThis( thisThread );
1591 Thread.add( thisThread );
1592 Thread.add( thisContext );
1597 * Deregisters the calling thread from use with the runtime. If this routine
1598 * is called for a thread which is already registered, the result is undefined.
1600 extern (C) void thread_detachThis()
1602 Thread.remove( Thread.getThis() );
1607 * Joins all non-daemon threads that are currently running. This is done by
1608 * performing successive scans through the thread list until a scan consists
1609 * of only daemon threads.
1611 extern (C) void thread_joinAll()
1616 Thread nonDaemon = null;
1618 foreach( t; Thread )
1626 if( nonDaemon is null )
1634 * Performs intermediate shutdown of the thread module.
1638 // NOTE: The functionality related to garbage collection must be minimally
1639 // operable after this dtor completes. Therefore, only minimal
1640 // cleanup may occur.
1642 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1650 // Used for needLock below
1651 private bool multiThreadedFlag = false;
1655 * This function is used to determine whether the the process is
1656 * multi-threaded. Optimizations may only be performed on this
1657 * value if the programmer can guarantee that no path from the
1658 * enclosed code will start a thread.
1661 * True if Thread.start() has been called in this process.
1663 extern (C) bool thread_needLock()
1665 return multiThreadedFlag;
1669 // Used for suspendAll/resumeAll below
1670 private uint suspendDepth = 0;
1674 * Suspend all threads but the calling thread for "stop the world" garbage
1675 * collection runs. This function may be called multiple times, and must
1676 * be followed by a matching number of calls to thread_resumeAll before
1677 * processing is resumed.
1680 * ThreadException if the suspend operation fails for a running thread.
1682 extern (C) void thread_suspendAll()
1685 * Suspend the specified thread and load stack and register information for
1686 * use by thread_scanAll. If the supplied thread is the calling thread,
1687 * stack and register information will be loaded but the thread will not
1688 * be suspended. If the suspend operation fails and the thread is not
1689 * running then it will be removed from the global thread list, otherwise
1690 * an exception will be thrown.
1693 * t = The thread to suspend.
1696 * ThreadException if the suspend operation fails for a running thread.
1698 void suspend( Thread t )
1702 if( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF )
1709 throw new ThreadException( "Unable to suspend thread" );
1712 CONTEXT context = void;
1713 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
1715 if( !GetThreadContext( t.m_hndl, &context ) )
1716 throw new ThreadException( "Unable to load thread context" );
1718 t.m_curr.tstack = cast(void*) context.Esp;
1719 // edi,esi,ebp,esp,ebx,edx,ecx,eax
1720 t.m_reg[0] = context.Edi;
1721 t.m_reg[1] = context.Esi;
1722 t.m_reg[2] = context.Ebp;
1723 t.m_reg[3] = context.Esp;
1724 t.m_reg[4] = context.Ebx;
1725 t.m_reg[5] = context.Edx;
1726 t.m_reg[6] = context.Ecx;
1727 t.m_reg[7] = context.Eax;
1729 else version( Posix )
1731 if( t.m_addr != pthread_self() )
1733 if( pthread_kill( t.m_addr, SIGUSR1 ) != 0 )
1740 throw new ThreadException( "Unable to suspend thread" );
1742 // NOTE: It's really not ideal to wait for each thread to
1743 // signal individually -- rather, it would be better to
1744 // suspend them all and wait once at the end. However,
1745 // semaphores don't really work this way, and the obvious
1746 // alternative (looping on an atomic suspend count)
1747 // requires either the atomic module (which only works on
1748 // x86) or other specialized functionality. It would
1749 // also be possible to simply loop on sem_wait at the
1750 // end, but I'm not convinced that this would be much
1751 // faster than the current approach.
1752 sem_wait( &suspendCount );
1754 else if( !t.m_lock )
1756 t.m_curr.tstack = getStackTop();
1762 // NOTE: We've got an odd chicken & egg problem here, because while the GC
1763 // is required to call thread_init before calling any other thread
1764 // routines, thread_init may allocate memory which could in turn
1765 // trigger a collection. Thus, thread_suspendAll, thread_scanAll,
1766 // and thread_resumeAll must be callable before thread_init
1767 // completes, with the assumption that no other GC memory has yet
1768 // been allocated by the system, and thus there is no risk of losing
1769 // data if the global thread list is empty. The check of
1770 // Thread.sm_tbeg below is done to ensure thread_init has completed,
1771 // and therefore that calling Thread.getThis will not result in an
1772 // error. For the short time when Thread.sm_tbeg is null, there is
1773 // no reason not to simply call the multithreaded code below, with
1774 // the expectation that the foreach loop will never be entered.
1775 if( !multiThreadedFlag && Thread.sm_tbeg )
1777 if( ++suspendDepth == 1 )
1778 suspend( Thread.getThis() );
1781 synchronized( Thread.slock )
1783 if( ++suspendDepth > 1 )
1786 // NOTE: I'd really prefer not to check isRunning within this loop but
1787 // not doing so could be problematic if threads are termianted
1788 // abnormally and a new thread is created with the same thread
1789 // address before the next GC run. This situation might cause
1790 // the same thread to be suspended twice, which would likely
1791 // cause the second suspend to fail, the garbage collection to
1792 // abort, and Bad Things to occur.
1793 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1803 // wait on semaphore -- see note in suspend for
1804 // why this is currently not implemented
1811 * Resume all threads but the calling thread for "stop the world" garbage
1812 * collection runs. This function must be called once for each preceding
1813 * call to thread_suspendAll before the threads are actually resumed.
1816 * This routine must be preceded by a call to thread_suspendAll.
1819 * ThreadException if the resume operation fails for a running thread.
1821 extern (C) void thread_resumeAll()
1824 assert( suspendDepth > 0 );
1829 * Resume the specified thread and unload stack and register information.
1830 * If the supplied thread is the calling thread, stack and register
1831 * information will be unloaded but the thread will not be resumed. If
1832 * the resume operation fails and the thread is not running then it will
1833 * be removed from the global thread list, otherwise an exception will be
1837 * t = The thread to resume.
1840 * ThreadException if the resume fails for a running thread.
1842 void resume( Thread t )
1846 if( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF )
1853 throw new ThreadException( "Unable to resume thread" );
1857 t.m_curr.tstack = t.m_curr.bstack;
1858 t.m_reg[0 .. $] = 0;
1860 else version( Posix )
1862 if( t.m_addr != pthread_self() )
1864 if( pthread_kill( t.m_addr, SIGUSR2 ) != 0 )
1871 throw new ThreadException( "Unable to resume thread" );
1874 else if( !t.m_lock )
1876 t.m_curr.tstack = t.m_curr.bstack;
1882 // NOTE: See thread_suspendAll for the logic behind this.
1883 if( !multiThreadedFlag && Thread.sm_tbeg )
1885 if( --suspendDepth == 0 )
1886 resume( Thread.getThis() );
1889 synchronized( Thread.slock )
1891 if( --suspendDepth > 0 )
1894 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1902 private alias void delegate( void*, void* ) scanAllThreadsFn;
1906 * The main entry point for garbage collection. The supplied delegate
1907 * will be passed ranges representing both stack and register values.
1910 * scan = The scanner function. It should scan from p1 through p2 - 1.
1911 * curStackTop = An optional pointer to the top of the calling thread's stack.
1914 * This routine must be preceded by a call to thread_suspendAll.
1916 extern (C) void thread_scanAll( scanAllThreadsFn scan, void* curStackTop = null )
1919 assert( suspendDepth > 0 );
1923 Thread thisThread = null;
1924 void* oldStackTop = null;
1926 if( curStackTop && Thread.sm_tbeg )
1928 thisThread = Thread.getThis();
1929 if( !thisThread.m_lock )
1931 oldStackTop = thisThread.m_curr.tstack;
1932 thisThread.m_curr.tstack = curStackTop;
1938 if( curStackTop && Thread.sm_tbeg )
1940 if( !thisThread.m_lock )
1942 thisThread.m_curr.tstack = oldStackTop;
1947 // NOTE: Synchronizing on Thread.slock is not needed because this
1948 // function may only be called after all other threads have
1949 // been suspended from within the same lock.
1950 for( Thread.Context* c = Thread.sm_cbeg; c; c = c.next )
1952 version( StackGrowsDown )
1954 // NOTE: We can't index past the bottom of the stack
1955 // so don't do the "+1" for StackGrowsDown.
1956 if( c.tstack && c.tstack < c.bstack )
1957 scan( c.tstack, c.bstack );
1961 if( c.bstack && c.bstack < c.tstack )
1962 scan( c.bstack, c.tstack + 1 );
1967 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1969 scan( &t.m_reg[0], &t.m_reg[0] + t.m_reg.length );
1975 ///////////////////////////////////////////////////////////////////////////////
1977 ///////////////////////////////////////////////////////////////////////////////
1981 * This class encapsulates the operations required to initialize, access, and
1982 * destroy thread local data.
1984 class ThreadLocal( T )
1986 ///////////////////////////////////////////////////////////////////////////
1988 ///////////////////////////////////////////////////////////////////////////
1992 * Initializes thread local storage for the indicated value which will be
1993 * initialized to def for all threads.
1996 * def = The default value to return if no value has been explicitly set.
1998 this( T def = T.init )
2001 m_key = Thread.createLocal();
2007 Thread.deleteLocal( m_key );
2011 ///////////////////////////////////////////////////////////////////////////
2013 ///////////////////////////////////////////////////////////////////////////
2017 * Gets the value last set by the calling thread, or def if no such value
2021 * The stored value or def if no value is stored.
2025 Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
2027 return wrap ? wrap.val : m_def;
2032 * Copies newval to a location specific to the calling thread, and returns
2036 * newval = The value to set.
2039 * The value passed to this function.
2043 Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
2048 Thread.setLocal( m_key, wrap );
2057 // A wrapper for the stored data. This is needed for determining whether
2058 // set has ever been called for this thread (and therefore whether the
2059 // default value should be returned) and also to flatten the differences
2060 // between data that is smaller and larger than (void*).sizeof. The
2061 // obvious tradeoff here is an extra per-thread allocation for each
2062 // ThreadLocal value as compared to calling the Thread routines directly.
2075 ///////////////////////////////////////////////////////////////////////////////
2077 ///////////////////////////////////////////////////////////////////////////////
2081 * This class is intended to simplify certain common programming techniques.
2086 * Creates and starts a new Thread object that executes fn and adds it to
2087 * the list of tracked threads.
2090 * fn = The thread function.
2093 * A reference to the newly created thread.
2095 final Thread create( void function() fn )
2097 Thread t = new Thread( fn );
2100 synchronized( this )
2109 * Creates and starts a new Thread object that executes dg and adds it to
2110 * the list of tracked threads.
2113 * dg = The thread function.
2116 * A reference to the newly created thread.
2118 final Thread create( void delegate() dg )
2120 Thread t = new Thread( dg );
2123 synchronized( this )
2132 * Add t to the list of tracked threads if it is not already being tracked.
2135 * t = The thread to add.
2138 * t must not be null.
2140 final void add( Thread t )
2147 synchronized( this )
2155 * Removes t from the list of tracked threads. No operation will be
2156 * performed if t is not currently being tracked by this object.
2159 * t = The thread to remove.
2162 * t must not be null.
2164 final void remove( Thread t )
2171 synchronized( this )
2179 * Operates on all threads currently tracked by this object.
2181 final int opApply( int delegate( inout Thread ) dg )
2183 synchronized( this )
2187 // NOTE: This loop relies on the knowledge that m_all uses the
2188 // Thread object for both the key and the mapped value.
2189 foreach( Thread t; m_all.keys )
2201 * Iteratively joins all tracked threads. This function will block add,
2202 * remove, and opApply until it completes.
2205 * rethrow = Rethrow any unhandled exception which may have caused the
2206 * current thread to terminate.
2209 * Any exception not handled by the joined threads.
2211 final void joinAll( bool rethrow = true )
2213 synchronized( this )
2215 // NOTE: This loop relies on the knowledge that m_all uses the
2216 // Thread object for both the key and the mapped value.
2217 foreach( Thread t; m_all.keys )
2226 Thread[Thread] m_all;
2230 ///////////////////////////////////////////////////////////////////////////////
2231 // Fiber Platform Detection and Memory Allocation
2232 ///////////////////////////////////////////////////////////////////////////////
2237 version( D_InlineAsm_X86 )
2246 version = AsmX86_Win32;
2247 else version( Posix )
2248 version = AsmX86_Posix;
2254 version = AsmPPC_Posix;
2260 import core.sys.posix.unistd; // for sysconf
2261 import core.sys.posix.sys.mman; // for mmap
2262 import core.sys.posix.stdlib; // for malloc, valloc, free
2264 version( AsmX86_Win32 ) {} else
2265 version( AsmX86_Posix ) {} else
2266 version( AsmPPC_Posix ) {} else
2268 // NOTE: The ucontext implementation requires architecture specific
2269 // data definitions to operate so testing for it must be done
2270 // by checking for the existence of ucontext_t rather than by
2271 // a version identifier. Please note that this is considered
2272 // an obsolescent feature according to the POSIX spec, so a
2273 // custom solution is still preferred.
2274 import core.sys.posix.ucontext;
2278 const size_t PAGESIZE;
2284 static if( is( typeof( GetSystemInfo ) ) )
2287 GetSystemInfo( &info );
2289 PAGESIZE = info.dwPageSize;
2290 assert( PAGESIZE < int.max );
2292 else static if( is( typeof( sysconf ) ) &&
2293 is( typeof( _SC_PAGESIZE ) ) )
2295 PAGESIZE = cast(size_t) sysconf( _SC_PAGESIZE );
2296 assert( PAGESIZE < int.max );
2308 ///////////////////////////////////////////////////////////////////////////////
2309 // Fiber Entry Point and Context Switch
2310 ///////////////////////////////////////////////////////////////////////////////
2315 extern (C) void fiber_entryPoint()
2317 Fiber obj = Fiber.getThis();
2320 assert( Thread.getThis().m_curr is obj.m_ctxt );
2321 volatile Thread.getThis().m_lock = false;
2322 obj.m_ctxt.tstack = obj.m_ctxt.bstack;
2323 obj.m_state = Fiber.State.EXEC;
2331 obj.m_unhandled = o;
2334 static if( is( ucontext_t ) )
2335 obj.m_ucur = &obj.m_utxt;
2337 obj.m_state = Fiber.State.TERM;
2342 // NOTE: If AsmPPC_Posix is defined then the context switch routine will
2343 // be defined externally until GDC supports inline PPC ASM.
2344 version( AsmPPC_Posix )
2345 extern (C) void fiber_switchContext( void** oldp, void* newp );
2347 extern (C) void fiber_switchContext( void** oldp, void* newp )
2349 // NOTE: The data pushed and popped in this routine must match the
2350 // default stack created by Fiber.initStack or the initial
2351 // switch into a new context will fail.
2353 version( AsmX86_Win32 )
2359 // save current stack state
2363 push dword ptr FS:[0];
2364 push dword ptr FS:[4];
2365 push dword ptr FS:[8];
2370 // store oldp again with more accurate address
2371 mov EAX, dword ptr 8[EBP];
2373 // load newp to begin context switch
2374 mov ESP, dword ptr 12[EBP];
2376 // load saved state from new stack
2380 pop dword ptr FS:[8];
2381 pop dword ptr FS:[4];
2382 pop dword ptr FS:[0];
2386 // 'return' to complete switch
2390 else version( AsmX86_Posix )
2396 // save current stack state
2404 // store oldp again with more accurate address
2405 mov EAX, dword ptr 8[EBP];
2407 // load newp to begin context switch
2408 mov ESP, dword ptr 12[EBP];
2410 // load saved state from new stack
2417 // 'return' to complete switch
2421 else static if( is( ucontext_t ) )
2423 Fiber cfib = Fiber.getThis();
2424 void* ucur = cfib.m_ucur;
2427 swapcontext( **(cast(ucontext_t***) oldp),
2428 *(cast(ucontext_t**) newp) );
2434 ///////////////////////////////////////////////////////////////////////////////
2436 ///////////////////////////////////////////////////////////////////////////////
2440 * This class provides a cooperative concurrency mechanism integrated with the
2441 * threading and garbage collection functionality. Calling a fiber may be
2442 * considered a blocking operation that returns when the fiber yields (via
2443 * Fiber.yield()). Execution occurs within the context of the calling thread
2444 * so synchronization is not necessary to guarantee memory visibility so long
2445 * as the same thread calls the fiber each time. Please note that there is no
2446 * requirement that a fiber be bound to one specific thread. Rather, fibers
2447 * may be freely passed between threads so long as they are not currently
2448 * executing. Like threads, a new fiber thread may be created using either
2449 * derivation or composition, as in the following example.
2452 * ----------------------------------------------------------------------
2454 * class DerivedFiber : Fiber
2464 * printf( "Derived fiber running.\n" );
2470 * printf( "Composed fiber running.\n" );
2472 * printf( "Composed fiber running.\n" );
2475 * // create instances of each type
2476 * Fiber derived = new DerivedFiber();
2477 * Fiber composed = new Fiber( &fiberFunc );
2479 * // call both fibers once
2482 * printf( "Execution returned to calling context.\n" );
2485 * // since each fiber has run to completion, each should have state TERM
2486 * assert( derived.state == Fiber.State.TERM );
2487 * assert( composed.state == Fiber.State.TERM );
2489 * ----------------------------------------------------------------------
2491 * Authors: Based on a design by Mikola Lysenko.
2495 ///////////////////////////////////////////////////////////////////////////
2497 ///////////////////////////////////////////////////////////////////////////
2501 * Initializes a fiber object which is associated with a static
2505 * fn = The thread function.
2506 * sz = The stack size for this fiber.
2509 * fn must not be null.
2511 this( void function() fn, size_t sz = PAGESIZE )
2520 m_state = State.HOLD;
2527 * Initializes a fiber object which is associated with a dynamic
2531 * dg = The thread function.
2532 * sz = The stack size for this fiber.
2535 * dg must not be null.
2537 this( void delegate() dg, size_t sz = PAGESIZE )
2546 m_state = State.HOLD;
2553 * Cleans up any remaining resources used by this object.
2557 // NOTE: A live reference to this object will exist on its associated
2558 // stack from the first time its call() method has been called
2559 // until its execution completes with State.TERM. Thus, the only
2560 // times this dtor should be called are either if the fiber has
2561 // terminated (and therefore has no active stack) or if the user
2562 // explicitly deletes this object. The latter case is an error
2563 // but is not easily tested for, since State.HOLD may imply that
2564 // the fiber was just created but has never been run. There is
2565 // not a compelling case to create a State.INIT just to offer a
2566 // means of ensuring the user isn't violating this object's
2567 // contract, so for now this requirement will be enforced by
2568 // documentation only.
2573 ///////////////////////////////////////////////////////////////////////////
2575 ///////////////////////////////////////////////////////////////////////////
2579 * Transfers execution to this fiber object. The calling context will be
2580 * suspended until the fiber calls Fiber.yield() or until it terminates
2581 * via an unhandled exception.
2584 * rethrow = Rethrow any unhandled exception which may have caused this
2585 * fiber to terminate.
2588 * This fiber must be in state HOLD.
2591 * Any exception not handled by the joined thread.
2594 * Any exception not handled by this fiber if rethrow = false, null
2597 final Object call( bool rethrow = true )
2600 assert( m_state == State.HOLD );
2604 Fiber cur = getThis();
2606 static if( is( ucontext_t ) )
2607 m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt;
2613 static if( is( ucontext_t ) )
2616 // NOTE: If the fiber has terminated then the stack pointers must be
2617 // reset. This ensures that the stack for this fiber is not
2618 // scanned if the fiber has terminated. This is necessary to
2619 // prevent any references lingering on the stack from delaying
2620 // the collection of otherwise dead objects. The most notable
2621 // being the current object, which is referenced at the top of
2622 // fiber_entryPoint.
2623 if( m_state == State.TERM )
2625 m_ctxt.tstack = m_ctxt.bstack;
2629 Object obj = m_unhandled;
2640 * Resets this fiber so that it may be re-used. This routine may only be
2641 * called for fibers that have terminated, as doing otherwise could result
2642 * in scope-dependent functionality that is not executed. Stack-based
2643 * classes, for example, may not be cleaned up properly if a fiber is reset
2644 * before it has terminated.
2647 * This fiber must be in state TERM.
2652 assert( m_state == State.TERM );
2653 assert( m_ctxt.tstack == m_ctxt.bstack );
2657 m_state = State.HOLD;
2663 ///////////////////////////////////////////////////////////////////////////
2664 // General Properties
2665 ///////////////////////////////////////////////////////////////////////////
2669 * A fiber may occupy one of three states: HOLD, EXEC, and TERM. The HOLD
2670 * state applies to any fiber that is suspended and ready to be called.
2671 * The EXEC state will be set for any fiber that is currently executing.
2672 * And the TERM state is set when a fiber terminates. Once a fiber
2673 * terminates, it must be reset before it may be called again.
2684 * Gets the current state of this fiber.
2687 * The state of this fiber as an enumerated value.
2695 ///////////////////////////////////////////////////////////////////////////
2696 // Actions on Calling Fiber
2697 ///////////////////////////////////////////////////////////////////////////
2701 * Forces a context switch to occur away from the calling fiber.
2705 Fiber cur = getThis();
2706 assert( cur, "Fiber.yield() called with no active fiber" );
2707 assert( cur.m_state == State.EXEC );
2709 static if( is( ucontext_t ) )
2710 cur.m_ucur = &cur.m_utxt;
2712 cur.m_state = State.HOLD;
2714 cur.m_state = State.EXEC;
2719 * Forces a context switch to occur away from the calling fiber and then
2720 * throws obj in the calling fiber.
2723 * obj = The object to throw.
2726 * obj must not be null.
2728 static void yieldAndThrow( Object obj )
2735 Fiber cur = getThis();
2736 assert( cur, "Fiber.yield() called with no active fiber" );
2737 assert( cur.m_state == State.EXEC );
2739 static if( is( ucontext_t ) )
2740 cur.m_ucur = &cur.m_utxt;
2742 cur.m_unhandled = obj;
2743 cur.m_state = State.HOLD;
2745 cur.m_state = State.EXEC;
2749 ///////////////////////////////////////////////////////////////////////////
2751 ///////////////////////////////////////////////////////////////////////////
2755 * Provides a reference to the calling fiber or null if no fiber is
2759 * The fiber object representing the calling fiber or null if no fiber
2760 * is currently active. The result of deleting this object is undefined.
2762 static Fiber getThis()
2766 return cast(Fiber) TlsGetValue( sm_this );
2768 else version( Posix )
2770 return cast(Fiber) pthread_getspecific( sm_this );
2775 ///////////////////////////////////////////////////////////////////////////
2776 // Static Initialization
2777 ///////////////////////////////////////////////////////////////////////////
2784 sm_this = TlsAlloc();
2785 assert( sm_this != TLS_OUT_OF_INDEXES );
2787 else version( Posix )
2791 status = pthread_key_create( &sm_this, null );
2792 assert( status == 0 );
2794 static if( is( ucontext_t ) )
2796 status = getcontext( &sm_utxt );
2797 assert( status == 0 );
2805 // Initializes a fiber object which has no associated executable function.
2814 // Fiber entry point. Invokes the function or delegate passed on
2815 // construction (if any).
2835 // The type of routine passed on fiber construction.
2846 // Standard fiber data
2851 void function() m_fn;
2852 void delegate() m_dg;
2860 ///////////////////////////////////////////////////////////////////////////
2862 ///////////////////////////////////////////////////////////////////////////
2866 // Allocate a new stack for this fiber.
2868 final void allocStack( size_t sz )
2871 assert( !m_pmem && !m_ctxt );
2875 // adjust alloc size to a multiple of PAGESIZE
2877 sz -= sz % PAGESIZE;
2879 // NOTE: This instance of Thread.Context is dynamic so Fiber objects
2880 // can be collected by the GC so long as no user level references
2881 // to the object exist. If m_ctxt were not dynamic then its
2882 // presence in the global context list would be enough to keep
2883 // this object alive indefinitely. An alternative to allocating
2884 // room for this struct explicitly would be to mash it into the
2885 // base of the stack being allocated below. However, doing so
2886 // requires too much special logic to be worthwhile.
2887 m_ctxt = new Thread.Context;
2889 static if( is( typeof( VirtualAlloc ) ) )
2891 // reserve memory for stack
2892 m_pmem = VirtualAlloc( null,
2898 throw new FiberException( "Unable to reserve memory for stack" );
2901 version( StackGrowsDown )
2903 void* stack = m_pmem + PAGESIZE;
2904 void* guard = m_pmem;
2905 void* pbase = stack + sz;
2909 void* stack = m_pmem;
2910 void* guard = m_pmem + sz;
2911 void* pbase = stack;
2914 // allocate reserved stack segment
2915 stack = VirtualAlloc( stack,
2921 throw new FiberException( "Unable to allocate memory for stack" );
2924 // allocate reserved guard page
2925 guard = VirtualAlloc( guard,
2928 PAGE_READWRITE | PAGE_GUARD );
2931 throw new FiberException( "Unable to create guard page for stack" );
2934 m_ctxt.bstack = pbase;
2935 m_ctxt.tstack = pbase;
2939 { static if( is( typeof( mmap ) ) )
2941 m_pmem = mmap( null,
2943 PROT_READ | PROT_WRITE,
2944 MAP_PRIVATE | MAP_ANON,
2947 if( m_pmem == MAP_FAILED )
2950 else static if( is( typeof( valloc ) ) )
2952 m_pmem = valloc( sz );
2954 else static if( is( typeof( malloc ) ) )
2956 m_pmem = malloc( sz );
2965 throw new FiberException( "Unable to allocate memory for stack" );
2968 version( StackGrowsDown )
2970 m_ctxt.bstack = m_pmem + sz;
2971 m_ctxt.tstack = m_pmem + sz;
2975 m_ctxt.bstack = m_pmem;
2976 m_ctxt.tstack = m_pmem;
2981 Thread.add( m_ctxt );
2986 // Free this fiber's stack.
2988 final void freeStack()
2991 assert( m_pmem && m_ctxt );
2995 // NOTE: Since this routine is only ever expected to be called from
2996 // the dtor, pointers to freed data are not set to null.
2998 // NOTE: m_ctxt is guaranteed to be alive because it is held in the
2999 // global context list.
3000 Thread.remove( m_ctxt );
3002 static if( is( typeof( VirtualAlloc ) ) )
3004 VirtualFree( m_pmem, 0, MEM_RELEASE );
3006 else static if( is( typeof( mmap ) ) )
3008 munmap( m_pmem, m_size );
3010 else static if( is( typeof( valloc ) ) )
3014 else static if( is( typeof( malloc ) ) )
3023 // Initialize the allocated stack.
3025 final void initStack()
3028 assert( m_ctxt.tstack && m_ctxt.tstack == m_ctxt.bstack );
3029 assert( cast(size_t) m_ctxt.bstack % (void*).sizeof == 0 );
3033 void* pstack = m_ctxt.tstack;
3034 scope( exit ) m_ctxt.tstack = pstack;
3036 void push( size_t val )
3038 version( StackGrowsDown )
3040 pstack -= size_t.sizeof;
3041 *(cast(size_t*) pstack) = val;
3045 pstack += size_t.sizeof;
3046 *(cast(size_t*) pstack) = val;
3050 // NOTE: On OS X the stack must be 16-byte aligned according to the
3054 pstack = cast(void*)(cast(uint)(pstack) - (cast(uint)(pstack) & 0x0F));
3057 version( AsmX86_Win32 )
3059 push( cast(size_t) &fiber_entryPoint ); // EIP
3060 push( 0xFFFFFFFF ); // EBP
3061 push( 0x00000000 ); // EAX
3062 push( 0xFFFFFFFF ); // FS:[0]
3063 version( StackGrowsDown )
3065 push( cast(size_t) m_ctxt.bstack ); // FS:[4]
3066 push( cast(size_t) m_ctxt.bstack - m_size ); // FS:[8]
3070 push( cast(size_t) m_ctxt.bstack ); // FS:[4]
3071 push( cast(size_t) m_ctxt.bstack + m_size ); // FS:[8]
3073 push( 0x00000000 ); // EBX
3074 push( 0x00000000 ); // ESI
3075 push( 0x00000000 ); // EDI
3077 else version( AsmX86_Posix )
3079 push( cast(size_t) &fiber_entryPoint ); // EIP
3080 push( 0x00000000 ); // EBP
3081 push( 0x00000000 ); // EAX
3082 push( 0x00000000 ); // EBX
3083 push( 0x00000000 ); // ESI
3084 push( 0x00000000 ); // EDI
3086 else version( AsmPPC_Posix )
3088 version( StackGrowsDown )
3090 pstack -= int.sizeof * 5;
3094 pstack += int.sizeof * 5;
3097 push( cast(size_t) &fiber_entryPoint ); // link register
3098 push( 0x00000000 ); // control register
3099 push( 0x00000000 ); // old stack pointer
3102 version( StackGrowsDown )
3104 pstack -= int.sizeof * 20;
3108 pstack += int.sizeof * 20;
3111 assert( cast(uint) pstack & 0x0f == 0 );
3113 else static if( is( ucontext_t ) )
3115 getcontext( &m_utxt );
3116 m_utxt.uc_stack.ss_sp = m_ctxt.bstack;
3117 m_utxt.uc_stack.ss_size = m_size;
3118 makecontext( &m_utxt, &fiber_entryPoint, 0 );
3119 // NOTE: If ucontext is being used then the top of the stack will
3120 // be a pointer to the ucontext_t struct for that fiber.
3121 push( cast(size_t) &m_utxt );
3126 Thread.Context* m_ctxt;
3130 static if( is( ucontext_t ) )
3132 // NOTE: The static ucontext instance is used to represent the context
3133 // of the main application thread.
3134 static ucontext_t sm_utxt = void;
3135 ucontext_t m_utxt = void;
3136 ucontext_t* m_ucur = null;
3141 ///////////////////////////////////////////////////////////////////////////
3142 // Storage of Active Fiber
3143 ///////////////////////////////////////////////////////////////////////////
3147 // Sets a thread-local reference to the current fiber object.
3149 static void setThis( Fiber f )
3153 TlsSetValue( sm_this, cast(void*) f );
3155 else version( Posix )
3157 pthread_setspecific( sm_this, cast(void*) f );
3162 static Thread.TLSKey sm_this;
3166 ///////////////////////////////////////////////////////////////////////////
3167 // Context Switching
3168 ///////////////////////////////////////////////////////////////////////////
3172 // Switches into the stack held by this fiber.
3174 final void switchIn()
3176 Thread tobj = Thread.getThis();
3177 void** oldp = &tobj.m_curr.tstack;
3178 void* newp = m_ctxt.tstack;
3180 // NOTE: The order of operations here is very important. The current
3181 // stack top must be stored before m_lock is set, and pushContext
3182 // must not be called until after m_lock is set. This process
3183 // is intended to prevent a race condition with the suspend
3184 // mechanism used for garbage collection. If it is not followed,
3185 // a badly timed collection could cause the GC to scan from the
3186 // bottom of one stack to the top of another, or to miss scanning
3187 // a stack that still contains valid data. The old stack pointer
3188 // oldp will be set again before the context switch to guarantee
3189 // that it points to exactly the correct stack location so the
3190 // successive pop operations will succeed.
3191 *oldp = getStackTop();
3192 volatile tobj.m_lock = true;
3193 tobj.pushContext( m_ctxt );
3195 fiber_switchContext( oldp, newp );
3197 // NOTE: As above, these operations must be performed in a strict order
3198 // to prevent Bad Things from happening.
3200 volatile tobj.m_lock = false;
3201 tobj.m_curr.tstack = tobj.m_curr.bstack;
3206 // Switches out of the current stack and into the enclosing stack.
3208 final void switchOut()
3210 Thread tobj = Thread.getThis();
3211 void** oldp = &m_ctxt.tstack;
3212 void* newp = tobj.m_curr.within.tstack;
3214 // NOTE: The order of operations here is very important. The current
3215 // stack top must be stored before m_lock is set, and pushContext
3216 // must not be called until after m_lock is set. This process
3217 // is intended to prevent a race condition with the suspend
3218 // mechanism used for garbage collection. If it is not followed,
3219 // a badly timed collection could cause the GC to scan from the
3220 // bottom of one stack to the top of another, or to miss scanning
3221 // a stack that still contains valid data. The old stack pointer
3222 // oldp will be set again before the context switch to guarantee
3223 // that it points to exactly the correct stack location so the
3224 // successive pop operations will succeed.
3225 *oldp = getStackTop();
3226 volatile tobj.m_lock = true;
3228 fiber_switchContext( oldp, newp );
3230 // NOTE: As above, these operations must be performed in a strict order
3231 // to prevent Bad Things from happening.
3232 volatile tobj.m_lock = false;
3233 tobj.m_curr.tstack = tobj.m_curr.bstack;