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.
204 pthread_cleanup cleanup = void;
205 cleanup.push( &thread_cleanupHandler, cast(void*) obj );
207 else version( darwin )
209 pthread_cleanup cleanup = void;
210 cleanup.push( &thread_cleanupHandler, cast(void*) obj );
214 pthread_cleanup_push( &thread_cleanupHandler, cast(void*) obj );
217 // NOTE: For some reason this does not always work for threads.
218 //obj.m_main.bstack = getStackBottom();
219 version( D_InlineAsm_X86 )
221 static void* getBasePtr()
231 obj.m_main.bstack = getBasePtr();
233 else version( StackGrowsDown )
234 obj.m_main.bstack = &obj + 1;
236 obj.m_main.bstack = &obj;
237 obj.m_main.tstack = obj.m_main.bstack;
238 assert( obj.m_curr == &obj.m_main );
239 Thread.add( &obj.m_main );
240 Thread.setThis( obj );
242 // NOTE: No GC allocations may occur until the stack pointers have
243 // been set and Thread.getThis returns a valid reference to
244 // this thread object (this latter condition is not strictly
245 // necessary on Win32 but it should be followed for the sake
248 // TODO: Consider putting an auto exception object here (using
249 // alloca) forOutOfMemoryError plus something to track
250 // whether an exception is in-flight?
265 // used to track the number of suspended threads
270 extern (C) void thread_suspendHandler( int sig )
273 assert( sig == SIGUSR1 );
277 version( D_InlineAsm_X86 )
286 __builtin_unwind_init();
290 static assert( false, "Architecture not supported." );
293 // NOTE: Since registers are being pushed and popped from the
294 // stack, any other stack data used by this function should
295 // be gone before the stack cleanup code is called below.
297 Thread obj = Thread.getThis();
299 // NOTE: The thread reference returned by getThis is set within
300 // the thread startup code, so it is possible that this
301 // handler may be called before the reference is set. In
302 // this case it is safe to simply suspend and not worry
303 // about the stack pointers as the thread will not have
304 // any references to GC-managed data.
305 if( obj && !obj.m_lock )
307 obj.m_curr.tstack = getStackTop();
310 sigset_t sigres = void;
313 status = sigfillset( &sigres );
314 assert( status == 0 );
316 status = sigdelset( &sigres, SIGUSR2 );
317 assert( status == 0 );
319 status = sem_post( &suspendCount );
320 assert( status == 0 );
322 sigsuspend( &sigres );
324 if( obj && !obj.m_lock )
326 obj.m_curr.tstack = obj.m_curr.bstack;
330 version( D_InlineAsm_X86 )
339 // registers will be popped automatically
343 static assert( false, "Architecture not supported." );
348 extern (C) void thread_resumeHandler( int sig )
351 assert( sig == SIGUSR2 );
361 // NOTE: This is the only place threading versions are checked. If a new
362 // version is added, the module code will need to be searched for
363 // places where version-specific code may be required. This can be
364 // easily accomlished by searching for 'Windows' or 'Posix'.
365 static assert( false, "Unknown threading implementation." );
369 ///////////////////////////////////////////////////////////////////////////////
371 ///////////////////////////////////////////////////////////////////////////////
375 * This class encapsulates all threading functionality for the D
376 * programming language. As thread manipulation is a required facility
377 * for garbage collection, all user threads should derive from this
378 * class, and instances of this class should never be explicitly deleted.
379 * A new thread may be created using either derivation or composition, as
380 * in the following example.
383 * ----------------------------------------------------------------------------
385 * class DerivedThread : Thread
395 * printf( "Derived thread running.\n" );
401 * printf( "Composed thread running.\n" );
404 * // create instances of each type
405 * Thread derived = new DerivedThread();
406 * Thread composed = new Thread( &threadFunc );
408 * // start both threads
412 * ----------------------------------------------------------------------------
416 ///////////////////////////////////////////////////////////////////////////
418 ///////////////////////////////////////////////////////////////////////////
422 * Initializes a thread object which is associated with a static
426 * fn = The thread function.
427 * sz = The stack size for this thread.
430 * fn must not be null.
432 this( void function() fn, size_t sz = 0 )
447 * Initializes a thread object which is associated with a dynamic
451 * dg = The thread function.
452 * sz = The stack size for this thread.
455 * dg must not be null.
457 this( void delegate() dg, size_t sz = 0 )
472 * Cleans up any remaining resources used by this object.
476 if( m_addr == m_addr.init )
483 m_addr = m_addr.init;
484 CloseHandle( m_hndl );
485 m_hndl = m_hndl.init;
487 else version( Posix )
489 pthread_detach( m_addr );
490 m_addr = m_addr.init;
495 ///////////////////////////////////////////////////////////////////////////
497 ///////////////////////////////////////////////////////////////////////////
501 * Starts the thread and invokes the function or delegate passed upon
505 * This routine may only be called once per thread instance.
508 * ThreadException if the thread fails to start.
513 assert( !next && !prev );
517 version( Win32 ) {} else
522 if( pthread_attr_init( &attr ) )
523 throw new ThreadException( "Error initializing thread attributes" );
524 if( m_sz && pthread_attr_setstacksize( &attr, m_sz ) )
525 throw new ThreadException( "Error initializing thread stack size" );
526 if( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) )
527 throw new ThreadException( "Error setting thread joinable" );
530 // NOTE: This operation needs to be synchronized to avoid a race
531 // condition with the GC. Without this lock, the thread
532 // could start and allocate memory before being added to
533 // the global thread list, preventing it from being scanned
534 // and causing memory to be collected that is still in use.
535 synchronized( slock )
539 m_hndl = cast(HANDLE) _beginthreadex( null, m_sz, &thread_entryPoint, cast(void*) this, 0, &m_addr );
540 if( cast(size_t) m_hndl == 0 )
541 throw new ThreadException( "Error creating thread" );
543 else version( Posix )
546 scope( failure ) m_isRunning = false;
548 if( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 )
549 throw new ThreadException( "Error creating thread" );
551 multiThreadedFlag = true;
558 * Waits for this thread to complete. If the thread terminated as the
559 * result of an unhandled exception, this exception will be rethrown.
562 * rethrow = Rethrow any unhandled exception which may have caused this
563 * thread to terminate.
566 * ThreadException if the operation fails.
567 * Any exception not handled by the joined thread.
570 * Any exception not handled by this thread if rethrow = false, null
573 final Object join( bool rethrow = true )
577 if( WaitForSingleObject( m_hndl, INFINITE ) != WAIT_OBJECT_0 )
578 throw new ThreadException( "Unable to join thread" );
579 // NOTE: m_addr must be cleared before m_hndl is closed to avoid
580 // a race condition with isRunning. The operation is labeled
581 // volatile to prevent compiler reordering.
582 volatile m_addr = m_addr.init;
583 CloseHandle( m_hndl );
584 m_hndl = m_hndl.init;
586 else version( Posix )
588 if( pthread_join( m_addr, null ) != 0 )
589 throw new ThreadException( "Unable to join thread" );
590 // NOTE: pthread_join acts as a substitute for pthread_detach,
591 // which is normally called by the dtor. Setting m_addr
592 // to zero ensures that pthread_detach will not be called
593 // on object destruction.
594 volatile m_addr = m_addr.init;
606 ///////////////////////////////////////////////////////////////////////////
607 // General Properties
608 ///////////////////////////////////////////////////////////////////////////
612 * Gets the user-readable label for this thread.
615 * The name of this thread.
627 * Sets the user-readable label for this thread.
630 * val = The new name of this thread.
632 final void name( char[] val )
642 * Gets the daemon status for this thread. While the runtime will wait for
643 * all normal threads to complete before tearing down the process, daemon
644 * threads are effectively ignored and thus will not prevent the process
645 * from terminating. In effect, daemon threads will be terminated
646 * automatically by the OS when the process exits.
649 * true if this is a daemon thread.
651 final bool isDaemon()
661 * Sets the daemon status for this thread. While the runtime will wait for
662 * all normal threads to complete before tearing down the process, daemon
663 * threads are effectively ignored and thus will not prevent the process
664 * from terminating. In effect, daemon threads will be terminated
665 * automatically by the OS when the process exits.
668 * val = The new daemon status for this thread.
670 final void isDaemon( bool val )
680 * Tests whether this thread is running.
683 * true if the thread is running, false if not.
685 final bool isRunning()
687 if( m_addr == m_addr.init )
695 GetExitCodeThread( m_hndl, &ecode );
696 return ecode == STILL_ACTIVE;
698 else version( Posix )
700 // NOTE: It should be safe to access this value without
701 // memory barriers because word-tearing and such
702 // really isn't an issue for boolean values.
708 ///////////////////////////////////////////////////////////////////////////
709 // Thread Priority Actions
710 ///////////////////////////////////////////////////////////////////////////
714 * The minimum scheduling priority that may be set for a thread. On
715 * systems where multiple scheduling policies are defined, this value
716 * represents the minimum valid priority for the scheduling policy of
719 static const int PRIORITY_MIN;
723 * The maximum scheduling priority that may be set for a thread. On
724 * systems where multiple scheduling policies are defined, this value
725 * represents the minimum valid priority for the scheduling policy of
728 static const int PRIORITY_MAX;
732 * Gets the scheduling priority for the associated thread.
735 * The scheduling priority of this thread.
741 return GetThreadPriority( m_hndl );
743 else version( Posix )
748 if( pthread_getschedparam( m_addr, &policy, ¶m ) )
749 throw new ThreadException( "Unable to get thread priority" );
750 return param.sched_priority;
756 * Sets the scheduling priority for the associated thread.
759 * val = The new scheduling priority of this thread.
761 final void priority( int val )
765 if( !SetThreadPriority( m_hndl, val ) )
766 throw new ThreadException( "Unable to set thread priority" );
768 else version( Posix )
770 // NOTE: pthread_setschedprio is not implemented on linux, so use
771 // the more complicated get/set sequence below.
772 //if( pthread_setschedprio( m_addr, val ) )
773 // throw new ThreadException( "Unable to set thread priority" );
778 if( pthread_getschedparam( m_addr, &policy, ¶m ) )
779 throw new ThreadException( "Unable to set thread priority" );
780 param.sched_priority = val;
781 if( pthread_setschedparam( m_addr, policy, ¶m ) )
782 throw new ThreadException( "Unable to set thread priority" );
787 ///////////////////////////////////////////////////////////////////////////
788 // Actions on Calling Thread
789 ///////////////////////////////////////////////////////////////////////////
793 * Suspends the calling thread for at least the supplied period. This may
794 * result in multiple OS calls if period is greater than the maximum sleep
795 * duration supported by the operating system.
798 * period = The minimum duration the calling thread should be suspended,
799 * in 100 nanosecond intervals.
802 * period must be non-negative.
805 * ------------------------------------------------------------------------
807 * Thread.sleep( 500 ); // sleep for 50 milliseconds
808 * Thread.sleep( 50_000_000 ); // sleep for 5 seconds
810 * ------------------------------------------------------------------------
812 static void sleep( long period )
815 assert( period >= 0 );
823 TICKS_PER_MILLI = 10_000,
824 MAX_SLEEP_MILLIS = uint.max - 1
827 period = period < TICKS_PER_MILLI ?
829 period / TICKS_PER_MILLI;
830 while( period > MAX_SLEEP_MILLIS )
832 Sleep( MAX_SLEEP_MILLIS );
833 period -= MAX_SLEEP_MILLIS;
835 Sleep( cast(uint) period );
837 else version( Posix )
840 timespec tout = void;
844 NANOS_PER_TICK = 100,
845 TICKS_PER_SECOND = 10_000_000,
847 enum : typeof(period)
849 MAX_SLEEP_TICKS = cast(typeof(period)) tin.tv_sec.max * TICKS_PER_SECOND
854 if( period > MAX_SLEEP_TICKS )
856 tin.tv_sec = tin.tv_sec.max;
861 tin.tv_sec = cast(typeof(tin.tv_sec)) (period / TICKS_PER_SECOND);
862 tin.tv_nsec = cast(typeof(tin.tv_nsec)) (period % TICKS_PER_SECOND) * NANOS_PER_TICK;
866 if( !nanosleep( &tin, &tout ) )
868 if( getErrno() != EINTR )
869 throw new ThreadException( "Unable to sleep for the specified duration" );
872 period -= (cast(typeof(period)) tin.tv_sec) * TICKS_PER_SECOND;
873 period -= (cast(typeof(period)) tin.tv_nsec) / NANOS_PER_TICK;
874 } while( period > 0 );
880 * Forces a context switch to occur away from the calling thread.
886 // NOTE: Sleep(1) is necessary because Sleep(0) does not give
887 // lower priority threads any timeslice, so looping on
888 // Sleep(0) could be resource-intensive in some cases.
891 else version( Posix )
898 ///////////////////////////////////////////////////////////////////////////
900 ///////////////////////////////////////////////////////////////////////////
904 * Provides a reference to the calling thread.
907 * The thread object representing the calling thread. The result of
908 * deleting this object is undefined.
910 static Thread getThis()
912 // NOTE: This function may not be called until thread_init has
913 // completed. See thread_suspendAll for more information
914 // on why this might occur.
917 return cast(Thread) TlsGetValue( sm_this );
919 else version( Posix )
921 return cast(Thread) pthread_getspecific( sm_this );
927 * Provides a list of all threads currently being tracked by the system.
930 * An array containing references to all threads currently being
931 * tracked by the system. The result of deleting any contained
932 * objects is undefined.
934 static Thread[] getAll()
936 synchronized( slock )
939 Thread[] buf = new Thread[sm_tlen];
941 foreach( Thread t; Thread )
951 * Operates on all threads currently being tracked by the system. The
952 * result of deleting any Thread object is undefined.
955 * dg = The supplied code as a delegate.
958 * Zero if all elemented are visited, nonzero if not.
960 static int opApply( int delegate( inout Thread ) dg )
962 synchronized( slock )
966 for( Thread t = sm_tbeg; t; t = t.next )
977 ///////////////////////////////////////////////////////////////////////////
978 // Local Storage Actions
979 ///////////////////////////////////////////////////////////////////////////
983 * Indicates the number of local storage pointers available at program
984 * startup. It is recommended that this number be at least 64.
986 static const uint LOCAL_MAX = 64;
990 * Reserves a local storage pointer for use and initializes this location
991 * to null for all running threads.
994 * A key representing the array offset of this memory location.
996 static uint createLocal()
998 synchronized( slock )
1000 foreach( uint key, inout bool set; sm_local )
1004 //foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
1005 for( Thread t = sm_tbeg; t; t = t.next )
1007 t.m_local[key] = null;
1013 throw new ThreadException( "No more local storage slots available" );
1019 * Marks the supplied key as available and sets the associated location
1020 * to null for all running threads. It is assumed that any key passed
1021 * to this function is valid. The result of calling this function for
1022 * a key which is still in use is undefined.
1025 * key = The key to delete.
1027 static void deleteLocal( uint key )
1029 synchronized( slock )
1031 sm_local[key] = false;
1032 // foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
1033 for( Thread t = sm_tbeg; t; t = t.next )
1035 t.m_local[key] = null;
1042 * Loads the value stored at key within a thread-local static array. It is
1043 * assumed that any key passed to this function is valid.
1046 * key = The location which holds the desired data.
1049 * The data associated with the supplied key.
1051 static void* getLocal( uint key )
1053 return getThis().m_local[key];
1058 * Stores the supplied value at key within a thread-local static array. It
1059 * is assumed that any key passed to this function is valid.
1062 * key = The location to store the supplied data.
1063 * val = The data to store.
1066 * A copy of the data which has just been stored.
1068 static void* setLocal( uint key, void* val )
1070 return getThis().m_local[key] = val;
1074 ///////////////////////////////////////////////////////////////////////////
1075 // Static Initalizer
1076 ///////////////////////////////////////////////////////////////////////////
1080 * This initializer is used to set thread constants. All functional
1081 * initialization occurs within thread_init().
1090 else version( Posix )
1094 pthread_t self = pthread_self();
1096 int status = pthread_getschedparam( self, &policy, ¶m );
1097 assert( status == 0 );
1099 PRIORITY_MIN = sched_get_priority_min( policy );
1100 assert( PRIORITY_MIN != -1 );
1102 PRIORITY_MAX = sched_get_priority_max( policy );
1103 assert( PRIORITY_MAX != -1 );
1110 // Initializes a thread object which has no associated executable function.
1111 // This is used for the main thread initialized in thread_init().
1121 // Thread entry point. Invokes the function or delegate passed on
1122 // construction (if any).
1142 // The type of routine passed on thread construction.
1158 alias uint ThreadAddr;
1160 else version( Posix )
1162 alias pthread_key_t TLSKey;
1163 alias pthread_t ThreadAddr;
1170 static bool[LOCAL_MAX] sm_local;
1171 static TLSKey sm_this;
1173 void*[LOCAL_MAX] m_local;
1177 // Standard thread data
1188 void function() m_fn;
1189 void delegate() m_dg;
1201 ///////////////////////////////////////////////////////////////////////////
1202 // Storage of Active Thread
1203 ///////////////////////////////////////////////////////////////////////////
1207 // Sets a thread-local reference to the current thread object.
1209 static void setThis( Thread t )
1213 TlsSetValue( sm_this, cast(void*) t );
1215 else version( Posix )
1217 pthread_setspecific( sm_this, cast(void*) t );
1223 ///////////////////////////////////////////////////////////////////////////
1224 // Thread Context and GC Scanning Support
1225 ///////////////////////////////////////////////////////////////////////////
1228 final void pushContext( Context* c )
1231 assert( !c.within );
1240 final void popContext()
1243 assert( m_curr && m_curr.within );
1247 Context* c = m_curr;
1253 final Context* topContext()
1264 static struct Context
1280 uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
1285 ///////////////////////////////////////////////////////////////////////////
1286 // GC Scanning Support
1287 ///////////////////////////////////////////////////////////////////////////
1290 // NOTE: The GC scanning process works like so:
1292 // 1. Suspend all threads.
1293 // 2. Scan the stacks of all suspended threads for roots.
1294 // 3. Resume all threads.
1296 // Step 1 and 3 require a list of all threads in the system, while
1297 // step 2 requires a list of all thread stacks (each represented by
1298 // a Context struct). Traditionally, there was one stack per thread
1299 // and the Context structs were not necessary. However, Fibers have
1300 // changed things so that each thread has its own 'main' stack plus
1301 // an arbitrary number of nested stacks (normally referenced via
1302 // m_curr). Also, there may be 'free-floating' stacks in the system,
1303 // which are Fibers that are not currently executing on any specific
1304 // thread but are still being processed and still contain valid
1307 // To support all of this, the Context struct has been created to
1308 // represent a stack range, and a global list of Context structs has
1309 // been added to enable scanning of these stack ranges. The lifetime
1310 // (and presence in the Context list) of a thread's 'main' stack will
1311 // be equivalent to the thread's lifetime. So the Ccontext will be
1312 // added to the list on thread entry, and removed from the list on
1313 // thread exit (which is essentially the same as the presence of a
1314 // Thread object in its own global list). The lifetime of a Fiber's
1315 // context, however, will be tied to the lifetime of the Fiber object
1316 // itself, and Fibers are expected to add/remove their Context struct
1317 // on construction/deletion.
1321 // All use of the global lists should synchronize on this lock.
1323 static Object slock()
1325 return Thread.classinfo;
1329 static Context* sm_cbeg;
1330 static size_t sm_clen;
1332 static Thread sm_tbeg;
1333 static size_t sm_tlen;
1336 // Used for ordering threads in the global thread list.
1342 ///////////////////////////////////////////////////////////////////////////
1343 // Global Context List Operations
1344 ///////////////////////////////////////////////////////////////////////////
1348 // Add a context to the global context list.
1350 static void add( Context* c )
1354 assert( !c.next && !c.prev );
1358 synchronized( slock )
1372 // Remove a context from the global context list.
1374 static void remove( Context* c )
1378 assert( c.next || c.prev );
1382 synchronized( slock )
1385 c.prev.next = c.next;
1387 c.next.prev = c.prev;
1392 // NOTE: Don't null out c.next or c.prev because opApply currently
1393 // follows c.next after removing a node. This could be easily
1394 // addressed by simply returning the next node from this
1395 // function, however, a context should never be re-added to the
1396 // list anyway and having next and prev be non-null is a good way
1401 ///////////////////////////////////////////////////////////////////////////
1402 // Global Thread List Operations
1403 ///////////////////////////////////////////////////////////////////////////
1407 // Add a thread to the global thread list.
1409 static void add( Thread t )
1413 assert( !t.next && !t.prev );
1414 assert( t.isRunning );
1418 synchronized( slock )
1432 // Remove a thread from the global thread list.
1434 static void remove( Thread t )
1438 assert( t.next || t.prev );
1441 // NOTE: This doesn't work for Posix as m_isRunning must be set to
1442 // false after the thread is removed during normal execution.
1443 assert( !t.isRunning );
1448 synchronized( slock )
1450 // NOTE: When a thread is removed from the global thread list its
1451 // main context is invalid and should be removed as well.
1452 // It is possible that t.m_curr could reference more
1453 // than just the main context if the thread exited abnormally
1454 // (if it was terminated), but we must assume that the user
1455 // retains a reference to them and that they may be re-used
1456 // elsewhere. Therefore, it is the responsibility of any
1457 // object that creates contexts to clean them up properly
1458 // when it is done with them.
1459 remove( &t.m_main );
1462 t.prev.next = t.next;
1464 t.next.prev = t.prev;
1469 // NOTE: Don't null out t.next or t.prev because opApply currently
1470 // follows t.next after removing a node. This could be easily
1471 // addressed by simply returning the next node from this
1472 // function, however, a thread should never be re-added to the
1473 // list anyway and having next and prev be non-null is a good way
1479 ///////////////////////////////////////////////////////////////////////////////
1480 // GC Support Routines
1481 ///////////////////////////////////////////////////////////////////////////////
1485 * Initializes the thread module. This function must be called by the
1486 * garbage collector on startup and before any other thread routines
1489 extern (C) void thread_init()
1491 // NOTE: If thread_init itself performs any allocations then the thread
1492 // routines reserved for garbage collector use may be called while
1493 // thread_init is being processed. However, since no memory should
1494 // exist to be scanned at this point, it is sufficient for these
1495 // functions to detect the condition and return immediately.
1499 Thread.sm_this = TlsAlloc();
1500 assert( Thread.sm_this != TLS_OUT_OF_INDEXES );
1502 else version( Posix )
1505 sigaction_t sigusr1 = void;
1506 sigaction_t sigusr2 = void;
1508 // This is a quick way to zero-initialize the structs without using
1509 // memset or creating a link dependency on their static initializer.
1510 (cast(byte*) &sigusr1)[0 .. sigaction_t.sizeof] = 0;
1511 (cast(byte*) &sigusr2)[0 .. sigaction_t.sizeof] = 0;
1513 // NOTE: SA_RESTART indicates that system calls should restart if they
1514 // are interrupted by a signal, but this is not available on all
1515 // Posix systems, even those that support multithreading.
1516 static if( is( typeof( SA_RESTART ) ) )
1517 sigusr1.sa_flags = SA_RESTART;
1519 sigusr1.sa_flags = 0;
1520 sigusr1.sa_handler = &thread_suspendHandler;
1521 // NOTE: We want to ignore all signals while in this handler, so fill
1522 // sa_mask to indicate this.
1523 status = sigfillset( &sigusr1.sa_mask );
1524 assert( status == 0 );
1526 // NOTE: Since SIGUSR2 should only be issued for threads within the
1527 // suspend handler, we don't want this signal to trigger a
1529 sigusr2.sa_flags = 0;
1530 sigusr2.sa_handler = &thread_resumeHandler;
1531 // NOTE: We want to ignore all signals while in this handler, so fill
1532 // sa_mask to indicate this.
1533 status = sigfillset( &sigusr2.sa_mask );
1534 assert( status == 0 );
1536 status = sigaction( SIGUSR1, &sigusr1, null );
1537 assert( status == 0 );
1539 status = sigaction( SIGUSR2, &sigusr2, null );
1540 assert( status == 0 );
1542 status = sem_init( &suspendCount, 0, 0 );
1543 assert( status == 0 );
1545 status = pthread_key_create( &Thread.sm_this, null );
1546 assert( status == 0 );
1549 thread_attachThis();
1554 * Registers the calling thread for use with the D Runtime. If this routine
1555 * is called for a thread which is already registered, the result is undefined.
1557 extern (C) void thread_attachThis()
1561 Thread thisThread = new Thread();
1562 Thread.Context* thisContext = &thisThread.m_main;
1563 assert( thisContext == thisThread.m_curr );
1565 thisThread.m_addr = GetCurrentThreadId();
1566 thisThread.m_hndl = GetCurrentThreadHandle();
1567 thisContext.bstack = getStackBottom();
1568 thisContext.tstack = thisContext.bstack;
1570 thisThread.m_isDaemon = true;
1572 Thread.setThis( thisThread );
1574 else version( Posix )
1576 Thread thisThread = new Thread();
1577 Thread.Context* thisContext = thisThread.m_curr;
1578 assert( thisContext == &thisThread.m_main );
1580 thisThread.m_addr = pthread_self();
1581 thisContext.bstack = getStackBottom();
1582 thisContext.tstack = thisContext.bstack;
1584 thisThread.m_isRunning = true;
1585 thisThread.m_isDaemon = true;
1587 Thread.setThis( thisThread );
1590 Thread.add( thisThread );
1591 Thread.add( thisContext );
1596 * Deregisters the calling thread from use with the runtime. If this routine
1597 * is called for a thread which is already registered, the result is undefined.
1599 extern (C) void thread_detachThis()
1601 Thread.remove( Thread.getThis() );
1606 * Joins all non-daemon threads that are currently running. This is done by
1607 * performing successive scans through the thread list until a scan consists
1608 * of only daemon threads.
1610 extern (C) void thread_joinAll()
1615 Thread nonDaemon = null;
1617 foreach( t; Thread )
1625 if( nonDaemon is null )
1633 * Performs intermediate shutdown of the thread module.
1637 // NOTE: The functionality related to garbage collection must be minimally
1638 // operable after this dtor completes. Therefore, only minimal
1639 // cleanup may occur.
1641 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1649 // Used for needLock below
1650 private bool multiThreadedFlag = false;
1654 * This function is used to determine whether the the process is
1655 * multi-threaded. Optimizations may only be performed on this
1656 * value if the programmer can guarantee that no path from the
1657 * enclosed code will start a thread.
1660 * True if Thread.start() has been called in this process.
1662 extern (C) bool thread_needLock()
1664 return multiThreadedFlag;
1668 // Used for suspendAll/resumeAll below
1669 private uint suspendDepth = 0;
1673 * Suspend all threads but the calling thread for "stop the world" garbage
1674 * collection runs. This function may be called multiple times, and must
1675 * be followed by a matching number of calls to thread_resumeAll before
1676 * processing is resumed.
1679 * ThreadException if the suspend operation fails for a running thread.
1681 extern (C) void thread_suspendAll()
1684 * Suspend the specified thread and load stack and register information for
1685 * use by thread_scanAll. If the supplied thread is the calling thread,
1686 * stack and register information will be loaded but the thread will not
1687 * be suspended. If the suspend operation fails and the thread is not
1688 * running then it will be removed from the global thread list, otherwise
1689 * an exception will be thrown.
1692 * t = The thread to suspend.
1695 * ThreadException if the suspend operation fails for a running thread.
1697 void suspend( Thread t )
1701 if( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF )
1708 throw new ThreadException( "Unable to suspend thread" );
1711 CONTEXT context = void;
1712 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
1714 if( !GetThreadContext( t.m_hndl, &context ) )
1715 throw new ThreadException( "Unable to load thread context" );
1717 t.m_curr.tstack = cast(void*) context.Esp;
1718 // edi,esi,ebp,esp,ebx,edx,ecx,eax
1719 t.m_reg[0] = context.Edi;
1720 t.m_reg[1] = context.Esi;
1721 t.m_reg[2] = context.Ebp;
1722 t.m_reg[3] = context.Esp;
1723 t.m_reg[4] = context.Ebx;
1724 t.m_reg[5] = context.Edx;
1725 t.m_reg[6] = context.Ecx;
1726 t.m_reg[7] = context.Eax;
1728 else version( Posix )
1730 if( t.m_addr != pthread_self() )
1732 if( pthread_kill( t.m_addr, SIGUSR1 ) != 0 )
1739 throw new ThreadException( "Unable to suspend thread" );
1741 // NOTE: It's really not ideal to wait for each thread to
1742 // signal individually -- rather, it would be better to
1743 // suspend them all and wait once at the end. However,
1744 // semaphores don't really work this way, and the obvious
1745 // alternative (looping on an atomic suspend count)
1746 // requires either the atomic module (which only works on
1747 // x86) or other specialized functionality. It would
1748 // also be possible to simply loop on sem_wait at the
1749 // end, but I'm not convinced that this would be much
1750 // faster than the current approach.
1751 sem_wait( &suspendCount );
1753 else if( !t.m_lock )
1755 t.m_curr.tstack = getStackTop();
1761 // NOTE: We've got an odd chicken & egg problem here, because while the GC
1762 // is required to call thread_init before calling any other thread
1763 // routines, thread_init may allocate memory which could in turn
1764 // trigger a collection. Thus, thread_suspendAll, thread_scanAll,
1765 // and thread_resumeAll must be callable before thread_init
1766 // completes, with the assumption that no other GC memory has yet
1767 // been allocated by the system, and thus there is no risk of losing
1768 // data if the global thread list is empty. The check of
1769 // Thread.sm_tbeg below is done to ensure thread_init has completed,
1770 // and therefore that calling Thread.getThis will not result in an
1771 // error. For the short time when Thread.sm_tbeg is null, there is
1772 // no reason not to simply call the multithreaded code below, with
1773 // the expectation that the foreach loop will never be entered.
1774 if( !multiThreadedFlag && Thread.sm_tbeg )
1776 if( ++suspendDepth == 1 )
1777 suspend( Thread.getThis() );
1780 synchronized( Thread.slock )
1782 if( ++suspendDepth > 1 )
1785 // NOTE: I'd really prefer not to check isRunning within this loop but
1786 // not doing so could be problematic if threads are termianted
1787 // abnormally and a new thread is created with the same thread
1788 // address before the next GC run. This situation might cause
1789 // the same thread to be suspended twice, which would likely
1790 // cause the second suspend to fail, the garbage collection to
1791 // abort, and Bad Things to occur.
1792 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1802 // wait on semaphore -- see note in suspend for
1803 // why this is currently not implemented
1810 * Resume all threads but the calling thread for "stop the world" garbage
1811 * collection runs. This function must be called once for each preceding
1812 * call to thread_suspendAll before the threads are actually resumed.
1815 * This routine must be preceded by a call to thread_suspendAll.
1818 * ThreadException if the resume operation fails for a running thread.
1820 extern (C) void thread_resumeAll()
1823 assert( suspendDepth > 0 );
1828 * Resume the specified thread and unload stack and register information.
1829 * If the supplied thread is the calling thread, stack and register
1830 * information will be unloaded but the thread will not be resumed. If
1831 * the resume operation fails and the thread is not running then it will
1832 * be removed from the global thread list, otherwise an exception will be
1836 * t = The thread to resume.
1839 * ThreadException if the resume fails for a running thread.
1841 void resume( Thread t )
1845 if( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF )
1852 throw new ThreadException( "Unable to resume thread" );
1856 t.m_curr.tstack = t.m_curr.bstack;
1857 t.m_reg[0 .. $] = 0;
1859 else version( Posix )
1861 if( t.m_addr != pthread_self() )
1863 if( pthread_kill( t.m_addr, SIGUSR2 ) != 0 )
1870 throw new ThreadException( "Unable to resume thread" );
1873 else if( !t.m_lock )
1875 t.m_curr.tstack = t.m_curr.bstack;
1881 // NOTE: See thread_suspendAll for the logic behind this.
1882 if( !multiThreadedFlag && Thread.sm_tbeg )
1884 if( --suspendDepth == 0 )
1885 resume( Thread.getThis() );
1888 synchronized( Thread.slock )
1890 if( --suspendDepth > 0 )
1893 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1901 private alias void delegate( void*, void* ) scanAllThreadsFn;
1905 * The main entry point for garbage collection. The supplied delegate
1906 * will be passed ranges representing both stack and register values.
1909 * scan = The scanner function. It should scan from p1 through p2 - 1.
1910 * curStackTop = An optional pointer to the top of the calling thread's stack.
1913 * This routine must be preceded by a call to thread_suspendAll.
1915 extern (C) void thread_scanAll( scanAllThreadsFn scan, void* curStackTop = null )
1918 assert( suspendDepth > 0 );
1922 Thread thisThread = null;
1923 void* oldStackTop = null;
1925 if( curStackTop && Thread.sm_tbeg )
1927 thisThread = Thread.getThis();
1928 if( !thisThread.m_lock )
1930 oldStackTop = thisThread.m_curr.tstack;
1931 thisThread.m_curr.tstack = curStackTop;
1937 if( curStackTop && Thread.sm_tbeg )
1939 if( !thisThread.m_lock )
1941 thisThread.m_curr.tstack = oldStackTop;
1946 // NOTE: Synchronizing on Thread.slock is not needed because this
1947 // function may only be called after all other threads have
1948 // been suspended from within the same lock.
1949 for( Thread.Context* c = Thread.sm_cbeg; c; c = c.next )
1951 version( StackGrowsDown )
1953 // NOTE: We can't index past the bottom of the stack
1954 // so don't do the "+1" for StackGrowsDown.
1955 if( c.tstack && c.tstack < c.bstack )
1956 scan( c.tstack, c.bstack );
1960 if( c.bstack && c.bstack < c.tstack )
1961 scan( c.bstack, c.tstack + 1 );
1966 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1968 scan( &t.m_reg[0], &t.m_reg[0] + t.m_reg.length );
1974 ///////////////////////////////////////////////////////////////////////////////
1976 ///////////////////////////////////////////////////////////////////////////////
1980 * This class encapsulates the operations required to initialize, access, and
1981 * destroy thread local data.
1983 class ThreadLocal( T )
1985 ///////////////////////////////////////////////////////////////////////////
1987 ///////////////////////////////////////////////////////////////////////////
1991 * Initializes thread local storage for the indicated value which will be
1992 * initialized to def for all threads.
1995 * def = The default value to return if no value has been explicitly set.
1997 this( T def = T.init )
2000 m_key = Thread.createLocal();
2006 Thread.deleteLocal( m_key );
2010 ///////////////////////////////////////////////////////////////////////////
2012 ///////////////////////////////////////////////////////////////////////////
2016 * Gets the value last set by the calling thread, or def if no such value
2020 * The stored value or def if no value is stored.
2024 Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
2026 return wrap ? wrap.val : m_def;
2031 * Copies newval to a location specific to the calling thread, and returns
2035 * newval = The value to set.
2038 * The value passed to this function.
2042 Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
2047 Thread.setLocal( m_key, wrap );
2056 // A wrapper for the stored data. This is needed for determining whether
2057 // set has ever been called for this thread (and therefore whether the
2058 // default value should be returned) and also to flatten the differences
2059 // between data that is smaller and larger than (void*).sizeof. The
2060 // obvious tradeoff here is an extra per-thread allocation for each
2061 // ThreadLocal value as compared to calling the Thread routines directly.
2074 ///////////////////////////////////////////////////////////////////////////////
2076 ///////////////////////////////////////////////////////////////////////////////
2080 * This class is intended to simplify certain common programming techniques.
2085 * Creates and starts a new Thread object that executes fn and adds it to
2086 * the list of tracked threads.
2089 * fn = The thread function.
2092 * A reference to the newly created thread.
2094 final Thread create( void function() fn )
2096 Thread t = new Thread( fn );
2099 synchronized( this )
2108 * Creates and starts a new Thread object that executes dg and adds it to
2109 * the list of tracked threads.
2112 * dg = The thread function.
2115 * A reference to the newly created thread.
2117 final Thread create( void delegate() dg )
2119 Thread t = new Thread( dg );
2122 synchronized( this )
2131 * Add t to the list of tracked threads if it is not already being tracked.
2134 * t = The thread to add.
2137 * t must not be null.
2139 final void add( Thread t )
2146 synchronized( this )
2154 * Removes t from the list of tracked threads. No operation will be
2155 * performed if t is not currently being tracked by this object.
2158 * t = The thread to remove.
2161 * t must not be null.
2163 final void remove( Thread t )
2170 synchronized( this )
2178 * Operates on all threads currently tracked by this object.
2180 final int opApply( int delegate( inout Thread ) dg )
2182 synchronized( this )
2186 // NOTE: This loop relies on the knowledge that m_all uses the
2187 // Thread object for both the key and the mapped value.
2188 foreach( Thread t; m_all.keys )
2200 * Iteratively joins all tracked threads. This function will block add,
2201 * remove, and opApply until it completes.
2204 * rethrow = Rethrow any unhandled exception which may have caused the
2205 * current thread to terminate.
2208 * Any exception not handled by the joined threads.
2210 final void joinAll( bool rethrow = true )
2212 synchronized( this )
2214 // NOTE: This loop relies on the knowledge that m_all uses the
2215 // Thread object for both the key and the mapped value.
2216 foreach( Thread t; m_all.keys )
2225 Thread[Thread] m_all;
2229 ///////////////////////////////////////////////////////////////////////////////
2230 // Fiber Platform Detection and Memory Allocation
2231 ///////////////////////////////////////////////////////////////////////////////
2236 version( D_InlineAsm_X86 )
2245 version = AsmX86_Win32;
2246 else version( Posix )
2247 version = AsmX86_Posix;
2253 version = AsmPPC_Posix;
2259 import stdc.posix.unistd; // for sysconf
2260 import stdc.posix.sys.mman; // for mmap
2261 import stdc.posix.stdlib; // for malloc, valloc, free
2263 version( AsmX86_Win32 ) {} else
2264 version( AsmX86_Posix ) {} else
2265 version( AsmPPC_Posix ) {} else
2267 // NOTE: The ucontext implementation requires architecture specific
2268 // data definitions to operate so testing for it must be done
2269 // by checking for the existence of ucontext_t rather than by
2270 // a version identifier. Please note that this is considered
2271 // an obsolescent feature according to the POSIX spec, so a
2272 // custom solution is still preferred.
2273 import stdc.posix.ucontext;
2277 const size_t PAGESIZE;
2283 static if( is( typeof( GetSystemInfo ) ) )
2286 GetSystemInfo( &info );
2288 PAGESIZE = info.dwPageSize;
2289 assert( PAGESIZE < int.max );
2291 else static if( is( typeof( sysconf ) ) &&
2292 is( typeof( _SC_PAGESIZE ) ) )
2294 PAGESIZE = cast(size_t) sysconf( _SC_PAGESIZE );
2295 assert( PAGESIZE < int.max );
2307 ///////////////////////////////////////////////////////////////////////////////
2308 // Fiber Entry Point and Context Switch
2309 ///////////////////////////////////////////////////////////////////////////////
2314 extern (C) void fiber_entryPoint()
2316 Fiber obj = Fiber.getThis();
2319 assert( Thread.getThis().m_curr is obj.m_ctxt );
2320 volatile Thread.getThis().m_lock = false;
2321 obj.m_ctxt.tstack = obj.m_ctxt.bstack;
2322 obj.m_state = Fiber.State.EXEC;
2330 obj.m_unhandled = o;
2333 static if( is( ucontext_t ) )
2334 obj.m_ucur = &obj.m_utxt;
2336 obj.m_state = Fiber.State.TERM;
2341 // NOTE: If AsmPPC_Posix is defined then the context switch routine will
2342 // be defined externally until GDC supports inline PPC ASM.
2343 version( AsmPPC_Posix )
2344 extern (C) void fiber_switchContext( void** oldp, void* newp );
2346 extern (C) void fiber_switchContext( void** oldp, void* newp )
2348 // NOTE: The data pushed and popped in this routine must match the
2349 // default stack created by Fiber.initStack or the initial
2350 // switch into a new context will fail.
2352 version( AsmX86_Win32 )
2358 // save current stack state
2362 push dword ptr FS:[0];
2363 push dword ptr FS:[4];
2364 push dword ptr FS:[8];
2369 // store oldp again with more accurate address
2370 mov EAX, dword ptr 8[EBP];
2372 // load newp to begin context switch
2373 mov ESP, dword ptr 12[EBP];
2375 // load saved state from new stack
2379 pop dword ptr FS:[8];
2380 pop dword ptr FS:[4];
2381 pop dword ptr FS:[0];
2385 // 'return' to complete switch
2389 else version( AsmX86_Posix )
2395 // save current stack state
2403 // store oldp again with more accurate address
2404 mov EAX, dword ptr 8[EBP];
2406 // load newp to begin context switch
2407 mov ESP, dword ptr 12[EBP];
2409 // load saved state from new stack
2416 // 'return' to complete switch
2420 else static if( is( ucontext_t ) )
2422 Fiber cfib = Fiber.getThis();
2423 void* ucur = cfib.m_ucur;
2426 swapcontext( **(cast(ucontext_t***) oldp),
2427 *(cast(ucontext_t**) newp) );
2433 ///////////////////////////////////////////////////////////////////////////////
2435 ///////////////////////////////////////////////////////////////////////////////
2439 * This class provides a cooperative concurrency mechanism integrated with the
2440 * threading and garbage collection functionality. Calling a fiber may be
2441 * considered a blocking operation that returns when the fiber yields (via
2442 * Fiber.yield()). Execution occurs within the context of the calling thread
2443 * so synchronization is not necessary to guarantee memory visibility so long
2444 * as the same thread calls the fiber each time. Please note that there is no
2445 * requirement that a fiber be bound to one specific thread. Rather, fibers
2446 * may be freely passed between threads so long as they are not currently
2447 * executing. Like threads, a new fiber thread may be created using either
2448 * derivation or composition, as in the following example.
2451 * ----------------------------------------------------------------------
2453 * class DerivedFiber : Fiber
2463 * printf( "Derived fiber running.\n" );
2469 * printf( "Composed fiber running.\n" );
2471 * printf( "Composed fiber running.\n" );
2474 * // create instances of each type
2475 * Fiber derived = new DerivedFiber();
2476 * Fiber composed = new Fiber( &fiberFunc );
2478 * // call both fibers once
2481 * printf( "Execution returned to calling context.\n" );
2484 * // since each fiber has run to completion, each should have state TERM
2485 * assert( derived.state == Fiber.State.TERM );
2486 * assert( composed.state == Fiber.State.TERM );
2488 * ----------------------------------------------------------------------
2490 * Authors: Based on a design by Mikola Lysenko.
2494 ///////////////////////////////////////////////////////////////////////////
2496 ///////////////////////////////////////////////////////////////////////////
2500 * Initializes a fiber object which is associated with a static
2504 * fn = The thread function.
2505 * sz = The stack size for this fiber.
2508 * fn must not be null.
2510 this( void function() fn, size_t sz = PAGESIZE )
2519 m_state = State.HOLD;
2526 * Initializes a fiber object which is associated with a dynamic
2530 * dg = The thread function.
2531 * sz = The stack size for this fiber.
2534 * dg must not be null.
2536 this( void delegate() dg, size_t sz = PAGESIZE )
2545 m_state = State.HOLD;
2552 * Cleans up any remaining resources used by this object.
2556 // NOTE: A live reference to this object will exist on its associated
2557 // stack from the first time its call() method has been called
2558 // until its execution completes with State.TERM. Thus, the only
2559 // times this dtor should be called are either if the fiber has
2560 // terminated (and therefore has no active stack) or if the user
2561 // explicitly deletes this object. The latter case is an error
2562 // but is not easily tested for, since State.HOLD may imply that
2563 // the fiber was just created but has never been run. There is
2564 // not a compelling case to create a State.INIT just to offer a
2565 // means of ensuring the user isn't violating this object's
2566 // contract, so for now this requirement will be enforced by
2567 // documentation only.
2572 ///////////////////////////////////////////////////////////////////////////
2574 ///////////////////////////////////////////////////////////////////////////
2578 * Transfers execution to this fiber object. The calling context will be
2579 * suspended until the fiber calls Fiber.yield() or until it terminates
2580 * via an unhandled exception.
2583 * rethrow = Rethrow any unhandled exception which may have caused this
2584 * fiber to terminate.
2587 * This fiber must be in state HOLD.
2590 * Any exception not handled by the joined thread.
2593 * Any exception not handled by this fiber if rethrow = false, null
2596 final Object call( bool rethrow = true )
2599 assert( m_state == State.HOLD );
2603 Fiber cur = getThis();
2605 static if( is( ucontext_t ) )
2606 m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt;
2612 static if( is( ucontext_t ) )
2615 // NOTE: If the fiber has terminated then the stack pointers must be
2616 // reset. This ensures that the stack for this fiber is not
2617 // scanned if the fiber has terminated. This is necessary to
2618 // prevent any references lingering on the stack from delaying
2619 // the collection of otherwise dead objects. The most notable
2620 // being the current object, which is referenced at the top of
2621 // fiber_entryPoint.
2622 if( m_state == State.TERM )
2624 m_ctxt.tstack = m_ctxt.bstack;
2628 Object obj = m_unhandled;
2639 * Resets this fiber so that it may be re-used. This routine may only be
2640 * called for fibers that have terminated, as doing otherwise could result
2641 * in scope-dependent functionality that is not executed. Stack-based
2642 * classes, for example, may not be cleaned up properly if a fiber is reset
2643 * before it has terminated.
2646 * This fiber must be in state TERM.
2651 assert( m_state == State.TERM );
2652 assert( m_ctxt.tstack == m_ctxt.bstack );
2656 m_state = State.HOLD;
2662 ///////////////////////////////////////////////////////////////////////////
2663 // General Properties
2664 ///////////////////////////////////////////////////////////////////////////
2668 * A fiber may occupy one of three states: HOLD, EXEC, and TERM. The HOLD
2669 * state applies to any fiber that is suspended and ready to be called.
2670 * The EXEC state will be set for any fiber that is currently executing.
2671 * And the TERM state is set when a fiber terminates. Once a fiber
2672 * terminates, it must be reset before it may be called again.
2683 * Gets the current state of this fiber.
2686 * The state of this fiber as an enumerated value.
2694 ///////////////////////////////////////////////////////////////////////////
2695 // Actions on Calling Fiber
2696 ///////////////////////////////////////////////////////////////////////////
2700 * Forces a context switch to occur away from the calling fiber.
2704 Fiber cur = getThis();
2705 assert( cur, "Fiber.yield() called with no active fiber" );
2706 assert( cur.m_state == State.EXEC );
2708 static if( is( ucontext_t ) )
2709 cur.m_ucur = &cur.m_utxt;
2711 cur.m_state = State.HOLD;
2713 cur.m_state = State.EXEC;
2718 * Forces a context switch to occur away from the calling fiber and then
2719 * throws obj in the calling fiber.
2722 * obj = The object to throw.
2725 * obj must not be null.
2727 static void yieldAndThrow( Object obj )
2734 Fiber cur = getThis();
2735 assert( cur, "Fiber.yield() called with no active fiber" );
2736 assert( cur.m_state == State.EXEC );
2738 static if( is( ucontext_t ) )
2739 cur.m_ucur = &cur.m_utxt;
2741 cur.m_unhandled = obj;
2742 cur.m_state = State.HOLD;
2744 cur.m_state = State.EXEC;
2748 ///////////////////////////////////////////////////////////////////////////
2750 ///////////////////////////////////////////////////////////////////////////
2754 * Provides a reference to the calling fiber or null if no fiber is
2758 * The fiber object representing the calling fiber or null if no fiber
2759 * is currently active. The result of deleting this object is undefined.
2761 static Fiber getThis()
2765 return cast(Fiber) TlsGetValue( sm_this );
2767 else version( Posix )
2769 return cast(Fiber) pthread_getspecific( sm_this );
2774 ///////////////////////////////////////////////////////////////////////////
2775 // Static Initialization
2776 ///////////////////////////////////////////////////////////////////////////
2783 sm_this = TlsAlloc();
2784 assert( sm_this != TLS_OUT_OF_INDEXES );
2786 else version( Posix )
2790 status = pthread_key_create( &sm_this, null );
2791 assert( status == 0 );
2793 static if( is( ucontext_t ) )
2795 status = getcontext( &sm_utxt );
2796 assert( status == 0 );
2804 // Initializes a fiber object which has no associated executable function.
2813 // Fiber entry point. Invokes the function or delegate passed on
2814 // construction (if any).
2834 // The type of routine passed on fiber construction.
2845 // Standard fiber data
2850 void function() m_fn;
2851 void delegate() m_dg;
2859 ///////////////////////////////////////////////////////////////////////////
2861 ///////////////////////////////////////////////////////////////////////////
2865 // Allocate a new stack for this fiber.
2867 final void allocStack( size_t sz )
2870 assert( !m_pmem && !m_ctxt );
2874 // adjust alloc size to a multiple of PAGESIZE
2876 sz -= sz % PAGESIZE;
2878 // NOTE: This instance of Thread.Context is dynamic so Fiber objects
2879 // can be collected by the GC so long as no user level references
2880 // to the object exist. If m_ctxt were not dynamic then its
2881 // presence in the global context list would be enough to keep
2882 // this object alive indefinitely. An alternative to allocating
2883 // room for this struct explicitly would be to mash it into the
2884 // base of the stack being allocated below. However, doing so
2885 // requires too much special logic to be worthwhile.
2886 m_ctxt = new Thread.Context;
2888 static if( is( typeof( VirtualAlloc ) ) )
2890 // reserve memory for stack
2891 m_pmem = VirtualAlloc( null,
2897 throw new FiberException( "Unable to reserve memory for stack" );
2900 version( StackGrowsDown )
2902 void* stack = m_pmem + PAGESIZE;
2903 void* guard = m_pmem;
2904 void* pbase = stack + sz;
2908 void* stack = m_pmem;
2909 void* guard = m_pmem + sz;
2910 void* pbase = stack;
2913 // allocate reserved stack segment
2914 stack = VirtualAlloc( stack,
2920 throw new FiberException( "Unable to allocate memory for stack" );
2923 // allocate reserved guard page
2924 guard = VirtualAlloc( guard,
2927 PAGE_READWRITE | PAGE_GUARD );
2930 throw new FiberException( "Unable to create guard page for stack" );
2933 m_ctxt.bstack = pbase;
2934 m_ctxt.tstack = pbase;
2938 { static if( is( typeof( mmap ) ) )
2940 m_pmem = mmap( null,
2942 PROT_READ | PROT_WRITE,
2943 MAP_PRIVATE | MAP_ANON,
2946 if( m_pmem == MAP_FAILED )
2949 else static if( is( typeof( valloc ) ) )
2951 m_pmem = valloc( sz );
2953 else static if( is( typeof( malloc ) ) )
2955 m_pmem = malloc( sz );
2964 throw new FiberException( "Unable to allocate memory for stack" );
2967 version( StackGrowsDown )
2969 m_ctxt.bstack = m_pmem + sz;
2970 m_ctxt.tstack = m_pmem + sz;
2974 m_ctxt.bstack = m_pmem;
2975 m_ctxt.tstack = m_pmem;
2980 Thread.add( m_ctxt );
2985 // Free this fiber's stack.
2987 final void freeStack()
2990 assert( m_pmem && m_ctxt );
2994 // NOTE: Since this routine is only ever expected to be called from
2995 // the dtor, pointers to freed data are not set to null.
2997 // NOTE: m_ctxt is guaranteed to be alive because it is held in the
2998 // global context list.
2999 Thread.remove( m_ctxt );
3001 static if( is( typeof( VirtualAlloc ) ) )
3003 VirtualFree( m_pmem, 0, MEM_RELEASE );
3005 else static if( is( typeof( mmap ) ) )
3007 munmap( m_pmem, m_size );
3009 else static if( is( typeof( valloc ) ) )
3013 else static if( is( typeof( malloc ) ) )
3022 // Initialize the allocated stack.
3024 final void initStack()
3027 assert( m_ctxt.tstack && m_ctxt.tstack == m_ctxt.bstack );
3028 assert( cast(size_t) m_ctxt.bstack % (void*).sizeof == 0 );
3032 void* pstack = m_ctxt.tstack;
3033 scope( exit ) m_ctxt.tstack = pstack;
3035 void push( size_t val )
3037 version( StackGrowsDown )
3039 pstack -= size_t.sizeof;
3040 *(cast(size_t*) pstack) = val;
3044 pstack += size_t.sizeof;
3045 *(cast(size_t*) pstack) = val;
3049 // NOTE: On OS X the stack must be 16-byte aligned according to the
3053 pstack = cast(void*)(cast(uint)(pstack) - (cast(uint)(pstack) & 0x0F));
3056 version( AsmX86_Win32 )
3058 push( cast(size_t) &fiber_entryPoint ); // EIP
3059 push( 0xFFFFFFFF ); // EBP
3060 push( 0x00000000 ); // EAX
3061 push( 0xFFFFFFFF ); // FS:[0]
3062 version( StackGrowsDown )
3064 push( cast(size_t) m_ctxt.bstack ); // FS:[4]
3065 push( cast(size_t) m_ctxt.bstack - m_size ); // FS:[8]
3069 push( cast(size_t) m_ctxt.bstack ); // FS:[4]
3070 push( cast(size_t) m_ctxt.bstack + m_size ); // FS:[8]
3072 push( 0x00000000 ); // EBX
3073 push( 0x00000000 ); // ESI
3074 push( 0x00000000 ); // EDI
3076 else version( AsmX86_Posix )
3078 push( cast(size_t) &fiber_entryPoint ); // EIP
3079 push( 0x00000000 ); // EBP
3080 push( 0x00000000 ); // EAX
3081 push( 0x00000000 ); // EBX
3082 push( 0x00000000 ); // ESI
3083 push( 0x00000000 ); // EDI
3085 else version( AsmPPC_Posix )
3087 version( StackGrowsDown )
3089 pstack -= int.sizeof * 5;
3093 pstack += int.sizeof * 5;
3096 push( cast(size_t) &fiber_entryPoint ); // link register
3097 push( 0x00000000 ); // control register
3098 push( 0x00000000 ); // old stack pointer
3101 version( StackGrowsDown )
3103 pstack -= int.sizeof * 20;
3107 pstack += int.sizeof * 20;
3110 assert( cast(uint) pstack & 0x0f == 0 );
3112 else static if( is( ucontext_t ) )
3114 getcontext( &m_utxt );
3115 m_utxt.uc_stack.ss_sp = m_ctxt.bstack;
3116 m_utxt.uc_stack.ss_size = m_size;
3117 makecontext( &m_utxt, &fiber_entryPoint, 0 );
3118 // NOTE: If ucontext is being used then the top of the stack will
3119 // be a pointer to the ucontext_t struct for that fiber.
3120 push( cast(size_t) &m_utxt );
3125 Thread.Context* m_ctxt;
3129 static if( is( ucontext_t ) )
3131 // NOTE: The static ucontext instance is used to represent the context
3132 // of the main application thread.
3133 static ucontext_t sm_utxt = void;
3134 ucontext_t m_utxt = void;
3135 ucontext_t* m_ucur = null;
3140 ///////////////////////////////////////////////////////////////////////////
3141 // Storage of Active Fiber
3142 ///////////////////////////////////////////////////////////////////////////
3146 // Sets a thread-local reference to the current fiber object.
3148 static void setThis( Fiber f )
3152 TlsSetValue( sm_this, cast(void*) f );
3154 else version( Posix )
3156 pthread_setspecific( sm_this, cast(void*) f );
3161 static Thread.TLSKey sm_this;
3165 ///////////////////////////////////////////////////////////////////////////
3166 // Context Switching
3167 ///////////////////////////////////////////////////////////////////////////
3171 // Switches into the stack held by this fiber.
3173 final void switchIn()
3175 Thread tobj = Thread.getThis();
3176 void** oldp = &tobj.m_curr.tstack;
3177 void* newp = m_ctxt.tstack;
3179 // NOTE: The order of operations here is very important. The current
3180 // stack top must be stored before m_lock is set, and pushContext
3181 // must not be called until after m_lock is set. This process
3182 // is intended to prevent a race condition with the suspend
3183 // mechanism used for garbage collection. If it is not followed,
3184 // a badly timed collection could cause the GC to scan from the
3185 // bottom of one stack to the top of another, or to miss scanning
3186 // a stack that still contains valid data. The old stack pointer
3187 // oldp will be set again before the context switch to guarantee
3188 // that it points to exactly the correct stack location so the
3189 // successive pop operations will succeed.
3190 *oldp = getStackTop();
3191 volatile tobj.m_lock = true;
3192 tobj.pushContext( m_ctxt );
3194 fiber_switchContext( oldp, newp );
3196 // NOTE: As above, these operations must be performed in a strict order
3197 // to prevent Bad Things from happening.
3199 volatile tobj.m_lock = false;
3200 tobj.m_curr.tstack = tobj.m_curr.bstack;
3205 // Switches out of the current stack and into the enclosing stack.
3207 final void switchOut()
3209 Thread tobj = Thread.getThis();
3210 void** oldp = &m_ctxt.tstack;
3211 void* newp = tobj.m_curr.within.tstack;
3213 // NOTE: The order of operations here is very important. The current
3214 // stack top must be stored before m_lock is set, and pushContext
3215 // must not be called until after m_lock is set. This process
3216 // is intended to prevent a race condition with the suspend
3217 // mechanism used for garbage collection. If it is not followed,
3218 // a badly timed collection could cause the GC to scan from the
3219 // bottom of one stack to the top of another, or to miss scanning
3220 // a stack that still contains valid data. The old stack pointer
3221 // oldp will be set again before the context switch to guarantee
3222 // that it points to exactly the correct stack location so the
3223 // successive pop operations will succeed.
3224 *oldp = getStackTop();
3225 volatile tobj.m_lock = true;
3227 fiber_switchContext( oldp, newp );
3229 // NOTE: As above, these operations must be performed in a strict order
3230 // to prevent Bad Things from happening.
3231 volatile tobj.m_lock = false;
3232 tobj.m_curr.tstack = tobj.m_curr.bstack;