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 Windows but it should be followed for the
115 // sake of consistency).
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 Windows but it should be followed for the
247 // sake of consistency).
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( Windows ) {} 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_000 ); // 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 // NOTE: In instances where all other threads in the process have a
829 // lower priority than the current thread, the current thread
830 // will not yield with a sleep time of zero. However, unlike
831 // yield(), the user is not asking for a yield to occur but
832 // only for execution to suspend for the requested interval.
833 // Therefore, expected performance may not be met if a yield
834 // is forced upon the user.
835 period /= TICKS_PER_MILLI;
836 while( period > MAX_SLEEP_MILLIS )
838 Sleep( MAX_SLEEP_MILLIS );
839 period -= MAX_SLEEP_MILLIS;
841 Sleep( cast(uint) period );
843 else version( Posix )
846 timespec tout = void;
850 NANOS_PER_TICK = 100,
851 TICKS_PER_SECOND = 10_000_000,
853 enum : typeof(period)
855 MAX_SLEEP_TICKS = cast(typeof(period)) tin.tv_sec.max * TICKS_PER_SECOND
860 if( period > MAX_SLEEP_TICKS )
862 tin.tv_sec = tin.tv_sec.max;
867 tin.tv_sec = cast(typeof(tin.tv_sec)) (period / TICKS_PER_SECOND);
868 tin.tv_nsec = cast(typeof(tin.tv_nsec)) (period % TICKS_PER_SECOND) * NANOS_PER_TICK;
872 if( !nanosleep( &tin, &tout ) )
874 if( getErrno() != EINTR )
875 throw new ThreadException( "Unable to sleep for the specified duration" );
878 period -= (cast(typeof(period)) tin.tv_sec) * TICKS_PER_SECOND;
879 period -= (cast(typeof(period)) tin.tv_nsec) / NANOS_PER_TICK;
880 } while( period > 0 );
886 * Forces a context switch to occur away from the calling thread.
892 // NOTE: Sleep(1) is necessary because Sleep(0) does not give
893 // lower priority threads any timeslice, so looping on
894 // Sleep(0) could be resource-intensive in some cases.
897 else version( Posix )
904 ///////////////////////////////////////////////////////////////////////////
906 ///////////////////////////////////////////////////////////////////////////
910 * Provides a reference to the calling thread.
913 * The thread object representing the calling thread. The result of
914 * deleting this object is undefined.
916 static Thread getThis()
918 // NOTE: This function may not be called until thread_init has
919 // completed. See thread_suspendAll for more information
920 // on why this might occur.
923 return cast(Thread) TlsGetValue( sm_this );
925 else version( Posix )
927 return cast(Thread) pthread_getspecific( sm_this );
933 * Provides a list of all threads currently being tracked by the system.
936 * An array containing references to all threads currently being
937 * tracked by the system. The result of deleting any contained
938 * objects is undefined.
940 static Thread[] getAll()
942 synchronized( slock )
945 Thread[] buf = new Thread[sm_tlen];
947 foreach( Thread t; Thread )
957 * Operates on all threads currently being tracked by the system. The
958 * result of deleting any Thread object is undefined.
961 * dg = The supplied code as a delegate.
964 * Zero if all elemented are visited, nonzero if not.
966 static int opApply( int delegate( inout Thread ) dg )
968 synchronized( slock )
972 for( Thread t = sm_tbeg; t; t = t.next )
983 ///////////////////////////////////////////////////////////////////////////
984 // Local Storage Actions
985 ///////////////////////////////////////////////////////////////////////////
989 * Indicates the number of local storage pointers available at program
990 * startup. It is recommended that this number be at least 64.
992 static const uint LOCAL_MAX = 64;
996 * Reserves a local storage pointer for use and initializes this location
997 * to null for all running threads.
1000 * A key representing the array offset of this memory location.
1002 static uint createLocal()
1004 synchronized( slock )
1006 foreach( uint key, inout bool set; sm_local )
1010 //foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
1011 for( Thread t = sm_tbeg; t; t = t.next )
1013 t.m_local[key] = null;
1019 throw new ThreadException( "No more local storage slots available" );
1025 * Marks the supplied key as available and sets the associated location
1026 * to null for all running threads. It is assumed that any key passed
1027 * to this function is valid. The result of calling this function for
1028 * a key which is still in use is undefined.
1031 * key = The key to delete.
1033 static void deleteLocal( uint key )
1035 synchronized( slock )
1037 sm_local[key] = false;
1038 // foreach( Thread t; sm_tbeg ) Bug in GDC 0.24 SVN (r139)
1039 for( Thread t = sm_tbeg; t; t = t.next )
1041 t.m_local[key] = null;
1048 * Loads the value stored at key within a thread-local static array. It is
1049 * assumed that any key passed to this function is valid.
1052 * key = The location which holds the desired data.
1055 * The data associated with the supplied key.
1057 static void* getLocal( uint key )
1059 return getThis().m_local[key];
1064 * Stores the supplied value at key within a thread-local static array. It
1065 * is assumed that any key passed to this function is valid.
1068 * key = The location to store the supplied data.
1069 * val = The data to store.
1072 * A copy of the data which has just been stored.
1074 static void* setLocal( uint key, void* val )
1076 return getThis().m_local[key] = val;
1080 ///////////////////////////////////////////////////////////////////////////
1081 // Static Initalizer
1082 ///////////////////////////////////////////////////////////////////////////
1086 * This initializer is used to set thread constants. All functional
1087 * initialization occurs within thread_init().
1096 else version( Posix )
1100 pthread_t self = pthread_self();
1102 int status = pthread_getschedparam( self, &policy, ¶m );
1103 assert( status == 0 );
1105 PRIORITY_MIN = sched_get_priority_min( policy );
1106 assert( PRIORITY_MIN != -1 );
1108 PRIORITY_MAX = sched_get_priority_max( policy );
1109 assert( PRIORITY_MAX != -1 );
1116 // Initializes a thread object which has no associated executable function.
1117 // This is used for the main thread initialized in thread_init().
1127 // Thread entry point. Invokes the function or delegate passed on
1128 // construction (if any).
1148 // The type of routine passed on thread construction.
1164 alias uint ThreadAddr;
1166 else version( Posix )
1168 alias pthread_key_t TLSKey;
1169 alias pthread_t ThreadAddr;
1176 static bool[LOCAL_MAX] sm_local;
1177 static TLSKey sm_this;
1179 void*[LOCAL_MAX] m_local;
1183 // Standard thread data
1194 void function() m_fn;
1195 void delegate() m_dg;
1207 ///////////////////////////////////////////////////////////////////////////
1208 // Storage of Active Thread
1209 ///////////////////////////////////////////////////////////////////////////
1213 // Sets a thread-local reference to the current thread object.
1215 static void setThis( Thread t )
1219 TlsSetValue( sm_this, cast(void*) t );
1221 else version( Posix )
1223 pthread_setspecific( sm_this, cast(void*) t );
1229 ///////////////////////////////////////////////////////////////////////////
1230 // Thread Context and GC Scanning Support
1231 ///////////////////////////////////////////////////////////////////////////
1234 final void pushContext( Context* c )
1237 assert( !c.within );
1246 final void popContext()
1249 assert( m_curr && m_curr.within );
1253 Context* c = m_curr;
1259 final Context* topContext()
1270 static struct Context
1286 uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
1291 ///////////////////////////////////////////////////////////////////////////
1292 // GC Scanning Support
1293 ///////////////////////////////////////////////////////////////////////////
1296 // NOTE: The GC scanning process works like so:
1298 // 1. Suspend all threads.
1299 // 2. Scan the stacks of all suspended threads for roots.
1300 // 3. Resume all threads.
1302 // Step 1 and 3 require a list of all threads in the system, while
1303 // step 2 requires a list of all thread stacks (each represented by
1304 // a Context struct). Traditionally, there was one stack per thread
1305 // and the Context structs were not necessary. However, Fibers have
1306 // changed things so that each thread has its own 'main' stack plus
1307 // an arbitrary number of nested stacks (normally referenced via
1308 // m_curr). Also, there may be 'free-floating' stacks in the system,
1309 // which are Fibers that are not currently executing on any specific
1310 // thread but are still being processed and still contain valid
1313 // To support all of this, the Context struct has been created to
1314 // represent a stack range, and a global list of Context structs has
1315 // been added to enable scanning of these stack ranges. The lifetime
1316 // (and presence in the Context list) of a thread's 'main' stack will
1317 // be equivalent to the thread's lifetime. So the Ccontext will be
1318 // added to the list on thread entry, and removed from the list on
1319 // thread exit (which is essentially the same as the presence of a
1320 // Thread object in its own global list). The lifetime of a Fiber's
1321 // context, however, will be tied to the lifetime of the Fiber object
1322 // itself, and Fibers are expected to add/remove their Context struct
1323 // on construction/deletion.
1327 // All use of the global lists should synchronize on this lock.
1329 static Object slock()
1331 return Thread.classinfo;
1335 static Context* sm_cbeg;
1336 static size_t sm_clen;
1338 static Thread sm_tbeg;
1339 static size_t sm_tlen;
1342 // Used for ordering threads in the global thread list.
1348 ///////////////////////////////////////////////////////////////////////////
1349 // Global Context List Operations
1350 ///////////////////////////////////////////////////////////////////////////
1354 // Add a context to the global context list.
1356 static void add( Context* c )
1360 assert( !c.next && !c.prev );
1364 synchronized( slock )
1378 // Remove a context from the global context list.
1380 static void remove( Context* c )
1384 assert( c.next || c.prev );
1388 synchronized( slock )
1391 c.prev.next = c.next;
1393 c.next.prev = c.prev;
1398 // NOTE: Don't null out c.next or c.prev because opApply currently
1399 // follows c.next after removing a node. This could be easily
1400 // addressed by simply returning the next node from this
1401 // function, however, a context should never be re-added to the
1402 // list anyway and having next and prev be non-null is a good way
1407 ///////////////////////////////////////////////////////////////////////////
1408 // Global Thread List Operations
1409 ///////////////////////////////////////////////////////////////////////////
1413 // Add a thread to the global thread list.
1415 static void add( Thread t )
1419 assert( !t.next && !t.prev );
1420 assert( t.isRunning );
1424 synchronized( slock )
1438 // Remove a thread from the global thread list.
1440 static void remove( Thread t )
1444 assert( t.next || t.prev );
1447 // NOTE: This doesn't work for Posix as m_isRunning must be set to
1448 // false after the thread is removed during normal execution.
1449 assert( !t.isRunning );
1454 synchronized( slock )
1456 // NOTE: When a thread is removed from the global thread list its
1457 // main context is invalid and should be removed as well.
1458 // It is possible that t.m_curr could reference more
1459 // than just the main context if the thread exited abnormally
1460 // (if it was terminated), but we must assume that the user
1461 // retains a reference to them and that they may be re-used
1462 // elsewhere. Therefore, it is the responsibility of any
1463 // object that creates contexts to clean them up properly
1464 // when it is done with them.
1465 remove( &t.m_main );
1468 t.prev.next = t.next;
1470 t.next.prev = t.prev;
1475 // NOTE: Don't null out t.next or t.prev because opApply currently
1476 // follows t.next after removing a node. This could be easily
1477 // addressed by simply returning the next node from this
1478 // function, however, a thread should never be re-added to the
1479 // list anyway and having next and prev be non-null is a good way
1485 ///////////////////////////////////////////////////////////////////////////////
1486 // GC Support Routines
1487 ///////////////////////////////////////////////////////////////////////////////
1491 * Initializes the thread module. This function must be called by the
1492 * garbage collector on startup and before any other thread routines
1495 extern (C) void thread_init()
1497 // NOTE: If thread_init itself performs any allocations then the thread
1498 // routines reserved for garbage collector use may be called while
1499 // thread_init is being processed. However, since no memory should
1500 // exist to be scanned at this point, it is sufficient for these
1501 // functions to detect the condition and return immediately.
1505 Thread.sm_this = TlsAlloc();
1506 assert( Thread.sm_this != TLS_OUT_OF_INDEXES );
1508 else version( Posix )
1511 sigaction_t sigusr1 = void;
1512 sigaction_t sigusr2 = void;
1514 // This is a quick way to zero-initialize the structs without using
1515 // memset or creating a link dependency on their static initializer.
1516 (cast(byte*) &sigusr1)[0 .. sigaction_t.sizeof] = 0;
1517 (cast(byte*) &sigusr2)[0 .. sigaction_t.sizeof] = 0;
1519 // NOTE: SA_RESTART indicates that system calls should restart if they
1520 // are interrupted by a signal, but this is not available on all
1521 // Posix systems, even those that support multithreading.
1522 static if( is( typeof( SA_RESTART ) ) )
1523 sigusr1.sa_flags = SA_RESTART;
1525 sigusr1.sa_flags = 0;
1526 sigusr1.sa_handler = &thread_suspendHandler;
1527 // NOTE: We want to ignore all signals while in this handler, so fill
1528 // sa_mask to indicate this.
1529 status = sigfillset( &sigusr1.sa_mask );
1530 assert( status == 0 );
1532 // NOTE: Since SIGUSR2 should only be issued for threads within the
1533 // suspend handler, we don't want this signal to trigger a
1535 sigusr2.sa_flags = 0;
1536 sigusr2.sa_handler = &thread_resumeHandler;
1537 // NOTE: We want to ignore all signals while in this handler, so fill
1538 // sa_mask to indicate this.
1539 status = sigfillset( &sigusr2.sa_mask );
1540 assert( status == 0 );
1542 status = sigaction( SIGUSR1, &sigusr1, null );
1543 assert( status == 0 );
1545 status = sigaction( SIGUSR2, &sigusr2, null );
1546 assert( status == 0 );
1548 status = sem_init( &suspendCount, 0, 0 );
1549 assert( status == 0 );
1551 status = pthread_key_create( &Thread.sm_this, null );
1552 assert( status == 0 );
1555 thread_attachThis();
1560 * Registers the calling thread for use with the D Runtime. If this routine
1561 * is called for a thread which is already registered, the result is undefined.
1563 extern (C) void thread_attachThis()
1567 Thread thisThread = new Thread();
1568 Thread.Context* thisContext = &thisThread.m_main;
1569 assert( thisContext == thisThread.m_curr );
1571 thisThread.m_addr = GetCurrentThreadId();
1572 thisThread.m_hndl = GetCurrentThreadHandle();
1573 thisContext.bstack = getStackBottom();
1574 thisContext.tstack = thisContext.bstack;
1576 thisThread.m_isDaemon = true;
1578 Thread.setThis( thisThread );
1580 else version( Posix )
1582 Thread thisThread = new Thread();
1583 Thread.Context* thisContext = thisThread.m_curr;
1584 assert( thisContext == &thisThread.m_main );
1586 thisThread.m_addr = pthread_self();
1587 thisContext.bstack = getStackBottom();
1588 thisContext.tstack = thisContext.bstack;
1590 thisThread.m_isRunning = true;
1591 thisThread.m_isDaemon = true;
1593 Thread.setThis( thisThread );
1596 Thread.add( thisThread );
1597 Thread.add( thisContext );
1602 * Deregisters the calling thread from use with the runtime. If this routine
1603 * is called for a thread which is already registered, the result is undefined.
1605 extern (C) void thread_detachThis()
1607 Thread.remove( Thread.getThis() );
1612 * Joins all non-daemon threads that are currently running. This is done by
1613 * performing successive scans through the thread list until a scan consists
1614 * of only daemon threads.
1616 extern (C) void thread_joinAll()
1621 Thread nonDaemon = null;
1623 foreach( t; Thread )
1631 if( nonDaemon is null )
1639 * Performs intermediate shutdown of the thread module.
1643 // NOTE: The functionality related to garbage collection must be minimally
1644 // operable after this dtor completes. Therefore, only minimal
1645 // cleanup may occur.
1647 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1655 // Used for needLock below
1656 private bool multiThreadedFlag = false;
1660 * This function is used to determine whether the the process is
1661 * multi-threaded. Optimizations may only be performed on this
1662 * value if the programmer can guarantee that no path from the
1663 * enclosed code will start a thread.
1666 * True if Thread.start() has been called in this process.
1668 extern (C) bool thread_needLock()
1670 return multiThreadedFlag;
1674 // Used for suspendAll/resumeAll below
1675 private uint suspendDepth = 0;
1679 * Suspend all threads but the calling thread for "stop the world" garbage
1680 * collection runs. This function may be called multiple times, and must
1681 * be followed by a matching number of calls to thread_resumeAll before
1682 * processing is resumed.
1685 * ThreadException if the suspend operation fails for a running thread.
1687 extern (C) void thread_suspendAll()
1690 * Suspend the specified thread and load stack and register information for
1691 * use by thread_scanAll. If the supplied thread is the calling thread,
1692 * stack and register information will be loaded but the thread will not
1693 * be suspended. If the suspend operation fails and the thread is not
1694 * running then it will be removed from the global thread list, otherwise
1695 * an exception will be thrown.
1698 * t = The thread to suspend.
1701 * ThreadException if the suspend operation fails for a running thread.
1703 void suspend( Thread t )
1707 if( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF )
1714 throw new ThreadException( "Unable to suspend thread" );
1717 CONTEXT context = void;
1718 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
1720 if( !GetThreadContext( t.m_hndl, &context ) )
1721 throw new ThreadException( "Unable to load thread context" );
1723 t.m_curr.tstack = cast(void*) context.Esp;
1724 // edi,esi,ebp,esp,ebx,edx,ecx,eax
1725 t.m_reg[0] = context.Edi;
1726 t.m_reg[1] = context.Esi;
1727 t.m_reg[2] = context.Ebp;
1728 t.m_reg[3] = context.Esp;
1729 t.m_reg[4] = context.Ebx;
1730 t.m_reg[5] = context.Edx;
1731 t.m_reg[6] = context.Ecx;
1732 t.m_reg[7] = context.Eax;
1734 else version( Posix )
1736 if( t.m_addr != pthread_self() )
1738 if( pthread_kill( t.m_addr, SIGUSR1 ) != 0 )
1745 throw new ThreadException( "Unable to suspend thread" );
1747 // NOTE: It's really not ideal to wait for each thread to
1748 // signal individually -- rather, it would be better to
1749 // suspend them all and wait once at the end. However,
1750 // semaphores don't really work this way, and the obvious
1751 // alternative (looping on an atomic suspend count)
1752 // requires either the atomic module (which only works on
1753 // x86) or other specialized functionality. It would
1754 // also be possible to simply loop on sem_wait at the
1755 // end, but I'm not convinced that this would be much
1756 // faster than the current approach.
1757 sem_wait( &suspendCount );
1759 else if( !t.m_lock )
1761 t.m_curr.tstack = getStackTop();
1767 // NOTE: We've got an odd chicken & egg problem here, because while the GC
1768 // is required to call thread_init before calling any other thread
1769 // routines, thread_init may allocate memory which could in turn
1770 // trigger a collection. Thus, thread_suspendAll, thread_scanAll,
1771 // and thread_resumeAll must be callable before thread_init
1772 // completes, with the assumption that no other GC memory has yet
1773 // been allocated by the system, and thus there is no risk of losing
1774 // data if the global thread list is empty. The check of
1775 // Thread.sm_tbeg below is done to ensure thread_init has completed,
1776 // and therefore that calling Thread.getThis will not result in an
1777 // error. For the short time when Thread.sm_tbeg is null, there is
1778 // no reason not to simply call the multithreaded code below, with
1779 // the expectation that the foreach loop will never be entered.
1780 if( !multiThreadedFlag && Thread.sm_tbeg )
1782 if( ++suspendDepth == 1 )
1783 suspend( Thread.getThis() );
1786 synchronized( Thread.slock )
1788 if( ++suspendDepth > 1 )
1791 // NOTE: I'd really prefer not to check isRunning within this loop but
1792 // not doing so could be problematic if threads are termianted
1793 // abnormally and a new thread is created with the same thread
1794 // address before the next GC run. This situation might cause
1795 // the same thread to be suspended twice, which would likely
1796 // cause the second suspend to fail, the garbage collection to
1797 // abort, and Bad Things to occur.
1798 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1808 // wait on semaphore -- see note in suspend for
1809 // why this is currently not implemented
1816 * Resume all threads but the calling thread for "stop the world" garbage
1817 * collection runs. This function must be called once for each preceding
1818 * call to thread_suspendAll before the threads are actually resumed.
1821 * This routine must be preceded by a call to thread_suspendAll.
1824 * ThreadException if the resume operation fails for a running thread.
1826 extern (C) void thread_resumeAll()
1829 assert( suspendDepth > 0 );
1834 * Resume the specified thread and unload stack and register information.
1835 * If the supplied thread is the calling thread, stack and register
1836 * information will be unloaded but the thread will not be resumed. If
1837 * the resume operation fails and the thread is not running then it will
1838 * be removed from the global thread list, otherwise an exception will be
1842 * t = The thread to resume.
1845 * ThreadException if the resume fails for a running thread.
1847 void resume( Thread t )
1851 if( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF )
1858 throw new ThreadException( "Unable to resume thread" );
1862 t.m_curr.tstack = t.m_curr.bstack;
1863 t.m_reg[0 .. $] = 0;
1865 else version( Posix )
1867 if( t.m_addr != pthread_self() )
1869 if( pthread_kill( t.m_addr, SIGUSR2 ) != 0 )
1876 throw new ThreadException( "Unable to resume thread" );
1879 else if( !t.m_lock )
1881 t.m_curr.tstack = t.m_curr.bstack;
1887 // NOTE: See thread_suspendAll for the logic behind this.
1888 if( !multiThreadedFlag && Thread.sm_tbeg )
1890 if( --suspendDepth == 0 )
1891 resume( Thread.getThis() );
1894 synchronized( Thread.slock )
1896 if( --suspendDepth > 0 )
1899 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1907 private alias void delegate( void*, void* ) scanAllThreadsFn;
1911 * The main entry point for garbage collection. The supplied delegate
1912 * will be passed ranges representing both stack and register values.
1915 * scan = The scanner function. It should scan from p1 through p2 - 1.
1916 * curStackTop = An optional pointer to the top of the calling thread's stack.
1919 * This routine must be preceded by a call to thread_suspendAll.
1921 extern (C) void thread_scanAll( scanAllThreadsFn scan, void* curStackTop = null )
1924 assert( suspendDepth > 0 );
1928 Thread thisThread = null;
1929 void* oldStackTop = null;
1931 if( curStackTop && Thread.sm_tbeg )
1933 thisThread = Thread.getThis();
1934 if( !thisThread.m_lock )
1936 oldStackTop = thisThread.m_curr.tstack;
1937 thisThread.m_curr.tstack = curStackTop;
1943 if( curStackTop && Thread.sm_tbeg )
1945 if( !thisThread.m_lock )
1947 thisThread.m_curr.tstack = oldStackTop;
1952 // NOTE: Synchronizing on Thread.slock is not needed because this
1953 // function may only be called after all other threads have
1954 // been suspended from within the same lock.
1955 for( Thread.Context* c = Thread.sm_cbeg; c; c = c.next )
1957 version( StackGrowsDown )
1959 // NOTE: We can't index past the bottom of the stack
1960 // so don't do the "+1" for StackGrowsDown.
1961 if( c.tstack && c.tstack < c.bstack )
1962 scan( c.tstack, c.bstack );
1966 if( c.bstack && c.bstack < c.tstack )
1967 scan( c.bstack, c.tstack + 1 );
1972 for( Thread t = Thread.sm_tbeg; t; t = t.next )
1974 scan( &t.m_reg[0], &t.m_reg[0] + t.m_reg.length );
1980 ///////////////////////////////////////////////////////////////////////////////
1982 ///////////////////////////////////////////////////////////////////////////////
1986 * This class encapsulates the operations required to initialize, access, and
1987 * destroy thread local data.
1989 class ThreadLocal( T )
1991 ///////////////////////////////////////////////////////////////////////////
1993 ///////////////////////////////////////////////////////////////////////////
1997 * Initializes thread local storage for the indicated value which will be
1998 * initialized to def for all threads.
2001 * def = The default value to return if no value has been explicitly set.
2003 this( T def = T.init )
2006 m_key = Thread.createLocal();
2012 Thread.deleteLocal( m_key );
2016 ///////////////////////////////////////////////////////////////////////////
2018 ///////////////////////////////////////////////////////////////////////////
2022 * Gets the value last set by the calling thread, or def if no such value
2026 * The stored value or def if no value is stored.
2030 Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
2032 return wrap ? wrap.val : m_def;
2037 * Copies newval to a location specific to the calling thread, and returns
2041 * newval = The value to set.
2044 * The value passed to this function.
2048 Wrap* wrap = cast(Wrap*) Thread.getLocal( m_key );
2053 Thread.setLocal( m_key, wrap );
2062 // A wrapper for the stored data. This is needed for determining whether
2063 // set has ever been called for this thread (and therefore whether the
2064 // default value should be returned) and also to flatten the differences
2065 // between data that is smaller and larger than (void*).sizeof. The
2066 // obvious tradeoff here is an extra per-thread allocation for each
2067 // ThreadLocal value as compared to calling the Thread routines directly.
2080 ///////////////////////////////////////////////////////////////////////////////
2082 ///////////////////////////////////////////////////////////////////////////////
2086 * This class is intended to simplify certain common programming techniques.
2091 * Creates and starts a new Thread object that executes fn and adds it to
2092 * the list of tracked threads.
2095 * fn = The thread function.
2098 * A reference to the newly created thread.
2100 final Thread create( void function() fn )
2102 Thread t = new Thread( fn );
2105 synchronized( this )
2114 * Creates and starts a new Thread object that executes dg and adds it to
2115 * the list of tracked threads.
2118 * dg = The thread function.
2121 * A reference to the newly created thread.
2123 final Thread create( void delegate() dg )
2125 Thread t = new Thread( dg );
2128 synchronized( this )
2137 * Add t to the list of tracked threads if it is not already being tracked.
2140 * t = The thread to add.
2143 * t must not be null.
2145 final void add( Thread t )
2152 synchronized( this )
2160 * Removes t from the list of tracked threads. No operation will be
2161 * performed if t is not currently being tracked by this object.
2164 * t = The thread to remove.
2167 * t must not be null.
2169 final void remove( Thread t )
2176 synchronized( this )
2184 * Operates on all threads currently tracked by this object.
2186 final int opApply( int delegate( inout Thread ) dg )
2188 synchronized( this )
2192 // NOTE: This loop relies on the knowledge that m_all uses the
2193 // Thread object for both the key and the mapped value.
2194 foreach( Thread t; m_all.keys )
2206 * Iteratively joins all tracked threads. This function will block add,
2207 * remove, and opApply until it completes.
2210 * rethrow = Rethrow any unhandled exception which may have caused the
2211 * current thread to terminate.
2214 * Any exception not handled by the joined threads.
2216 final void joinAll( bool rethrow = true )
2218 synchronized( this )
2220 // NOTE: This loop relies on the knowledge that m_all uses the
2221 // Thread object for both the key and the mapped value.
2222 foreach( Thread t; m_all.keys )
2231 Thread[Thread] m_all;
2235 ///////////////////////////////////////////////////////////////////////////////
2236 // Fiber Platform Detection and Memory Allocation
2237 ///////////////////////////////////////////////////////////////////////////////
2242 version( D_InlineAsm_X86 )
2251 version = AsmX86_Win32;
2252 else version( Posix )
2253 version = AsmX86_Posix;
2259 version = AsmPPC_Posix;
2265 import core.sys.posix.unistd; // for sysconf
2266 import core.sys.posix.sys.mman; // for mmap
2267 import core.sys.posix.stdlib; // for malloc, valloc, free
2269 version( AsmX86_Win32 ) {} else
2270 version( AsmX86_Posix ) {} else
2271 version( AsmPPC_Posix ) {} else
2273 // NOTE: The ucontext implementation requires architecture specific
2274 // data definitions to operate so testing for it must be done
2275 // by checking for the existence of ucontext_t rather than by
2276 // a version identifier. Please note that this is considered
2277 // an obsolescent feature according to the POSIX spec, so a
2278 // custom solution is still preferred.
2279 import core.sys.posix.ucontext;
2283 const size_t PAGESIZE;
2289 static if( is( typeof( GetSystemInfo ) ) )
2292 GetSystemInfo( &info );
2294 PAGESIZE = info.dwPageSize;
2295 assert( PAGESIZE < int.max );
2297 else static if( is( typeof( sysconf ) ) &&
2298 is( typeof( _SC_PAGESIZE ) ) )
2300 PAGESIZE = cast(size_t) sysconf( _SC_PAGESIZE );
2301 assert( PAGESIZE < int.max );
2313 ///////////////////////////////////////////////////////////////////////////////
2314 // Fiber Entry Point and Context Switch
2315 ///////////////////////////////////////////////////////////////////////////////
2320 extern (C) void fiber_entryPoint()
2322 Fiber obj = Fiber.getThis();
2325 assert( Thread.getThis().m_curr is obj.m_ctxt );
2326 volatile Thread.getThis().m_lock = false;
2327 obj.m_ctxt.tstack = obj.m_ctxt.bstack;
2328 obj.m_state = Fiber.State.EXEC;
2336 obj.m_unhandled = o;
2339 static if( is( ucontext_t ) )
2340 obj.m_ucur = &obj.m_utxt;
2342 obj.m_state = Fiber.State.TERM;
2347 // NOTE: If AsmPPC_Posix is defined then the context switch routine will
2348 // be defined externally until GDC supports inline PPC ASM.
2349 version( AsmPPC_Posix )
2350 extern (C) void fiber_switchContext( void** oldp, void* newp );
2352 extern (C) void fiber_switchContext( void** oldp, void* newp )
2354 // NOTE: The data pushed and popped in this routine must match the
2355 // default stack created by Fiber.initStack or the initial
2356 // switch into a new context will fail.
2358 version( AsmX86_Win32 )
2364 // save current stack state
2368 push dword ptr FS:[0];
2369 push dword ptr FS:[4];
2370 push dword ptr FS:[8];
2375 // store oldp again with more accurate address
2376 mov EAX, dword ptr 8[EBP];
2378 // load newp to begin context switch
2379 mov ESP, dword ptr 12[EBP];
2381 // load saved state from new stack
2385 pop dword ptr FS:[8];
2386 pop dword ptr FS:[4];
2387 pop dword ptr FS:[0];
2391 // 'return' to complete switch
2395 else version( AsmX86_Posix )
2401 // save current stack state
2409 // store oldp again with more accurate address
2410 mov EAX, dword ptr 8[EBP];
2412 // load newp to begin context switch
2413 mov ESP, dword ptr 12[EBP];
2415 // load saved state from new stack
2422 // 'return' to complete switch
2426 else static if( is( ucontext_t ) )
2428 Fiber cfib = Fiber.getThis();
2429 void* ucur = cfib.m_ucur;
2432 swapcontext( **(cast(ucontext_t***) oldp),
2433 *(cast(ucontext_t**) newp) );
2439 ///////////////////////////////////////////////////////////////////////////////
2441 ///////////////////////////////////////////////////////////////////////////////
2445 * This class provides a cooperative concurrency mechanism integrated with the
2446 * threading and garbage collection functionality. Calling a fiber may be
2447 * considered a blocking operation that returns when the fiber yields (via
2448 * Fiber.yield()). Execution occurs within the context of the calling thread
2449 * so synchronization is not necessary to guarantee memory visibility so long
2450 * as the same thread calls the fiber each time. Please note that there is no
2451 * requirement that a fiber be bound to one specific thread. Rather, fibers
2452 * may be freely passed between threads so long as they are not currently
2453 * executing. Like threads, a new fiber thread may be created using either
2454 * derivation or composition, as in the following example.
2457 * ----------------------------------------------------------------------
2459 * class DerivedFiber : Fiber
2469 * printf( "Derived fiber running.\n" );
2475 * printf( "Composed fiber running.\n" );
2477 * printf( "Composed fiber running.\n" );
2480 * // create instances of each type
2481 * Fiber derived = new DerivedFiber();
2482 * Fiber composed = new Fiber( &fiberFunc );
2484 * // call both fibers once
2487 * printf( "Execution returned to calling context.\n" );
2490 * // since each fiber has run to completion, each should have state TERM
2491 * assert( derived.state == Fiber.State.TERM );
2492 * assert( composed.state == Fiber.State.TERM );
2494 * ----------------------------------------------------------------------
2496 * Authors: Based on a design by Mikola Lysenko.
2500 ///////////////////////////////////////////////////////////////////////////
2502 ///////////////////////////////////////////////////////////////////////////
2506 * Initializes a fiber object which is associated with a static
2510 * fn = The thread function.
2511 * sz = The stack size for this fiber.
2514 * fn must not be null.
2516 this( void function() fn, size_t sz = PAGESIZE )
2525 m_state = State.HOLD;
2532 * Initializes a fiber object which is associated with a dynamic
2536 * dg = The thread function.
2537 * sz = The stack size for this fiber.
2540 * dg must not be null.
2542 this( void delegate() dg, size_t sz = PAGESIZE )
2551 m_state = State.HOLD;
2558 * Cleans up any remaining resources used by this object.
2562 // NOTE: A live reference to this object will exist on its associated
2563 // stack from the first time its call() method has been called
2564 // until its execution completes with State.TERM. Thus, the only
2565 // times this dtor should be called are either if the fiber has
2566 // terminated (and therefore has no active stack) or if the user
2567 // explicitly deletes this object. The latter case is an error
2568 // but is not easily tested for, since State.HOLD may imply that
2569 // the fiber was just created but has never been run. There is
2570 // not a compelling case to create a State.INIT just to offer a
2571 // means of ensuring the user isn't violating this object's
2572 // contract, so for now this requirement will be enforced by
2573 // documentation only.
2578 ///////////////////////////////////////////////////////////////////////////
2580 ///////////////////////////////////////////////////////////////////////////
2584 * Transfers execution to this fiber object. The calling context will be
2585 * suspended until the fiber calls Fiber.yield() or until it terminates
2586 * via an unhandled exception.
2589 * rethrow = Rethrow any unhandled exception which may have caused this
2590 * fiber to terminate.
2593 * This fiber must be in state HOLD.
2596 * Any exception not handled by the joined thread.
2599 * Any exception not handled by this fiber if rethrow = false, null
2602 final Object call( bool rethrow = true )
2605 assert( m_state == State.HOLD );
2609 Fiber cur = getThis();
2611 static if( is( ucontext_t ) )
2612 m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt;
2618 static if( is( ucontext_t ) )
2621 // NOTE: If the fiber has terminated then the stack pointers must be
2622 // reset. This ensures that the stack for this fiber is not
2623 // scanned if the fiber has terminated. This is necessary to
2624 // prevent any references lingering on the stack from delaying
2625 // the collection of otherwise dead objects. The most notable
2626 // being the current object, which is referenced at the top of
2627 // fiber_entryPoint.
2628 if( m_state == State.TERM )
2630 m_ctxt.tstack = m_ctxt.bstack;
2634 Object obj = m_unhandled;
2645 * Resets this fiber so that it may be re-used. This routine may only be
2646 * called for fibers that have terminated, as doing otherwise could result
2647 * in scope-dependent functionality that is not executed. Stack-based
2648 * classes, for example, may not be cleaned up properly if a fiber is reset
2649 * before it has terminated.
2652 * This fiber must be in state TERM.
2657 assert( m_state == State.TERM );
2658 assert( m_ctxt.tstack == m_ctxt.bstack );
2662 m_state = State.HOLD;
2668 ///////////////////////////////////////////////////////////////////////////
2669 // General Properties
2670 ///////////////////////////////////////////////////////////////////////////
2674 * A fiber may occupy one of three states: HOLD, EXEC, and TERM. The HOLD
2675 * state applies to any fiber that is suspended and ready to be called.
2676 * The EXEC state will be set for any fiber that is currently executing.
2677 * And the TERM state is set when a fiber terminates. Once a fiber
2678 * terminates, it must be reset before it may be called again.
2689 * Gets the current state of this fiber.
2692 * The state of this fiber as an enumerated value.
2700 ///////////////////////////////////////////////////////////////////////////
2701 // Actions on Calling Fiber
2702 ///////////////////////////////////////////////////////////////////////////
2706 * Forces a context switch to occur away from the calling fiber.
2710 Fiber cur = getThis();
2711 assert( cur, "Fiber.yield() called with no active fiber" );
2712 assert( cur.m_state == State.EXEC );
2714 static if( is( ucontext_t ) )
2715 cur.m_ucur = &cur.m_utxt;
2717 cur.m_state = State.HOLD;
2719 cur.m_state = State.EXEC;
2724 * Forces a context switch to occur away from the calling fiber and then
2725 * throws obj in the calling fiber.
2728 * obj = The object to throw.
2731 * obj must not be null.
2733 static void yieldAndThrow( Object obj )
2740 Fiber cur = getThis();
2741 assert( cur, "Fiber.yield() called with no active fiber" );
2742 assert( cur.m_state == State.EXEC );
2744 static if( is( ucontext_t ) )
2745 cur.m_ucur = &cur.m_utxt;
2747 cur.m_unhandled = obj;
2748 cur.m_state = State.HOLD;
2750 cur.m_state = State.EXEC;
2754 ///////////////////////////////////////////////////////////////////////////
2756 ///////////////////////////////////////////////////////////////////////////
2760 * Provides a reference to the calling fiber or null if no fiber is
2764 * The fiber object representing the calling fiber or null if no fiber
2765 * is currently active. The result of deleting this object is undefined.
2767 static Fiber getThis()
2771 return cast(Fiber) TlsGetValue( sm_this );
2773 else version( Posix )
2775 return cast(Fiber) pthread_getspecific( sm_this );
2780 ///////////////////////////////////////////////////////////////////////////
2781 // Static Initialization
2782 ///////////////////////////////////////////////////////////////////////////
2789 sm_this = TlsAlloc();
2790 assert( sm_this != TLS_OUT_OF_INDEXES );
2792 else version( Posix )
2796 status = pthread_key_create( &sm_this, null );
2797 assert( status == 0 );
2799 static if( is( ucontext_t ) )
2801 status = getcontext( &sm_utxt );
2802 assert( status == 0 );
2810 // Initializes a fiber object which has no associated executable function.
2819 // Fiber entry point. Invokes the function or delegate passed on
2820 // construction (if any).
2840 // The type of routine passed on fiber construction.
2851 // Standard fiber data
2856 void function() m_fn;
2857 void delegate() m_dg;
2865 ///////////////////////////////////////////////////////////////////////////
2867 ///////////////////////////////////////////////////////////////////////////
2871 // Allocate a new stack for this fiber.
2873 final void allocStack( size_t sz )
2876 assert( !m_pmem && !m_ctxt );
2880 // adjust alloc size to a multiple of PAGESIZE
2882 sz -= sz % PAGESIZE;
2884 // NOTE: This instance of Thread.Context is dynamic so Fiber objects
2885 // can be collected by the GC so long as no user level references
2886 // to the object exist. If m_ctxt were not dynamic then its
2887 // presence in the global context list would be enough to keep
2888 // this object alive indefinitely. An alternative to allocating
2889 // room for this struct explicitly would be to mash it into the
2890 // base of the stack being allocated below. However, doing so
2891 // requires too much special logic to be worthwhile.
2892 m_ctxt = new Thread.Context;
2894 static if( is( typeof( VirtualAlloc ) ) )
2896 // reserve memory for stack
2897 m_pmem = VirtualAlloc( null,
2903 throw new FiberException( "Unable to reserve memory for stack" );
2906 version( StackGrowsDown )
2908 void* stack = m_pmem + PAGESIZE;
2909 void* guard = m_pmem;
2910 void* pbase = stack + sz;
2914 void* stack = m_pmem;
2915 void* guard = m_pmem + sz;
2916 void* pbase = stack;
2919 // allocate reserved stack segment
2920 stack = VirtualAlloc( stack,
2926 throw new FiberException( "Unable to allocate memory for stack" );
2929 // allocate reserved guard page
2930 guard = VirtualAlloc( guard,
2933 PAGE_READWRITE | PAGE_GUARD );
2936 throw new FiberException( "Unable to create guard page for stack" );
2939 m_ctxt.bstack = pbase;
2940 m_ctxt.tstack = pbase;
2944 { static if( is( typeof( mmap ) ) )
2946 m_pmem = mmap( null,
2948 PROT_READ | PROT_WRITE,
2949 MAP_PRIVATE | MAP_ANON,
2952 if( m_pmem == MAP_FAILED )
2955 else static if( is( typeof( valloc ) ) )
2957 m_pmem = valloc( sz );
2959 else static if( is( typeof( malloc ) ) )
2961 m_pmem = malloc( sz );
2970 throw new FiberException( "Unable to allocate memory for stack" );
2973 version( StackGrowsDown )
2975 m_ctxt.bstack = m_pmem + sz;
2976 m_ctxt.tstack = m_pmem + sz;
2980 m_ctxt.bstack = m_pmem;
2981 m_ctxt.tstack = m_pmem;
2986 Thread.add( m_ctxt );
2991 // Free this fiber's stack.
2993 final void freeStack()
2996 assert( m_pmem && m_ctxt );
3000 // NOTE: Since this routine is only ever expected to be called from
3001 // the dtor, pointers to freed data are not set to null.
3003 // NOTE: m_ctxt is guaranteed to be alive because it is held in the
3004 // global context list.
3005 Thread.remove( m_ctxt );
3007 static if( is( typeof( VirtualAlloc ) ) )
3009 VirtualFree( m_pmem, 0, MEM_RELEASE );
3011 else static if( is( typeof( mmap ) ) )
3013 munmap( m_pmem, m_size );
3015 else static if( is( typeof( valloc ) ) )
3019 else static if( is( typeof( malloc ) ) )
3028 // Initialize the allocated stack.
3030 final void initStack()
3033 assert( m_ctxt.tstack && m_ctxt.tstack == m_ctxt.bstack );
3034 assert( cast(size_t) m_ctxt.bstack % (void*).sizeof == 0 );
3038 void* pstack = m_ctxt.tstack;
3039 scope( exit ) m_ctxt.tstack = pstack;
3041 void push( size_t val )
3043 version( StackGrowsDown )
3045 pstack -= size_t.sizeof;
3046 *(cast(size_t*) pstack) = val;
3050 pstack += size_t.sizeof;
3051 *(cast(size_t*) pstack) = val;
3055 // NOTE: On OS X the stack must be 16-byte aligned according to the
3059 pstack = cast(void*)(cast(uint)(pstack) - (cast(uint)(pstack) & 0x0F));
3062 version( AsmX86_Win32 )
3064 push( cast(size_t) &fiber_entryPoint ); // EIP
3065 push( 0xFFFFFFFF ); // EBP
3066 push( 0x00000000 ); // EAX
3067 push( 0xFFFFFFFF ); // FS:[0]
3068 version( StackGrowsDown )
3070 push( cast(size_t) m_ctxt.bstack ); // FS:[4]
3071 push( cast(size_t) m_ctxt.bstack - m_size ); // FS:[8]
3075 push( cast(size_t) m_ctxt.bstack ); // FS:[4]
3076 push( cast(size_t) m_ctxt.bstack + m_size ); // FS:[8]
3078 push( 0x00000000 ); // EBX
3079 push( 0x00000000 ); // ESI
3080 push( 0x00000000 ); // EDI
3082 else version( AsmX86_Posix )
3084 push( cast(size_t) &fiber_entryPoint ); // EIP
3085 push( 0x00000000 ); // EBP
3086 push( 0x00000000 ); // EAX
3087 push( 0x00000000 ); // EBX
3088 push( 0x00000000 ); // ESI
3089 push( 0x00000000 ); // EDI
3091 else version( AsmPPC_Posix )
3093 version( StackGrowsDown )
3095 pstack -= int.sizeof * 5;
3099 pstack += int.sizeof * 5;
3102 push( cast(size_t) &fiber_entryPoint ); // link register
3103 push( 0x00000000 ); // control register
3104 push( 0x00000000 ); // old stack pointer
3107 version( StackGrowsDown )
3109 pstack -= int.sizeof * 20;
3113 pstack += int.sizeof * 20;
3116 assert( cast(uint) pstack & 0x0f == 0 );
3118 else static if( is( ucontext_t ) )
3120 getcontext( &m_utxt );
3121 m_utxt.uc_stack.ss_sp = m_ctxt.bstack;
3122 m_utxt.uc_stack.ss_size = m_size;
3123 makecontext( &m_utxt, &fiber_entryPoint, 0 );
3124 // NOTE: If ucontext is being used then the top of the stack will
3125 // be a pointer to the ucontext_t struct for that fiber.
3126 push( cast(size_t) &m_utxt );
3131 Thread.Context* m_ctxt;
3135 static if( is( ucontext_t ) )
3137 // NOTE: The static ucontext instance is used to represent the context
3138 // of the main application thread.
3139 static ucontext_t sm_utxt = void;
3140 ucontext_t m_utxt = void;
3141 ucontext_t* m_ucur = null;
3146 ///////////////////////////////////////////////////////////////////////////
3147 // Storage of Active Fiber
3148 ///////////////////////////////////////////////////////////////////////////
3152 // Sets a thread-local reference to the current fiber object.
3154 static void setThis( Fiber f )
3158 TlsSetValue( sm_this, cast(void*) f );
3160 else version( Posix )
3162 pthread_setspecific( sm_this, cast(void*) f );
3167 static Thread.TLSKey sm_this;
3171 ///////////////////////////////////////////////////////////////////////////
3172 // Context Switching
3173 ///////////////////////////////////////////////////////////////////////////
3177 // Switches into the stack held by this fiber.
3179 final void switchIn()
3181 Thread tobj = Thread.getThis();
3182 void** oldp = &tobj.m_curr.tstack;
3183 void* newp = m_ctxt.tstack;
3185 // NOTE: The order of operations here is very important. The current
3186 // stack top must be stored before m_lock is set, and pushContext
3187 // must not be called until after m_lock is set. This process
3188 // is intended to prevent a race condition with the suspend
3189 // mechanism used for garbage collection. If it is not followed,
3190 // a badly timed collection could cause the GC to scan from the
3191 // bottom of one stack to the top of another, or to miss scanning
3192 // a stack that still contains valid data. The old stack pointer
3193 // oldp will be set again before the context switch to guarantee
3194 // that it points to exactly the correct stack location so the
3195 // successive pop operations will succeed.
3196 *oldp = getStackTop();
3197 volatile tobj.m_lock = true;
3198 tobj.pushContext( m_ctxt );
3200 fiber_switchContext( oldp, newp );
3202 // NOTE: As above, these operations must be performed in a strict order
3203 // to prevent Bad Things from happening.
3205 volatile tobj.m_lock = false;
3206 tobj.m_curr.tstack = tobj.m_curr.bstack;
3211 // Switches out of the current stack and into the enclosing stack.
3213 final void switchOut()
3215 Thread tobj = Thread.getThis();
3216 void** oldp = &m_ctxt.tstack;
3217 void* newp = tobj.m_curr.within.tstack;
3219 // NOTE: The order of operations here is very important. The current
3220 // stack top must be stored before m_lock is set, and pushContext
3221 // must not be called until after m_lock is set. This process
3222 // is intended to prevent a race condition with the suspend
3223 // mechanism used for garbage collection. If it is not followed,
3224 // a badly timed collection could cause the GC to scan from the
3225 // bottom of one stack to the top of another, or to miss scanning
3226 // a stack that still contains valid data. The old stack pointer
3227 // oldp will be set again before the context switch to guarantee
3228 // that it points to exactly the correct stack location so the
3229 // successive pop operations will succeed.
3230 *oldp = getStackTop();
3231 volatile tobj.m_lock = true;
3233 fiber_switchContext( oldp, newp );
3235 // NOTE: As above, these operations must be performed in a strict order
3236 // to prevent Bad Things from happening.
3237 volatile tobj.m_lock = false;
3238 tobj.m_curr.tstack = tobj.m_curr.bstack;