PageRenderTime 65ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 1ms

/src/core/thread.d

http://github.com/AlexeyProkhin/druntime
D | 4697 lines | 2890 code | 567 blank | 1240 comment | 347 complexity | 672b56f280060a7ede3f5dea172df202 MD5 | raw file
  1. /**
  2. * The thread module provides support for thread creation and management.
  3. *
  4. * Copyright: Copyright Sean Kelly 2005 - 2012.
  5. * License: Distributed under the
  6. * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
  7. * (See accompanying file LICENSE)
  8. * Authors: Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak
  9. * Source: $(DRUNTIMESRC core/_thread.d)
  10. */
  11. module core.thread;
  12. public import core.time; // for Duration
  13. static import rt.tlsgc;
  14. // this should be true for most architectures
  15. version = StackGrowsDown;
  16. /**
  17. * Returns the process ID of the calling process, which is guaranteed to be
  18. * unique on the system. This call is always successful.
  19. *
  20. * Example:
  21. * ---
  22. * writefln("Current process id: %s", getpid());
  23. * ---
  24. */
  25. version(Posix)
  26. {
  27. alias core.sys.posix.unistd.getpid getpid;
  28. }
  29. else version (Windows)
  30. {
  31. alias core.sys.windows.windows.GetCurrentProcessId getpid;
  32. }
  33. ///////////////////////////////////////////////////////////////////////////////
  34. // Thread and Fiber Exceptions
  35. ///////////////////////////////////////////////////////////////////////////////
  36. /**
  37. * Base class for thread exceptions.
  38. */
  39. class ThreadException : Exception
  40. {
  41. this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
  42. {
  43. super(msg, file, line, next);
  44. }
  45. this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__)
  46. {
  47. super(msg, file, line, next);
  48. }
  49. }
  50. /**
  51. * Base class for fiber exceptions.
  52. */
  53. class FiberException : Exception
  54. {
  55. this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
  56. {
  57. super(msg, file, line, next);
  58. }
  59. this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__)
  60. {
  61. super(msg, file, line, next);
  62. }
  63. }
  64. private
  65. {
  66. import core.sync.mutex;
  67. import core.atomic;
  68. //
  69. // from core.memory
  70. //
  71. extern (C) void gc_enable();
  72. extern (C) void gc_disable();
  73. extern (C) void* gc_malloc(size_t sz, uint ba = 0);
  74. //
  75. // from core.stdc.string
  76. //
  77. extern (C) void* memcpy(void*, const void*, size_t);
  78. //
  79. // exposed by compiler runtime
  80. //
  81. extern (C) void rt_moduleTlsCtor();
  82. extern (C) void rt_moduleTlsDtor();
  83. alias void delegate() gc_atom;
  84. extern (C) void function(scope gc_atom) gc_atomic;
  85. }
  86. ///////////////////////////////////////////////////////////////////////////////
  87. // Thread Entry Point and Signal Handlers
  88. ///////////////////////////////////////////////////////////////////////////////
  89. version( Windows )
  90. {
  91. private
  92. {
  93. import core.stdc.stdint : uintptr_t; // for _beginthreadex decl below
  94. import core.stdc.stdlib; // for malloc, atexit
  95. import core.sys.windows.windows;
  96. import core.sys.windows.threadaux; // for OpenThreadHandle
  97. const DWORD TLS_OUT_OF_INDEXES = 0xFFFFFFFF;
  98. const CREATE_SUSPENDED = 0x00000004;
  99. extern (Windows) alias uint function(void*) btex_fptr;
  100. extern (C) uintptr_t _beginthreadex(void*, uint, btex_fptr, void*, uint, uint*);
  101. version( DigitalMars )
  102. {
  103. version (Win32)
  104. {
  105. // NOTE: The memory between the addresses of _tlsstart and _tlsend
  106. // is the storage for thread-local data in D 2.0. Both of
  107. // these are defined in dm\src\win32\tlsseg.asm by DMC.
  108. extern (C)
  109. {
  110. extern int _tlsstart;
  111. extern int _tlsend;
  112. }
  113. }
  114. version (Win64)
  115. {
  116. // NOTE: The memory between the addresses of _tls_start and _tls_end
  117. // is the storage for thread-local data in D 2.0. Both of
  118. // these are defined in LIBCMT:tlssub.obj
  119. extern (C)
  120. {
  121. extern int _tls_start;
  122. extern int _tls_end;
  123. }
  124. alias _tls_start _tlsstart;
  125. alias _tls_end _tlsend;
  126. }
  127. }
  128. else version (MinGW)
  129. {
  130. extern (C)
  131. {
  132. extern int _tls_start;
  133. extern int _tls_end;
  134. }
  135. alias _tls_start _tlsstart;
  136. alias _tls_end _tlsend;
  137. }
  138. else
  139. {
  140. __gshared int _tlsstart;
  141. alias _tlsstart _tlsend;
  142. }
  143. //
  144. // Entry point for Windows threads
  145. //
  146. extern (Windows) uint thread_entryPoint( void* arg )
  147. {
  148. Thread obj = cast(Thread) arg;
  149. assert( obj );
  150. assert( obj.m_curr is &obj.m_main );
  151. obj.m_main.bstack = getStackBottom();
  152. obj.m_main.tstack = obj.m_main.bstack;
  153. void* pstart = cast(void*) &_tlsstart;
  154. void* pend = cast(void*) &_tlsend;
  155. obj.m_tls = pstart[0 .. pend - pstart];
  156. Thread.setThis( obj );
  157. //Thread.add( obj );
  158. scope( exit )
  159. {
  160. Thread.remove( obj );
  161. }
  162. Thread.add( &obj.m_main );
  163. obj.m_tlsgcdata = rt.tlsgc.init();
  164. // NOTE: No GC allocations may occur until the stack pointers have
  165. // been set and Thread.getThis returns a valid reference to
  166. // this thread object (this latter condition is not strictly
  167. // necessary on Windows but it should be followed for the
  168. // sake of consistency).
  169. // TODO: Consider putting an auto exception object here (using
  170. // alloca) forOutOfMemoryError plus something to track
  171. // whether an exception is in-flight?
  172. void append( Throwable t )
  173. {
  174. if( obj.m_unhandled is null )
  175. obj.m_unhandled = t;
  176. else
  177. {
  178. Throwable last = obj.m_unhandled;
  179. while( last.next !is null )
  180. last = last.next;
  181. last.next = t;
  182. }
  183. }
  184. version( D_InlineAsm_X86 )
  185. {
  186. asm { fninit; }
  187. }
  188. try
  189. {
  190. rt_moduleTlsCtor();
  191. try
  192. {
  193. obj.run();
  194. }
  195. catch( Throwable t )
  196. {
  197. append( t );
  198. }
  199. rt_moduleTlsDtor();
  200. }
  201. catch( Throwable t )
  202. {
  203. append( t );
  204. }
  205. return 0;
  206. }
  207. HANDLE GetCurrentThreadHandle()
  208. {
  209. const uint DUPLICATE_SAME_ACCESS = 0x00000002;
  210. HANDLE curr = GetCurrentThread(),
  211. proc = GetCurrentProcess(),
  212. hndl;
  213. DuplicateHandle( proc, curr, proc, &hndl, 0, TRUE, DUPLICATE_SAME_ACCESS );
  214. return hndl;
  215. }
  216. }
  217. }
  218. else version( Posix )
  219. {
  220. private
  221. {
  222. import core.stdc.errno;
  223. import core.sys.posix.semaphore;
  224. import core.sys.posix.stdlib; // for malloc, valloc, free, atexit
  225. import core.sys.posix.pthread;
  226. import core.sys.posix.signal;
  227. import core.sys.posix.time;
  228. version( OSX )
  229. {
  230. import core.sys.osx.mach.thread_act;
  231. extern (C) mach_port_t pthread_mach_thread_np(pthread_t);
  232. }
  233. version( GNU )
  234. {
  235. import gcc.builtins;
  236. }
  237. version( DigitalMars )
  238. {
  239. version( linux )
  240. {
  241. extern (C)
  242. {
  243. extern int _tlsstart;
  244. extern int _tlsend;
  245. }
  246. }
  247. else version( OSX )
  248. {
  249. extern (C)
  250. {
  251. __gshared void[][2] _tls_data_array;
  252. }
  253. }
  254. else version( FreeBSD )
  255. {
  256. extern (C)
  257. {
  258. extern void* _tlsstart;
  259. extern void* _tlsend;
  260. }
  261. }
  262. else
  263. {
  264. __gshared int _tlsstart;
  265. alias _tlsstart _tlsend;
  266. }
  267. }
  268. else version (LDC)
  269. {
  270. version = LDC_NoTlsBracketSyms;
  271. }
  272. else
  273. {
  274. __gshared int _tlsstart;
  275. alias _tlsstart _tlsend;
  276. }
  277. //
  278. // Entry point for POSIX threads
  279. //
  280. extern (C) void* thread_entryPoint( void* arg )
  281. {
  282. Thread obj = cast(Thread) arg;
  283. assert( obj );
  284. assert( obj.m_curr is &obj.m_main );
  285. obj.m_main.bstack = getStackBottom();
  286. obj.m_main.tstack = obj.m_main.bstack;
  287. version (LDC_NoTlsBracketSyms)
  288. {
  289. version (OSX)
  290. {
  291. import ldc.memory;
  292. obj.m_tls = getCurrentTLSRange();
  293. }
  294. else
  295. {
  296. // Nothing to do here for Linux – glibc allocates the TLS
  297. // data at the start of the stack area, so we scan it anyway.
  298. }
  299. }
  300. else version(OSX)
  301. {
  302. // NOTE: OSX does not support TLS, so we do it ourselves. The TLS
  303. // data output by the compiler is bracketed by _tls_data_array[2],
  304. // so make a copy of it for each thread.
  305. const sz0 = (_tls_data_array[0].length + 15) & ~cast(size_t)15;
  306. const sz2 = sz0 + _tls_data_array[1].length;
  307. auto p = malloc( sz2 );
  308. assert( p );
  309. obj.m_tls = p[0 .. sz2];
  310. memcpy( p, _tls_data_array[0].ptr, _tls_data_array[0].length );
  311. memcpy( p + sz0, _tls_data_array[1].ptr, _tls_data_array[1].length );
  312. scope (exit) { free( p ); obj.m_tls = null; }
  313. }
  314. else
  315. {
  316. auto pstart = cast(void*) &_tlsstart;
  317. auto pend = cast(void*) &_tlsend;
  318. obj.m_tls = pstart[0 .. pend - pstart];
  319. }
  320. obj.m_isRunning = true;
  321. Thread.setThis( obj );
  322. //Thread.add( obj );
  323. scope( exit )
  324. {
  325. // NOTE: isRunning should be set to false after the thread is
  326. // removed or a double-removal could occur between this
  327. // function and thread_suspendAll.
  328. Thread.remove( obj );
  329. obj.m_isRunning = false;
  330. }
  331. Thread.add( &obj.m_main );
  332. obj.m_tlsgcdata = rt.tlsgc.init();
  333. static extern (C) void thread_cleanupHandler( void* arg ) nothrow
  334. {
  335. Thread obj = cast(Thread) arg;
  336. assert( obj );
  337. // NOTE: If the thread terminated abnormally, just set it as
  338. // not running and let thread_suspendAll remove it from
  339. // the thread list. This is safer and is consistent
  340. // with the Windows thread code.
  341. obj.m_isRunning = false;
  342. }
  343. // NOTE: Using void to skip the initialization here relies on
  344. // knowledge of how pthread_cleanup is implemented. It may
  345. // not be appropriate for all platforms. However, it does
  346. // avoid the need to link the pthread module. If any
  347. // implementation actually requires default initialization
  348. // then pthread_cleanup should be restructured to maintain
  349. // the current lack of a link dependency.
  350. static if( __traits( compiles, pthread_cleanup ) )
  351. {
  352. pthread_cleanup cleanup = void;
  353. cleanup.push( &thread_cleanupHandler, cast(void*) obj );
  354. }
  355. else static if( __traits( compiles, pthread_cleanup_push ) )
  356. {
  357. pthread_cleanup_push( &thread_cleanupHandler, cast(void*) obj );
  358. }
  359. else
  360. {
  361. static assert( false, "Platform not supported." );
  362. }
  363. // NOTE: No GC allocations may occur until the stack pointers have
  364. // been set and Thread.getThis returns a valid reference to
  365. // this thread object (this latter condition is not strictly
  366. // necessary on Windows but it should be followed for the
  367. // sake of consistency).
  368. // TODO: Consider putting an auto exception object here (using
  369. // alloca) forOutOfMemoryError plus something to track
  370. // whether an exception is in-flight?
  371. void append( Throwable t )
  372. {
  373. if( obj.m_unhandled is null )
  374. obj.m_unhandled = t;
  375. else
  376. {
  377. Throwable last = obj.m_unhandled;
  378. while( last.next !is null )
  379. last = last.next;
  380. last.next = t;
  381. }
  382. }
  383. try
  384. {
  385. rt_moduleTlsCtor();
  386. try
  387. {
  388. obj.run();
  389. }
  390. catch( Throwable t )
  391. {
  392. append( t );
  393. }
  394. rt_moduleTlsDtor();
  395. }
  396. catch( Throwable t )
  397. {
  398. append( t );
  399. }
  400. // NOTE: Normal cleanup is handled by scope(exit).
  401. static if( __traits( compiles, pthread_cleanup ) )
  402. {
  403. cleanup.pop( 0 );
  404. }
  405. else static if( __traits( compiles, pthread_cleanup_push ) )
  406. {
  407. pthread_cleanup_pop( 0 );
  408. }
  409. return null;
  410. }
  411. //
  412. // Used to track the number of suspended threads
  413. //
  414. __gshared sem_t suspendCount;
  415. extern (C) void thread_suspendHandler( int sig )
  416. in
  417. {
  418. assert( sig == SIGUSR1 );
  419. }
  420. body
  421. {
  422. void op(void* sp)
  423. {
  424. // NOTE: Since registers are being pushed and popped from the
  425. // stack, any other stack data used by this function should
  426. // be gone before the stack cleanup code is called below.
  427. Thread obj = Thread.getThis();
  428. // NOTE: The thread reference returned by getThis is set within
  429. // the thread startup code, so it is possible that this
  430. // handler may be called before the reference is set. In
  431. // this case it is safe to simply suspend and not worry
  432. // about the stack pointers as the thread will not have
  433. // any references to GC-managed data.
  434. if( obj && !obj.m_lock )
  435. {
  436. obj.m_curr.tstack = getStackTop();
  437. }
  438. sigset_t sigres = void;
  439. int status;
  440. status = sigfillset( &sigres );
  441. assert( status == 0 );
  442. status = sigdelset( &sigres, SIGUSR2 );
  443. assert( status == 0 );
  444. status = sem_post( &suspendCount );
  445. assert( status == 0 );
  446. sigsuspend( &sigres );
  447. if( obj && !obj.m_lock )
  448. {
  449. obj.m_curr.tstack = obj.m_curr.bstack;
  450. }
  451. }
  452. callWithStackShell(&op);
  453. }
  454. extern (C) void thread_resumeHandler( int sig )
  455. in
  456. {
  457. assert( sig == SIGUSR2 );
  458. }
  459. body
  460. {
  461. }
  462. }
  463. }
  464. else
  465. {
  466. // NOTE: This is the only place threading versions are checked. If a new
  467. // version is added, the module code will need to be searched for
  468. // places where version-specific code may be required. This can be
  469. // easily accomlished by searching for 'Windows' or 'Posix'.
  470. static assert( false, "Unknown threading implementation." );
  471. }
  472. ///////////////////////////////////////////////////////////////////////////////
  473. // Thread
  474. ///////////////////////////////////////////////////////////////////////////////
  475. /**
  476. * This class encapsulates all threading functionality for the D
  477. * programming language. As thread manipulation is a required facility
  478. * for garbage collection, all user threads should derive from this
  479. * class, and instances of this class should never be explicitly deleted.
  480. * A new thread may be created using either derivation or composition, as
  481. * in the following example.
  482. *
  483. * Example:
  484. * ----------------------------------------------------------------------------
  485. *
  486. * class DerivedThread : Thread
  487. * {
  488. * this()
  489. * {
  490. * super( &run );
  491. * }
  492. *
  493. * private :
  494. * void run()
  495. * {
  496. * printf( "Derived thread running.\n" );
  497. * }
  498. * }
  499. *
  500. * void threadFunc()
  501. * {
  502. * printf( "Composed thread running.\n" );
  503. * }
  504. *
  505. * // create instances of each type
  506. * Thread derived = new DerivedThread();
  507. * Thread composed = new Thread( &threadFunc );
  508. *
  509. * // start both threads
  510. * derived.start();
  511. * composed.start();
  512. *
  513. * ----------------------------------------------------------------------------
  514. */
  515. class Thread
  516. {
  517. ///////////////////////////////////////////////////////////////////////////
  518. // Initialization
  519. ///////////////////////////////////////////////////////////////////////////
  520. /**
  521. * Initializes a thread object which is associated with a static
  522. * D function.
  523. *
  524. * Params:
  525. * fn = The thread function.
  526. * sz = The stack size for this thread.
  527. *
  528. * In:
  529. * fn must not be null.
  530. */
  531. this( void function() fn, size_t sz = 0 )
  532. in
  533. {
  534. assert( fn );
  535. }
  536. body
  537. {
  538. this();
  539. m_fn = fn;
  540. m_sz = sz;
  541. m_call = Call.FN;
  542. m_curr = &m_main;
  543. }
  544. /**
  545. * Initializes a thread object which is associated with a dynamic
  546. * D function.
  547. *
  548. * Params:
  549. * dg = The thread function.
  550. * sz = The stack size for this thread.
  551. *
  552. * In:
  553. * dg must not be null.
  554. */
  555. this( void delegate() dg, size_t sz = 0 )
  556. in
  557. {
  558. assert( dg );
  559. }
  560. body
  561. {
  562. this();
  563. m_dg = dg;
  564. m_sz = sz;
  565. m_call = Call.DG;
  566. m_curr = &m_main;
  567. }
  568. /**
  569. * Cleans up any remaining resources used by this object.
  570. */
  571. ~this()
  572. {
  573. if( m_addr == m_addr.init )
  574. {
  575. return;
  576. }
  577. version( Windows )
  578. {
  579. m_addr = m_addr.init;
  580. CloseHandle( m_hndl );
  581. m_hndl = m_hndl.init;
  582. }
  583. else version( Posix )
  584. {
  585. pthread_detach( m_addr );
  586. m_addr = m_addr.init;
  587. }
  588. version( OSX )
  589. {
  590. m_tmach = m_tmach.init;
  591. }
  592. rt.tlsgc.destroy( m_tlsgcdata );
  593. m_tlsgcdata = null;
  594. }
  595. ///////////////////////////////////////////////////////////////////////////
  596. // General Actions
  597. ///////////////////////////////////////////////////////////////////////////
  598. /**
  599. * Starts the thread and invokes the function or delegate passed upon
  600. * construction.
  601. *
  602. * In:
  603. * This routine may only be called once per thread instance.
  604. *
  605. * Throws:
  606. * ThreadException if the thread fails to start.
  607. */
  608. final void start()
  609. in
  610. {
  611. assert( !next && !prev );
  612. }
  613. body
  614. {
  615. auto wasThreaded = multiThreadedFlag;
  616. multiThreadedFlag = true;
  617. scope( failure )
  618. {
  619. if( !wasThreaded )
  620. multiThreadedFlag = false;
  621. }
  622. version( Windows ) {} else
  623. version( Posix )
  624. {
  625. pthread_attr_t attr;
  626. if( pthread_attr_init( &attr ) )
  627. throw new ThreadException( "Error initializing thread attributes" );
  628. if( m_sz && pthread_attr_setstacksize( &attr, m_sz ) )
  629. throw new ThreadException( "Error initializing thread stack size" );
  630. if( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) )
  631. throw new ThreadException( "Error setting thread joinable" );
  632. }
  633. version( Windows )
  634. {
  635. // NOTE: If a thread is just executing DllMain()
  636. // while another thread is started here, it holds an OS internal
  637. // lock that serializes DllMain with CreateThread. As the code
  638. // might request a synchronization on slock (e.g. in thread_findByAddr()),
  639. // we cannot hold that lock while creating the thread without
  640. // creating a deadlock
  641. //
  642. // Solution: Create the thread in suspended state and then
  643. // add and resume it with slock acquired
  644. assert(m_sz <= uint.max, "m_sz must be less than or equal to uint.max");
  645. m_hndl = cast(HANDLE) _beginthreadex( null, cast(uint) m_sz, &thread_entryPoint, cast(void*) this, CREATE_SUSPENDED, &m_addr );
  646. if( cast(size_t) m_hndl == 0 )
  647. throw new ThreadException( "Error creating thread" );
  648. }
  649. // NOTE: The starting thread must be added to the global thread list
  650. // here rather than within thread_entryPoint to prevent a race
  651. // with the main thread, which could finish and terminat the
  652. // app without ever knowing that it should have waited for this
  653. // starting thread. In effect, not doing the add here risks
  654. // having thread being treated like a daemon thread.
  655. synchronized( slock )
  656. {
  657. version( Windows )
  658. {
  659. if( ResumeThread( m_hndl ) == -1 )
  660. throw new ThreadException( "Error resuming thread" );
  661. }
  662. else version( Posix )
  663. {
  664. // NOTE: This is also set to true by thread_entryPoint, but set it
  665. // here as well so the calling thread will see the isRunning
  666. // state immediately.
  667. m_isRunning = true;
  668. scope( failure ) m_isRunning = false;
  669. if( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 )
  670. throw new ThreadException( "Error creating thread" );
  671. }
  672. version( OSX )
  673. {
  674. m_tmach = pthread_mach_thread_np( m_addr );
  675. if( m_tmach == m_tmach.init )
  676. throw new ThreadException( "Error creating thread" );
  677. }
  678. // NOTE: when creating threads from inside a DLL, DllMain(THREAD_ATTACH)
  679. // might be called before ResumeThread returns, but the dll
  680. // helper functions need to know whether the thread is created
  681. // from the runtime itself or from another DLL or the application
  682. // to just attach to it
  683. // as a consequence, the new Thread object is added before actual
  684. // creation of the thread. There should be no problem with the GC
  685. // calling thread_suspendAll, because of the slock synchronization
  686. //
  687. // VERIFY: does this actually also apply to other platforms?
  688. add( this );
  689. }
  690. }
  691. /**
  692. * Waits for this thread to complete. If the thread terminated as the
  693. * result of an unhandled exception, this exception will be rethrown.
  694. *
  695. * Params:
  696. * rethrow = Rethrow any unhandled exception which may have caused this
  697. * thread to terminate.
  698. *
  699. * Throws:
  700. * ThreadException if the operation fails.
  701. * Any exception not handled by the joined thread.
  702. *
  703. * Returns:
  704. * Any exception not handled by this thread if rethrow = false, null
  705. * otherwise.
  706. */
  707. final Throwable join( bool rethrow = true )
  708. {
  709. version( Windows )
  710. {
  711. if( WaitForSingleObject( m_hndl, INFINITE ) != WAIT_OBJECT_0 )
  712. throw new ThreadException( "Unable to join thread" );
  713. // NOTE: m_addr must be cleared before m_hndl is closed to avoid
  714. // a race condition with isRunning. The operation is done
  715. // with atomicStore to prevent compiler reordering.
  716. atomicStore!(MemoryOrder.raw)(*cast(shared)&m_addr, m_addr.init);
  717. CloseHandle( m_hndl );
  718. m_hndl = m_hndl.init;
  719. }
  720. else version( Posix )
  721. {
  722. if( pthread_join( m_addr, null ) != 0 )
  723. throw new ThreadException( "Unable to join thread" );
  724. // NOTE: pthread_join acts as a substitute for pthread_detach,
  725. // which is normally called by the dtor. Setting m_addr
  726. // to zero ensures that pthread_detach will not be called
  727. // on object destruction.
  728. m_addr = m_addr.init;
  729. }
  730. if( m_unhandled )
  731. {
  732. if( rethrow )
  733. throw m_unhandled;
  734. return m_unhandled;
  735. }
  736. return null;
  737. }
  738. ///////////////////////////////////////////////////////////////////////////
  739. // General Properties
  740. ///////////////////////////////////////////////////////////////////////////
  741. /**
  742. * Gets the user-readable label for this thread.
  743. *
  744. * Returns:
  745. * The name of this thread.
  746. */
  747. final @property string name()
  748. {
  749. synchronized( this )
  750. {
  751. return m_name;
  752. }
  753. }
  754. /**
  755. * Sets the user-readable label for this thread.
  756. *
  757. * Params:
  758. * val = The new name of this thread.
  759. */
  760. final @property void name( string val )
  761. {
  762. synchronized( this )
  763. {
  764. m_name = val;
  765. }
  766. }
  767. /**
  768. * Gets the daemon status for this thread. While the runtime will wait for
  769. * all normal threads to complete before tearing down the process, daemon
  770. * threads are effectively ignored and thus will not prevent the process
  771. * from terminating. In effect, daemon threads will be terminated
  772. * automatically by the OS when the process exits.
  773. *
  774. * Returns:
  775. * true if this is a daemon thread.
  776. */
  777. final @property bool isDaemon()
  778. {
  779. synchronized( this )
  780. {
  781. return m_isDaemon;
  782. }
  783. }
  784. /**
  785. * Sets the daemon status for this thread. While the runtime will wait for
  786. * all normal threads to complete before tearing down the process, daemon
  787. * threads are effectively ignored and thus will not prevent the process
  788. * from terminating. In effect, daemon threads will be terminated
  789. * automatically by the OS when the process exits.
  790. *
  791. * Params:
  792. * val = The new daemon status for this thread.
  793. */
  794. final @property void isDaemon( bool val )
  795. {
  796. synchronized( this )
  797. {
  798. m_isDaemon = val;
  799. }
  800. }
  801. /**
  802. * Tests whether this thread is running.
  803. *
  804. * Returns:
  805. * true if the thread is running, false if not.
  806. */
  807. final @property bool isRunning()
  808. {
  809. if( m_addr == m_addr.init )
  810. {
  811. return false;
  812. }
  813. version( Windows )
  814. {
  815. uint ecode = 0;
  816. GetExitCodeThread( m_hndl, &ecode );
  817. return ecode == STILL_ACTIVE;
  818. }
  819. else version( Posix )
  820. {
  821. // NOTE: It should be safe to access this value without
  822. // memory barriers because word-tearing and such
  823. // really isn't an issue for boolean values.
  824. return m_isRunning;
  825. }
  826. }
  827. ///////////////////////////////////////////////////////////////////////////
  828. // Thread Priority Actions
  829. ///////////////////////////////////////////////////////////////////////////
  830. /**
  831. * The minimum scheduling priority that may be set for a thread. On
  832. * systems where multiple scheduling policies are defined, this value
  833. * represents the minimum valid priority for the scheduling policy of
  834. * the process.
  835. */
  836. __gshared const int PRIORITY_MIN;
  837. /**
  838. * The maximum scheduling priority that may be set for a thread. On
  839. * systems where multiple scheduling policies are defined, this value
  840. * represents the minimum valid priority for the scheduling policy of
  841. * the process.
  842. */
  843. __gshared const int PRIORITY_MAX;
  844. /**
  845. * Gets the scheduling priority for the associated thread.
  846. *
  847. * Returns:
  848. * The scheduling priority of this thread.
  849. */
  850. final @property int priority()
  851. {
  852. version( Windows )
  853. {
  854. return GetThreadPriority( m_hndl );
  855. }
  856. else version( Posix )
  857. {
  858. int policy;
  859. sched_param param;
  860. if( pthread_getschedparam( m_addr, &policy, &param ) )
  861. throw new ThreadException( "Unable to get thread priority" );
  862. return param.sched_priority;
  863. }
  864. }
  865. /**
  866. * Sets the scheduling priority for the associated thread.
  867. *
  868. * Params:
  869. * val = The new scheduling priority of this thread.
  870. */
  871. final @property void priority( int val )
  872. {
  873. version( Windows )
  874. {
  875. if( !SetThreadPriority( m_hndl, val ) )
  876. throw new ThreadException( "Unable to set thread priority" );
  877. }
  878. else version( Posix )
  879. {
  880. // NOTE: pthread_setschedprio is not implemented on linux, so use
  881. // the more complicated get/set sequence below.
  882. //if( pthread_setschedprio( m_addr, val ) )
  883. // throw new ThreadException( "Unable to set thread priority" );
  884. int policy;
  885. sched_param param;
  886. if( pthread_getschedparam( m_addr, &policy, &param ) )
  887. throw new ThreadException( "Unable to set thread priority" );
  888. param.sched_priority = val;
  889. if( pthread_setschedparam( m_addr, policy, &param ) )
  890. throw new ThreadException( "Unable to set thread priority" );
  891. }
  892. }
  893. ///////////////////////////////////////////////////////////////////////////
  894. // Actions on Calling Thread
  895. ///////////////////////////////////////////////////////////////////////////
  896. /**
  897. * Suspends the calling thread for at least the supplied period. This may
  898. * result in multiple OS calls if period is greater than the maximum sleep
  899. * duration supported by the operating system.
  900. *
  901. * Params:
  902. * val = The minimum duration the calling thread should be suspended.
  903. *
  904. * In:
  905. * period must be non-negative.
  906. *
  907. * Example:
  908. * ------------------------------------------------------------------------
  909. *
  910. * Thread.sleep( dur!("msecs")( 50 ) ); // sleep for 50 milliseconds
  911. * Thread.sleep( dur!("seconds")( 5 ) ); // sleep for 5 seconds
  912. *
  913. * ------------------------------------------------------------------------
  914. */
  915. static void sleep( Duration val )
  916. in
  917. {
  918. assert( !val.isNegative );
  919. }
  920. body
  921. {
  922. version( Windows )
  923. {
  924. auto maxSleepMillis = dur!("msecs")( uint.max - 1 );
  925. // NOTE: In instances where all other threads in the process have a
  926. // lower priority than the current thread, the current thread
  927. // will not yield with a sleep time of zero. However, unlike
  928. // yield(), the user is not asking for a yield to occur but
  929. // only for execution to suspend for the requested interval.
  930. // Therefore, expected performance may not be met if a yield
  931. // is forced upon the user.
  932. while( val > maxSleepMillis )
  933. {
  934. Sleep( cast(uint)
  935. maxSleepMillis.total!"msecs" );
  936. val -= maxSleepMillis;
  937. }
  938. Sleep( cast(uint) val.total!"msecs" );
  939. }
  940. else version( Posix )
  941. {
  942. timespec tin = void;
  943. timespec tout = void;
  944. if( val.total!"seconds" > tin.tv_sec.max )
  945. {
  946. tin.tv_sec = tin.tv_sec.max;
  947. tin.tv_nsec = cast(typeof(tin.tv_nsec)) val.fracSec.nsecs;
  948. }
  949. else
  950. {
  951. tin.tv_sec = cast(typeof(tin.tv_sec)) val.total!"seconds";
  952. tin.tv_nsec = cast(typeof(tin.tv_nsec)) val.fracSec.nsecs;
  953. }
  954. while( true )
  955. {
  956. if( !nanosleep( &tin, &tout ) )
  957. return;
  958. if( errno != EINTR )
  959. throw new ThreadException( "Unable to sleep for the specified duration" );
  960. tin = tout;
  961. }
  962. }
  963. }
  964. /**
  965. * $(RED Deprecated. It will be removed in December 2012. Please use the
  966. * version which takes a $(D Duration) instead.)
  967. *
  968. * Suspends the calling thread for at least the supplied period. This may
  969. * result in multiple OS calls if period is greater than the maximum sleep
  970. * duration supported by the operating system.
  971. *
  972. * Params:
  973. * period = The minimum duration the calling thread should be suspended,
  974. * in 100 nanosecond intervals.
  975. *
  976. * In:
  977. * period must be non-negative.
  978. *
  979. * Example:
  980. * ------------------------------------------------------------------------
  981. *
  982. * Thread.sleep( 500_000 ); // sleep for 50 milliseconds
  983. * Thread.sleep( 50_000_000 ); // sleep for 5 seconds
  984. *
  985. * ------------------------------------------------------------------------
  986. */
  987. deprecated("Please use the overload of sleep which takes a Duration.")
  988. static void sleep( long period )
  989. in
  990. {
  991. assert( period >= 0 );
  992. }
  993. body
  994. {
  995. sleep( dur!"hnsecs"( period ) );
  996. }
  997. /**
  998. * Forces a context switch to occur away from the calling thread.
  999. */
  1000. static void yield()
  1001. {
  1002. version( Windows )
  1003. SwitchToThread();
  1004. else version( Posix )
  1005. sched_yield();
  1006. }
  1007. ///////////////////////////////////////////////////////////////////////////
  1008. // Thread Accessors
  1009. ///////////////////////////////////////////////////////////////////////////
  1010. /**
  1011. * Provides a reference to the calling thread.
  1012. *
  1013. * Returns:
  1014. * The thread object representing the calling thread. The result of
  1015. * deleting this object is undefined. If the current thread is not
  1016. * attached to the runtime, a null reference is returned.
  1017. */
  1018. static Thread getThis()
  1019. {
  1020. // NOTE: This function may not be called until thread_init has
  1021. // completed. See thread_suspendAll for more information
  1022. // on why this might occur.
  1023. version( Windows )
  1024. {
  1025. auto t = cast(Thread) TlsGetValue( sm_this );
  1026. // NOTE: If this thread was attached via thread_attachByAddr then
  1027. // this TLS lookup won't initially be set, so when the TLS
  1028. // lookup fails, try an exhaustive search.
  1029. if( t is null )
  1030. {
  1031. t = thread_findByAddr( GetCurrentThreadId() );
  1032. setThis( t );
  1033. }
  1034. return t;
  1035. }
  1036. else version( Posix )
  1037. {
  1038. auto t = cast(Thread) pthread_getspecific( sm_this );
  1039. // NOTE: See the comment near thread_findByAddr() for why the
  1040. // secondary thread_findByAddr lookup can't be done on
  1041. // Posix. However, because thread_attachByAddr() is for
  1042. // Windows only, the secondary lookup is pointless anyway.
  1043. return t;
  1044. }
  1045. }
  1046. /**
  1047. * Provides a list of all threads currently being tracked by the system.
  1048. *
  1049. * Returns:
  1050. * An array containing references to all threads currently being
  1051. * tracked by the system. The result of deleting any contained
  1052. * objects is undefined.
  1053. */
  1054. static Thread[] getAll()
  1055. {
  1056. synchronized( slock )
  1057. {
  1058. size_t pos = 0;
  1059. Thread[] buf = new Thread[sm_tlen];
  1060. foreach( Thread t; Thread )
  1061. {
  1062. buf[pos++] = t;
  1063. }
  1064. return buf;
  1065. }
  1066. }
  1067. /**
  1068. * Operates on all threads currently being tracked by the system. The
  1069. * result of deleting any Thread object is undefined.
  1070. *
  1071. * Params:
  1072. * dg = The supplied code as a delegate.
  1073. *
  1074. * Returns:
  1075. * Zero if all elemented are visited, nonzero if not.
  1076. */
  1077. static int opApply( scope int delegate( ref Thread ) dg )
  1078. {
  1079. synchronized( slock )
  1080. {
  1081. int ret = 0;
  1082. for( Thread t = sm_tbeg; t; t = t.next )
  1083. {
  1084. ret = dg( t );
  1085. if( ret )
  1086. break;
  1087. }
  1088. return ret;
  1089. }
  1090. }
  1091. ///////////////////////////////////////////////////////////////////////////
  1092. // Static Initalizer
  1093. ///////////////////////////////////////////////////////////////////////////
  1094. /**
  1095. * This initializer is used to set thread constants. All functional
  1096. * initialization occurs within thread_init().
  1097. */
  1098. shared static this()
  1099. {
  1100. version( Windows )
  1101. {
  1102. PRIORITY_MIN = -15;
  1103. PRIORITY_MAX = 15;
  1104. }
  1105. else version( Posix )
  1106. {
  1107. int policy;
  1108. sched_param param;
  1109. pthread_t self = pthread_self();
  1110. int status = pthread_getschedparam( self, &policy, &param );
  1111. assert( status == 0 );
  1112. PRIORITY_MIN = sched_get_priority_min( policy );
  1113. assert( PRIORITY_MIN != -1 );
  1114. PRIORITY_MAX = sched_get_priority_max( policy );
  1115. assert( PRIORITY_MAX != -1 );
  1116. }
  1117. }
  1118. ///////////////////////////////////////////////////////////////////////////
  1119. // Stuff That Should Go Away
  1120. ///////////////////////////////////////////////////////////////////////////
  1121. private:
  1122. //
  1123. // Initializes a thread object which has no associated executable function.
  1124. // This is used for the main thread initialized in thread_init().
  1125. //
  1126. this()
  1127. {
  1128. m_call = Call.NO;
  1129. m_curr = &m_main;
  1130. version (LDC_NoTlsBracketSyms) {} else
  1131. version (OSX)
  1132. {
  1133. //printf("test2 %p %p\n", _tls_data_array[0].ptr, &_tls_data_array[1][length]);
  1134. //printf("test2 %p %p\n", &_tls_beg, &_tls_end);
  1135. // NOTE: OSX does not support TLS, so we do it ourselves. The TLS
  1136. // data output by the compiler is bracketed by _tls_data_array2],
  1137. // so make a copy of it for each thread.
  1138. const sz0 = (_tls_data_array[0].length + 15) & ~cast(size_t)15;
  1139. const sz2 = sz0 + _tls_data_array[1].length;
  1140. auto p = malloc( sz2 );
  1141. assert( p );
  1142. m_tls = p[0 .. sz2];
  1143. memcpy( p, _tls_data_array[0].ptr, _tls_data_array[0].length );
  1144. memcpy( p + sz0, _tls_data_array[1].ptr, _tls_data_array[1].length );
  1145. // The free must happen at program end, if anywhere.
  1146. }
  1147. else
  1148. {
  1149. auto pstart = cast(void*) &_tlsstart;
  1150. auto pend = cast(void*) &_tlsend;
  1151. m_tls = pstart[0 .. pend - pstart];
  1152. }
  1153. }
  1154. //
  1155. // Thread entry point. Invokes the function or delegate passed on
  1156. // construction (if any).
  1157. //
  1158. final void run()
  1159. {
  1160. switch( m_call )
  1161. {
  1162. case Call.FN:
  1163. m_fn();
  1164. break;
  1165. case Call.DG:
  1166. m_dg();
  1167. break;
  1168. default:
  1169. break;
  1170. }
  1171. }
  1172. private:
  1173. //
  1174. // The type of routine passed on thread construction.
  1175. //
  1176. enum Call
  1177. {
  1178. NO,
  1179. FN,
  1180. DG
  1181. }
  1182. //
  1183. // Standard types
  1184. //
  1185. version( Windows )
  1186. {
  1187. alias uint TLSKey;
  1188. alias uint ThreadAddr;
  1189. }
  1190. else version( Posix )
  1191. {
  1192. alias pthread_key_t TLSKey;
  1193. alias pthread_t ThreadAddr;
  1194. }
  1195. //
  1196. // Local storage
  1197. //
  1198. __gshared TLSKey sm_this;
  1199. //
  1200. // Main process thread
  1201. //
  1202. __gshared Thread sm_main;
  1203. //
  1204. // Standard thread data
  1205. //
  1206. version( Windows )
  1207. {
  1208. HANDLE m_hndl;
  1209. }
  1210. else version( OSX )
  1211. {
  1212. mach_port_t m_tmach;
  1213. }
  1214. ThreadAddr m_addr;
  1215. Call m_call;
  1216. string m_name;
  1217. union
  1218. {
  1219. void function() m_fn;
  1220. void delegate() m_dg;
  1221. }
  1222. size_t m_sz;
  1223. version( Posix )
  1224. {
  1225. bool m_isRunning;
  1226. }
  1227. bool m_isDaemon;
  1228. bool m_isInCriticalRegion;
  1229. Throwable m_unhandled;
  1230. private:
  1231. ///////////////////////////////////////////////////////////////////////////
  1232. // Storage of Active Thread
  1233. ///////////////////////////////////////////////////////////////////////////
  1234. //
  1235. // Sets a thread-local reference to the current thread object.
  1236. //
  1237. static void setThis( Thread t )
  1238. {
  1239. version( Windows )
  1240. {
  1241. TlsSetValue( sm_this, cast(void*) t );
  1242. }
  1243. else version( Posix )
  1244. {
  1245. pthread_setspecific( sm_this, cast(void*) t );
  1246. }
  1247. }
  1248. private:
  1249. ///////////////////////////////////////////////////////////////////////////
  1250. // Thread Context and GC Scanning Support
  1251. ///////////////////////////////////////////////////////////////////////////
  1252. final void pushContext( Context* c )
  1253. in
  1254. {
  1255. assert( !c.within );
  1256. }
  1257. body
  1258. {
  1259. c.within = m_curr;
  1260. m_curr = c;
  1261. }
  1262. final void popContext()
  1263. in
  1264. {
  1265. assert( m_curr && m_curr.within );
  1266. }
  1267. body
  1268. {
  1269. Context* c = m_curr;
  1270. m_curr = c.within;
  1271. c.within = null;
  1272. }
  1273. final Context* topContext()
  1274. in
  1275. {
  1276. assert( m_curr );
  1277. }
  1278. body
  1279. {
  1280. return m_curr;
  1281. }
  1282. static struct Context
  1283. {
  1284. void* bstack,
  1285. tstack;
  1286. Context* within;
  1287. Context* next,
  1288. prev;
  1289. }
  1290. Context m_main;
  1291. Context* m_curr;
  1292. bool m_lock;
  1293. void[] m_tls; // spans implicit thread local storage
  1294. rt.tlsgc.Data* m_tlsgcdata;
  1295. version( Windows )
  1296. {
  1297. version( X86 )
  1298. {
  1299. uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
  1300. }
  1301. else version( X86_64 )
  1302. {
  1303. ulong[16] m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax
  1304. // r8,r9,r10,r11,r12,r13,r14,r15
  1305. }
  1306. else
  1307. {
  1308. static assert(false, "Architecture not supported." );
  1309. }
  1310. }
  1311. else version( OSX )
  1312. {
  1313. version( X86 )
  1314. {
  1315. uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
  1316. }
  1317. else version( X86_64 )
  1318. {
  1319. ulong[16] m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax
  1320. // r8,r9,r10,r11,r12,r13,r14,r15
  1321. }
  1322. else
  1323. {
  1324. static assert(false, "Architecture not supported." );
  1325. }
  1326. }
  1327. private:
  1328. ///////////////////////////////////////////////////////////////////////////
  1329. // GC Scanning Support
  1330. ///////////////////////////////////////////////////////////////////////////
  1331. // NOTE: The GC scanning process works like so:
  1332. //
  1333. // 1. Suspend all threads.
  1334. // 2. Scan the stacks of all suspended threads for roots.
  1335. // 3. Resume all threads.
  1336. //
  1337. // Step 1 and 3 require a list of all threads in the system, while
  1338. // step 2 requires a list of all thread stacks (each represented by
  1339. // a Context struct). Traditionally, there was one stack per thread
  1340. // and the Context structs were not necessary. However, Fibers have
  1341. // changed things so that each thread has its own 'main' stack plus
  1342. // an arbitrary number of nested stacks (normally referenced via
  1343. // m_curr). Also, there may be 'free-floating' stacks in the system,
  1344. // which are Fibers that are not currently executing on any specific
  1345. // thread but are still being processed and still contain valid
  1346. // roots.
  1347. //
  1348. // To support all of this, the Context struct has been created to
  1349. // represent a stack range, and a global list of Context structs has
  1350. // been added to enable scanning of these stack ranges. The lifetime
  1351. // (and presence in the Context list) of a thread's 'main' stack will
  1352. // be equivalent to the thread's lifetime. So the Ccontext will be
  1353. // added to the list on thread entry, and removed from the list on
  1354. // thread exit (which is essentially the same as the presence of a
  1355. // Thread object in its own global list). The lifetime of a Fiber's
  1356. // context, however, will be tied to the lifetime of the Fiber object
  1357. // itself, and Fibers are expected to add/remove their Context struct
  1358. // on construction/deletion.
  1359. //
  1360. // All use of the global lists should synchronize on this lock.
  1361. //
  1362. @property static Mutex slock()
  1363. {
  1364. __gshared Mutex m;
  1365. __gshared byte[__traits(classInstanceSize, Mutex)] ms;
  1366. if (m is null)
  1367. {
  1368. // Initialization doesn't need to be synchronized because
  1369. // creating a thread will lock this mutex.
  1370. ms[] = Mutex.classinfo.init[];
  1371. m = cast(Mutex)ms.ptr;
  1372. m.__ctor();
  1373. extern(C) void destroy() { m.__dtor(); }
  1374. atexit(&destroy);
  1375. }
  1376. return m;
  1377. }
  1378. __gshared Context* sm_cbeg;
  1379. __gshared size_t sm_clen;
  1380. __gshared Thread sm_tbeg;
  1381. __gshared size_t sm_tlen;
  1382. //
  1383. // Used for ordering threads in the global thread list.
  1384. //
  1385. Thread prev;
  1386. Thread next;
  1387. ///////////////////////////////////////////////////////////////////////////
  1388. // Global Context List Operations
  1389. ///////////////////////////////////////////////////////////////////////////
  1390. //
  1391. // Add a context to the global context list.
  1392. //
  1393. static void add( Context* c )
  1394. in
  1395. {
  1396. assert( c );
  1397. assert( !c.next && !c.prev );
  1398. }
  1399. body
  1400. {
  1401. // NOTE: This loop is necessary to avoid a race between newly created
  1402. // threads and the GC. If a collection starts between the time
  1403. // Thread.start is called and the new thread calls Thread.add,
  1404. // the thread will have its stack scanned without first having
  1405. // been properly suspended. Testing has shown this to sometimes
  1406. // cause a deadlock.
  1407. while( true )
  1408. {
  1409. synchronized( slock )
  1410. {
  1411. if( !suspendDepth )
  1412. {
  1413. if( sm_cbeg )
  1414. {
  1415. c.next = sm_cbeg;
  1416. sm_cbeg.prev = c;
  1417. }
  1418. sm_cbeg = c;
  1419. ++sm_clen;
  1420. return;
  1421. }
  1422. }
  1423. yield();
  1424. }
  1425. }
  1426. //
  1427. // Remove a context from the global context list.
  1428. //
  1429. static void remove( Context* c )
  1430. in
  1431. {
  1432. assert( c );
  1433. assert( c.next || c.prev );
  1434. }
  1435. body
  1436. {
  1437. synchronized( slock )
  1438. {
  1439. if( c.prev )
  1440. c.prev.next = c.next;
  1441. if( c.next )
  1442. c.next.prev = c.prev;
  1443. if( sm_cbeg == c )
  1444. sm_cbeg = c.next;
  1445. --sm_clen;
  1446. }
  1447. // NOTE: Don't null out c.next or c.prev because opApply currently
  1448. // follows c.next after removing a node. This could be easily
  1449. // addressed by simply returning the next node from this
  1450. // function, however, a context should never be re-added to the
  1451. // list anyway and having next and prev be non-null is a good way
  1452. // to ensure that.
  1453. }
  1454. ///////////////////////////////////////////////////////////////////////////
  1455. // Global Thread List Operations
  1456. ///////////////////////////////////////////////////////////////////////////
  1457. //
  1458. // Add a thread to the global thread list.
  1459. //
  1460. static void add( Thread t )
  1461. in
  1462. {
  1463. assert( t );
  1464. assert( !t.next && !t.prev );
  1465. //assert( t.isRunning );
  1466. }
  1467. body
  1468. {
  1469. // NOTE: This loop is necessary to avoid a race between newly created
  1470. // threads and the GC. If a collection starts between the time
  1471. // Thread.start is called and the new thread calls Thread.add,
  1472. // the thread could manipulate global state while the collection
  1473. // is running, and by being added to the thread list it could be
  1474. // resumed by the GC when it was never suspended, which would
  1475. // result in an exception thrown by the GC code.
  1476. //
  1477. // An alternative would be to have Thread.start call Thread.add
  1478. // for the new thread, but this may introduce its own problems,
  1479. // since the thread object isn't entirely ready to be operated
  1480. // on by the GC. This could be fixed by tracking thread startup
  1481. // status, but it's far easier to simply have Thread.add wait
  1482. // for any running collection to stop before altering the thread
  1483. // list.
  1484. //
  1485. // After further testing, having add wait for a collect to end
  1486. // proved to have its own problems (explained in Thread.start),
  1487. // so add(Thread) is now being done in Thread.start. This
  1488. // reintroduced the deadlock issue mentioned in bugzilla 4890,
  1489. // which appears to have been solved by doing this same wait
  1490. // procedure in add(Context). These comments will remain in
  1491. // case other issues surface that require the startup state
  1492. // tracking described above.
  1493. while( true )
  1494. {
  1495. synchronized( slock )
  1496. {
  1497. if( !suspendDepth )
  1498. {
  1499. if( sm_tbeg )
  1500. {
  1501. t.next = sm_tbeg;
  1502. sm_tbeg.prev = t;
  1503. }
  1504. sm_tbeg = t;
  1505. ++sm_tlen;
  1506. return;
  1507. }
  1508. }
  1509. yield();
  1510. }
  1511. }
  1512. //
  1513. // Remove a thread from the global thread list.
  1514. //
  1515. static void remove( Thread t )
  1516. in
  1517. {
  1518. assert( t );
  1519. assert( t.next || t.prev );
  1520. }
  1521. body
  1522. {
  1523. synchronized( slock )
  1524. {
  1525. // NOTE: When a thread is removed from the global thread list its
  1526. // main context is invalid and should be removed as well.
  1527. // It is possible that t.m_curr could reference more
  1528. // than just the main context if the thread exited abnormally
  1529. // (if it was terminated), but we must assume that the user
  1530. // retains a reference to them and that they may be re-used
  1531. // elsewhere. Therefore, it is the responsibility of any
  1532. // object that creates contexts to clean them up properly
  1533. // when it is done with them.
  1534. remove( &t.m_main );
  1535. if( t.prev )
  1536. t.prev.next = t.next;
  1537. if( t.next )
  1538. t.next.prev = t.prev;
  1539. if( sm_tbeg == t )
  1540. sm_tbeg = t.next;
  1541. --sm_tlen;
  1542. }
  1543. // NOTE: Don't null out t.next or t.prev because opApply currently
  1544. // follows t.next after removing a node. This could be easily
  1545. // addressed by simply returning the next node from this
  1546. // function, however, a thread should never be re-added to the
  1547. // list anyway and having next and prev be non-null is a good way
  1548. // to ensure that.
  1549. }
  1550. }
  1551. // These must be kept in sync with core/thread.di
  1552. version (D_LP64)
  1553. {
  1554. version (Windows)
  1555. static assert(__traits(classInstanceSize, Thread) == 312);
  1556. else version (OSX)
  1557. static assert(__traits(classInstanceSize, Thread) == 320);
  1558. else version (Solaris)
  1559. static assert(__traits(classInstanceSize, Thread) == 176);
  1560. else version (Posix)
  1561. static assert(__traits(classInstanceSize, Thread) == 184);
  1562. else
  1563. static assert(0, "Platform not supported.");
  1564. }
  1565. else
  1566. {
  1567. static assert((void*).sizeof == 4); // 32-bit
  1568. version (Windows)
  1569. static assert(__traits(classInstanceSize, Thread) == 128);
  1570. else version (OSX)
  1571. static assert(__traits(classInstanceSize, Thread) == 128);
  1572. else version (Posix)
  1573. static assert(__traits(classInstanceSize, Thread) == 92);
  1574. else
  1575. static assert(0, "Platform not supported.");
  1576. }
  1577. unittest
  1578. {
  1579. int x = 0;
  1580. auto t = new Thread(
  1581. {
  1582. x++;
  1583. });
  1584. t.start(); t.join();
  1585. assert( x == 1 );
  1586. }
  1587. unittest
  1588. {
  1589. enum MSG = "Test message.";
  1590. string caughtMsg;
  1591. try
  1592. {
  1593. auto t = new Thread(
  1594. {
  1595. throw new Exception( MSG );
  1596. });
  1597. t.start(); t.join();
  1598. assert( false, "Expected rethrown exception." );
  1599. }
  1600. catch( Throwable t )
  1601. {
  1602. assert( t.msg == MSG );
  1603. }
  1604. }
  1605. ///////////////////////////////////////////////////////////////////////////////
  1606. // GC Support Routines
  1607. ///////////////////////////////////////////////////////////////////////////////
  1608. /**
  1609. * Initializes the thread module. This function must be called by the
  1610. * garbage collector on startup and before any other thread routines
  1611. * are called.
  1612. */
  1613. extern (C) void thread_init()
  1614. {
  1615. // NOTE: If thread_init itself performs any allocations then the thread
  1616. // routines reserved for garbage collector use may be called while
  1617. // thread_init is being processed. However, since no memory should
  1618. // exist to be scanned at this point, it is sufficient for these
  1619. // functions to detect the condition and return immediately.
  1620. version( Windows )
  1621. {
  1622. Thread.sm_this = TlsAlloc();
  1623. assert( Thread.sm_this != TLS_OUT_OF_INDEXES );
  1624. }
  1625. else version( OSX )
  1626. {
  1627. int status;
  1628. status = pthread_key_create( &Thread.sm_this, null );
  1629. assert( status == 0 );
  1630. }
  1631. else version( Posix )
  1632. {
  1633. int status;
  1634. sigaction_t sigusr1 = void;
  1635. sigaction_t sigusr2 = void;
  1636. // This is a quick way to zero-initialize the structs without using
  1637. // memset or creating a link dependency on their static initializer.
  1638. (cast(byte*) &sigusr1)[0 .. sigaction_t.sizeof] = 0;
  1639. (cast(byte*) &sigusr2)[0 .. sigaction_t.sizeof] = 0;
  1640. // NOTE: SA_RESTART indicates that system calls should restart if they
  1641. // are interrupted by a signal, but this is not available on all
  1642. // Posix systems, even those that support multithreading.
  1643. static if( __traits( compiles, SA_RESTART ) )
  1644. sigusr1.sa_flags = SA_RESTART;
  1645. else
  1646. sigusr1.sa_flags = 0;
  1647. sigusr1.sa_handler = &thread_suspendHandler;
  1648. // NOTE: We want to ignore all signals while in this handler, so fill
  1649. // sa_mask to indicate this.
  1650. status = sigfillset( &sigusr1.sa_mask );
  1651. assert( status == 0 );
  1652. // NOTE: Since SIGUSR2 should only be issued for threads within the
  1653. // suspend handler, we don't want this signal to trigger a
  1654. // restart.
  1655. sigusr2.sa_flags = 0;
  1656. sigusr2.sa_handler = &thread_resumeHandler;
  1657. // NOTE: We want to ignore all signals while in this handler, so fill
  1658. // sa_mask to indicate this.
  1659. status = sigfillset( &sigusr2.sa_mask );
  1660. assert( status == 0 );
  1661. status = sigaction( SIGUSR1, &sigusr1, null );
  1662. assert( status == 0 );
  1663. status = sigaction( SIGUSR2, &sigusr2, null );
  1664. assert( status == 0 );
  1665. status = sem_init( &suspendCount, 0, 0 );
  1666. assert( status == 0 );
  1667. status = pthread_key_create( &Thread.sm_this, null );
  1668. assert( status == 0 );
  1669. }
  1670. Thread.sm_main = thread_attachThis();
  1671. }
  1672. /**
  1673. *
  1674. */
  1675. extern (C) bool thread_isMainThread()
  1676. {
  1677. return Thread.getThis() is Thread.sm_main;
  1678. }
  1679. /**
  1680. * Registers the calling thread for use with the D Runtime. If this routine
  1681. * is called for a thread which is already registered, no action is performed.
  1682. */
  1683. extern (C) Thread thread_attachThis()
  1684. {
  1685. gc_disable(); scope(exit) gc_enable();
  1686. if (auto t = Thread.getThis())
  1687. return t;
  1688. Thread thisThread = new Thread();
  1689. Thread.Context* thisContext = &thisThread.m_main;
  1690. assert( thisContext == thisThread.m_curr );
  1691. version( Windows )
  1692. {
  1693. thisThread.m_addr = GetCurrentThreadId();
  1694. thisThread.m_hndl = GetCurrentThreadHandle();
  1695. thisContext.bstack = getStackBottom();
  1696. thisContext.tstack = thisContext.bstack;
  1697. }
  1698. else version( Posix )
  1699. {
  1700. thisThread.m_addr = pthread_self();
  1701. thisContext.bstack = getStackBottom();
  1702. thisContext.tstack = thisContext.bstack;
  1703. thisThread.m_isRunning = true;
  1704. }
  1705. thisThread.m_isDaemon = true;
  1706. Thread.setThis( thisThread );
  1707. version( OSX )
  1708. {
  1709. thisThread.m_tmach = pthread_mach_thread_np( thisThread.m_addr );
  1710. assert( thisThread.m_tmach != thisThread.m_tmach.init );
  1711. }
  1712. version (LDC_NoTlsBracketSyms) {} else
  1713. version (OSX)
  1714. {
  1715. //printf("test3 %p %p\n", _tls_data_array[0].ptr, &_tls_data_array[1][length]);
  1716. //printf("test3 %p %p\n", &_tls_beg, &_tls_end);
  1717. // NOTE: OSX does not support TLS, so we do it ourselves. The TLS
  1718. // data output by the compiler is bracketed by _tls_data_array[2],
  1719. // so make a copy of it for each thread.
  1720. const sz0 = (_tls_data_array[0].length + 15) & ~cast(size_t)15;
  1721. const sz2 = sz0 + _tls_data_array[1].length;
  1722. auto p = gc_malloc( sz2 );
  1723. assert( p );
  1724. thisThread.m_tls = p[0 .. sz2];
  1725. memcpy( p, _tls_data_array[0].ptr, _tls_data_array[0].length );
  1726. memcpy( p + sz0, _tls_data_array[1].ptr, _tls_data_array[1].length );
  1727. // used gc_malloc so no need to free
  1728. }
  1729. else
  1730. {
  1731. auto pstart = cast(void*) &_tlsstart;
  1732. auto pend = cast(void*) &_tlsend;
  1733. thisThread.m_tls = pstart[0 .. pend - pstart];
  1734. }
  1735. Thread.add( thisThread );
  1736. Thread.add( thisContext );
  1737. if( Thread.sm_main !is null )
  1738. multiThreadedFlag = true;
  1739. thisThread.m_tlsgcdata = rt.tlsgc.init();
  1740. return thisThread;
  1741. }
  1742. version( Windows )
  1743. {
  1744. // NOTE: These calls are not safe on Posix systems that use signals to
  1745. // perform garbage collection. The suspendHandler uses getThis()
  1746. // to get the thread handle so getThis() must be a simple call.
  1747. // Mutexes can't safely be acquired inside signal handlers, and
  1748. // even if they could, the mutex needed (Thread.slock) is held by
  1749. // thread_suspendAll(). So in short, these routines will remain
  1750. // Windows-specific. If they are truly needed elsewhere, the
  1751. // suspendHandler will need a way to call a version of getThis()
  1752. // that only does the TLS lookup without the fancy fallback stuff.
  1753. /// ditto
  1754. extern (C) Thread thread_attachByAddr( Thread.ThreadAddr addr )
  1755. {
  1756. return thread_attachByAddrB( addr, getThreadStackBottom( addr ) );
  1757. }
  1758. /// ditto
  1759. extern (C) Thread thread_attachByAddrB( Thread.ThreadAddr addr, void* bstack )
  1760. {
  1761. gc_disable(); scope(exit) gc_enable();
  1762. if (auto t = thread_findByAddr(addr))
  1763. return t;
  1764. Thread thisThread = new Thread();
  1765. Thread.Context* thisContext = &thisThread.m_main;
  1766. assert( thisContext == thisThread.m_curr );
  1767. thisThread.m_addr = addr;
  1768. thisContext.bstack = bstack;
  1769. thisContext.tstack = thisContext.bstack;
  1770. if( addr == GetCurrentThreadId() )
  1771. {
  1772. thisThread.m_hndl = GetCurrentThreadHandle();
  1773. }
  1774. else
  1775. {
  1776. thisThread.m_hndl = OpenThreadHandle( addr );
  1777. }
  1778. thisThread.m_isDaemon = true;
  1779. if( addr == GetCurrentThreadId() )
  1780. {
  1781. auto pstart = cast(void*) &_tlsstart;
  1782. auto pend = cast(void*) &_tlsend;
  1783. thisThread.m_tls = pstart[0 .. pend - pstart];
  1784. Thread.setThis( thisThread );
  1785. }
  1786. else
  1787. {
  1788. // TODO: This seems wrong. If we're binding threads from
  1789. // a DLL, will they always have space reserved for
  1790. // the TLS chunk we expect? I don't know Windows
  1791. // well enough to say.
  1792. auto pstart = cast(void*) &_tlsstart;
  1793. auto pend = cast(void*) &_tlsend;
  1794. auto pos = GetTlsDataAddress( thisThread.m_hndl );
  1795. if( pos ) // on x64, threads without TLS happen to exist
  1796. thisThread.m_tls = pos[0 .. pend - pstart];
  1797. else
  1798. thisThread.m_tls = [];
  1799. }
  1800. Thread.add( thisThread );
  1801. Thread.add( thisContext );
  1802. if( Thread.sm_main !is null )
  1803. multiThreadedFlag = true;
  1804. thisThread.m_tlsgcdata = rt.tlsgc.init();
  1805. return thisThread;
  1806. }
  1807. }
  1808. /**
  1809. * Deregisters the calling thread from use with the runtime. If this routine
  1810. * is called for a thread which is not registered, the result is undefined.
  1811. */
  1812. extern (C) void thread_detachThis()
  1813. {
  1814. if (auto t = Thread.getThis())
  1815. Thread.remove(t);
  1816. }
  1817. /// ditto
  1818. extern (C) void thread_detachByAddr( Thread.ThreadAddr addr )
  1819. {
  1820. if( auto t = thread_findByAddr( addr ) )
  1821. Thread.remove( t );
  1822. }
  1823. /**
  1824. * Search the list of all threads for a thread with the given thread identifier.
  1825. *
  1826. * Params:
  1827. * addr = The thread identifier to search for.
  1828. * Returns:
  1829. * The thread object associated with the thread identifier, null if not found.
  1830. */
  1831. static Thread thread_findByAddr( Thread.ThreadAddr addr )
  1832. {
  1833. synchronized( Thread.slock )
  1834. {
  1835. foreach( t; Thread )
  1836. {
  1837. if( t.m_addr == addr )
  1838. return t;
  1839. }
  1840. }
  1841. return null;
  1842. }
  1843. /**
  1844. * Sets the current thread to a specific reference. Only to be used
  1845. * when dealing with externally-created threads (in e.g. C code).
  1846. * The primary use of this function is when Thread.getThis() must
  1847. * return a sensible value in, for example, TLS destructors. In
  1848. * other words, don't touch this unless you know what you're doing.
  1849. *
  1850. * Params:
  1851. * t = A reference to the current thread. May be null.
  1852. */
  1853. extern (C) void thread_setThis(Thread t)
  1854. {
  1855. Thread.setThis(t);
  1856. }
  1857. /**
  1858. * Joins all non-daemon threads that are currently running. This is done by
  1859. * performing successive scans through the thread list until a scan consists
  1860. * of only daemon threads.
  1861. */
  1862. extern (C) void thread_joinAll()
  1863. {
  1864. while( true )
  1865. {
  1866. Thread nonDaemon = null;
  1867. foreach( t; Thread )
  1868. {
  1869. if( !t.isRunning )
  1870. {
  1871. Thread.remove( t );
  1872. continue;
  1873. }
  1874. if( !t.isDaemon )
  1875. {
  1876. nonDaemon = t;
  1877. break;
  1878. }
  1879. }
  1880. if( nonDaemon is null )
  1881. return;
  1882. nonDaemon.join();
  1883. }
  1884. }
  1885. /**
  1886. * Performs intermediate shutdown of the thread module.
  1887. */
  1888. shared static ~this()
  1889. {
  1890. // NOTE: The functionality related to garbage collection must be minimally
  1891. // operable after this dtor completes. Therefore, only minimal
  1892. // cleanup may occur.
  1893. for( Thread t = Thread.sm_tbeg; t; t = t.next )
  1894. {
  1895. if( !t.isRunning )
  1896. Thread.remove( t );
  1897. }
  1898. }
  1899. // Used for needLock below.
  1900. private __gshared bool multiThreadedFlag = false;
  1901. version (PPC64) version = ExternStackShell;
  1902. version (ExternStackShell)
  1903. {
  1904. extern(D) public void callWithStackShell(scope void delegate(void* sp) fn);
  1905. }
  1906. else
  1907. {
  1908. // Calls the given delegate, passing the current thread's stack pointer to it.
  1909. private void callWithStackShell(scope void delegate(void* sp) fn)
  1910. in
  1911. {
  1912. assert(fn);
  1913. }
  1914. body
  1915. {
  1916. // The purpose of the 'shell' is to ensure all the registers get
  1917. // put on the stack so they'll be scanned. We only need to push
  1918. // the callee-save registers.
  1919. void *sp = void;
  1920. version (GNU)
  1921. {
  1922. __builtin_unwind_init();
  1923. sp = &sp;
  1924. }
  1925. else version (AsmX86_Posix)
  1926. {
  1927. size_t[3] regs = void;
  1928. asm
  1929. {
  1930. mov [regs + 0 * 4], EBX;
  1931. mov [regs + 1 * 4], ESI;
  1932. mov [regs + 2 * 4], EDI;
  1933. mov sp[EBP], ESP;
  1934. }
  1935. }
  1936. else version (AsmX86_Windows)
  1937. {
  1938. size_t[3] regs = void;
  1939. asm
  1940. {
  1941. mov [regs + 0 * 4], EBX;
  1942. mov [regs + 1 * 4], ESI;
  1943. mov [regs + 2 * 4], EDI;
  1944. mov sp[EBP], ESP;
  1945. }
  1946. }
  1947. else version (AsmX86_64_Posix)
  1948. {
  1949. size_t[5] regs = void;
  1950. asm
  1951. {
  1952. mov [regs + 0 * 8], RBX;
  1953. mov [regs + 1 * 8], R12;
  1954. mov [regs + 2 * 8], R13;
  1955. mov [regs + 3 * 8], R14;
  1956. mov [regs + 4 * 8], R15;
  1957. mov sp[RBP], RSP;
  1958. }
  1959. }
  1960. else version (AsmX86_64_Windows)
  1961. {
  1962. size_t[7] regs = void;
  1963. asm
  1964. {
  1965. mov [regs + 0 * 8], RBX;
  1966. mov [regs + 1 * 8], RSI;
  1967. mov [regs + 2 * 8], RDI;
  1968. mov [regs + 3 * 8], R12;
  1969. mov [regs + 4 * 8], R13;
  1970. mov [regs + 5 * 8], R14;
  1971. mov [regs + 6 * 8], R15;
  1972. mov sp[RBP], RSP;
  1973. }
  1974. }
  1975. else version (ARM)
  1976. {
  1977. import ldc.llvmasm;
  1978. // Callee-save registers, according to AAPCS, section 5.1.1.
  1979. // FIXME: As loads/stores are explicit on ARM, the code generated for
  1980. // this is horrible. Better write the entire function in ASM.
  1981. size_t[8] regs = void;
  1982. __asm("str r4, $0", "=*m", regs.ptr + 0);
  1983. __asm("str r5, $0", "=*m", regs.ptr + 1);
  1984. __asm("str r6, $0", "=*m", regs.ptr + 2);
  1985. __asm("str r7, $0", "=*m", regs.ptr + 3);
  1986. __asm("str r8, $0", "=*m", regs.ptr + 4);
  1987. __asm("str r9, $0", "=*m", regs.ptr + 5);
  1988. __asm("str r10, $0", "=*m", regs.ptr + 6);
  1989. __asm("str r11, $0", "=*m", regs.ptr + 7);
  1990. __asm("str sp, $0", "=*m", &sp);
  1991. }
  1992. else
  1993. {
  1994. static assert(false, "Architecture not supported.");
  1995. }
  1996. fn(sp);
  1997. }
  1998. }
  1999. // Used for suspendAll/resumeAll below.
  2000. private __gshared uint suspendDepth = 0;
  2001. /**
  2002. * Suspend the specified thread and load stack and register information for
  2003. * use by thread_scanAll. If the supplied thread is the calling thread,
  2004. * stack and register information will be loaded but the thread will not
  2005. * be suspended. If the suspend operation fails and the thread is not
  2006. * running then it will be removed from the global thread list, otherwise
  2007. * an exception will be thrown.
  2008. *
  2009. * Params:
  2010. * t = The thread to suspend.
  2011. *
  2012. * Throws:
  2013. * ThreadException if the suspend operation fails for a running thread.
  2014. */
  2015. private void suspend( Thread t )
  2016. {
  2017. version( Windows )
  2018. {
  2019. if( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF )
  2020. {
  2021. if( !t.isRunning )
  2022. {
  2023. Thread.remove( t );
  2024. return;
  2025. }
  2026. throw new ThreadException( "Unable to suspend thread" );
  2027. }
  2028. CONTEXT context = void;
  2029. context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
  2030. if( !GetThreadContext( t.m_hndl, &context ) )
  2031. throw new ThreadException( "Unable to load thread context" );
  2032. version( X86 )
  2033. {
  2034. if( !t.m_lock )
  2035. t.m_curr.tstack = cast(void*) context.Esp;
  2036. // eax,ebx,ecx,edx,edi,esi,ebp,esp
  2037. t.m_reg[0] = context.Eax;
  2038. t.m_reg[1] = context.Ebx;
  2039. t.m_reg[2] = context.Ecx;
  2040. t.m_reg[3] = context.Edx;
  2041. t.m_reg[4] = context.Edi;
  2042. t.m_reg[5] = context.Esi;
  2043. t.m_reg[6] = context.Ebp;
  2044. t.m_reg[7] = context.Esp;
  2045. }
  2046. else version( X86_64 )
  2047. {
  2048. if( !t.m_lock )
  2049. t.m_curr.tstack = cast(void*) context.Rsp;
  2050. // rax,rbx,rcx,rdx,rdi,rsi,rbp,rsp
  2051. t.m_reg[0] = context.Rax;
  2052. t.m_reg[1] = context.Rbx;
  2053. t.m_reg[2] = context.Rcx;
  2054. t.m_reg[3] = context.Rdx;
  2055. t.m_reg[4] = context.Rdi;
  2056. t.m_reg[5] = context.Rsi;
  2057. t.m_reg[6] = context.Rbp;
  2058. t.m_reg[7] = context.Rsp;
  2059. // r8,r9,r10,r11,r12,r13,r14,r15
  2060. t.m_reg[8] = context.R8;
  2061. t.m_reg[9] = context.R9;
  2062. t.m_reg[10] = context.R10;
  2063. t.m_reg[11] = context.R11;
  2064. t.m_reg[12] = context.R12;
  2065. t.m_reg[13] = context.R13;
  2066. t.m_reg[14] = context.R14;
  2067. t.m_reg[15] = context.R15;
  2068. }
  2069. else
  2070. {
  2071. static assert(false, "Architecture not supported." );
  2072. }
  2073. }
  2074. else version( OSX )
  2075. {
  2076. if( t.m_addr != pthread_self() && thread_suspend( t.m_tmach ) != KERN_SUCCESS )
  2077. {
  2078. if( !t.isRunning )
  2079. {
  2080. Thread.remove( t );
  2081. return;
  2082. }
  2083. throw new ThreadException( "Unable to suspend thread" );
  2084. }
  2085. version( X86 )
  2086. {
  2087. x86_thread_state32_t state = void;
  2088. mach_msg_type_number_t count = x86_THREAD_STATE32_COUNT;
  2089. if( thread_get_state( t.m_tmach, x86_THREAD_STATE32, &state, &count ) != KERN_SUCCESS )
  2090. throw new ThreadException( "Unable to load thread state" );
  2091. if( !t.m_lock )
  2092. t.m_curr.tstack = cast(void*) state.esp;
  2093. // eax,ebx,ecx,edx,edi,esi,ebp,esp
  2094. t.m_reg[0] = state.eax;
  2095. t.m_reg[1] = state.ebx;
  2096. t.m_reg[2] = state.ecx;
  2097. t.m_reg[3] = state.edx;
  2098. t.m_reg[4] = state.edi;
  2099. t.m_reg[5] = state.esi;
  2100. t.m_reg[6] = state.ebp;
  2101. t.m_reg[7] = state.esp;
  2102. }
  2103. else version( X86_64 )
  2104. {
  2105. x86_thread_state64_t state = void;
  2106. mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
  2107. if( thread_get_state( t.m_tmach, x86_THREAD_STATE64, &state, &count ) != KERN_SUCCESS )
  2108. throw new ThreadException( "Unable to load thread state" );
  2109. if( !t.m_lock )
  2110. t.m_curr.tstack = cast(void*) state.rsp;
  2111. // rax,rbx,rcx,rdx,rdi,rsi,rbp,rsp
  2112. t.m_reg[0] = state.rax;
  2113. t.m_reg[1] = state.rbx;
  2114. t.m_reg[2] = state.rcx;
  2115. t.m_reg[3] = state.rdx;
  2116. t.m_reg[4] = state.rdi;
  2117. t.m_reg[5] = state.rsi;
  2118. t.m_reg[6] = state.rbp;
  2119. t.m_reg[7] = state.rsp;
  2120. // r8,r9,r10,r11,r12,r13,r14,r15
  2121. t.m_reg[8] = state.r8;
  2122. t.m_reg[9] = state.r9;
  2123. t.m_reg[10] = state.r10;
  2124. t.m_reg[11] = state.r11;
  2125. t.m_reg[12] = state.r12;
  2126. t.m_reg[13] = state.r13;
  2127. t.m_reg[14] = state.r14;
  2128. t.m_reg[15] = state.r15;
  2129. }
  2130. else
  2131. {
  2132. static assert(false, "Architecture not supported." );
  2133. }
  2134. }
  2135. else version( Posix )
  2136. {
  2137. if( t.m_addr != pthread_self() )
  2138. {
  2139. if( pthread_kill( t.m_addr, SIGUSR1 ) != 0 )
  2140. {
  2141. if( !t.isRunning )
  2142. {
  2143. Thread.remove( t );
  2144. return;
  2145. }
  2146. throw new ThreadException( "Unable to suspend thread" );
  2147. }
  2148. // NOTE: It's really not ideal to wait for each thread to
  2149. // signal individually -- rather, it would be better to
  2150. // suspend them all and wait once at the end. However,
  2151. // semaphores don't really work this way, and the obvious
  2152. // alternative (looping on an atomic suspend count)
  2153. // requires either the atomic module (which only works on
  2154. // x86) or other specialized functionality. It would
  2155. // also be possible to simply loop on sem_wait at the
  2156. // end, but I'm not convinced that this would be much
  2157. // faster than the current approach.
  2158. sem_wait( &suspendCount );
  2159. }
  2160. else if( !t.m_lock )
  2161. {
  2162. t.m_curr.tstack = getStackTop();
  2163. }
  2164. }
  2165. }
  2166. /**
  2167. * Suspend all threads but the calling thread for "stop the world" garbage
  2168. * collection runs. This function may be called multiple times, and must
  2169. * be followed by a matching number of calls to thread_resumeAll before
  2170. * processing is resumed.
  2171. *
  2172. * Throws:
  2173. * ThreadException if the suspend operation fails for a running thread.
  2174. */
  2175. extern (C) void thread_suspendAll()
  2176. {
  2177. // NOTE: We've got an odd chicken & egg problem here, because while the GC
  2178. // is required to call thread_init before calling any other thread
  2179. // routines, thread_init may allocate memory which could in turn
  2180. // trigger a collection. Thus, thread_suspendAll, thread_scanAll,
  2181. // and thread_resumeAll must be callable before thread_init
  2182. // completes, with the assumption that no other GC memory has yet
  2183. // been allocated by the system, and thus there is no risk of losing
  2184. // data if the global thread list is empty. The check of
  2185. // Thread.sm_tbeg below is done to ensure thread_init has completed,
  2186. // and therefore that calling Thread.getThis will not result in an
  2187. // error. For the short time when Thread.sm_tbeg is null, there is
  2188. // no reason not to simply call the multithreaded code below, with
  2189. // the expectation that the foreach loop will never be entered.
  2190. if( !multiThreadedFlag && Thread.sm_tbeg )
  2191. {
  2192. if( ++suspendDepth == 1 )
  2193. suspend( Thread.getThis() );
  2194. return;
  2195. }
  2196. Thread.slock.lock();
  2197. {
  2198. if( ++suspendDepth > 1 )
  2199. return;
  2200. // NOTE: I'd really prefer not to check isRunning within this loop but
  2201. // not doing so could be problematic if threads are terminated
  2202. // abnormally and a new thread is created with the same thread
  2203. // address before the next GC run. This situation might cause
  2204. // the same thread to be suspended twice, which would likely
  2205. // cause the second suspend to fail, the garbage collection to
  2206. // abort, and Bad Things to occur.
  2207. for( Thread t = Thread.sm_tbeg; t; t = t.next )
  2208. {
  2209. if( t.isRunning )
  2210. suspend( t );
  2211. else
  2212. Thread.remove( t );
  2213. }
  2214. // The world is stopped. We now make sure that all threads are outside
  2215. // critical regions by continually suspending and resuming them until all
  2216. // of them are safe. This is extremely error-prone; if some thread enters
  2217. // a critical region and never exits it (e.g. it waits for a mutex forever),
  2218. // then we'll pretty much 'deadlock' here. Not much we can do about that,
  2219. // and it indicates incorrect use of the critical region API anyway.
  2220. for (;;)
  2221. {
  2222. uint unsafeCount;
  2223. for (auto t = Thread.sm_tbeg; t; t = t.next)
  2224. {
  2225. // NOTE: We don't need to check whether the thread has died here,
  2226. // since it's checked in the loops above and below.
  2227. if (atomicLoad(*cast(shared)&t.m_isInCriticalRegion))
  2228. {
  2229. unsafeCount += 10;
  2230. resume(t);
  2231. }
  2232. }
  2233. // If all threads are safe (i.e. unsafeCount == 0), no threads were in
  2234. // critical regions in the first place, and we can just break. Otherwise,
  2235. // we sleep for a bit to give the threads a chance to get to safe points.
  2236. if (unsafeCount)
  2237. Thread.sleep(dur!"usecs"(unsafeCount)); // This heuristic could probably use some tuning.
  2238. else
  2239. break;
  2240. // Some thread was not in a safe region, so we suspend the world again to
  2241. // re-do this loop to check whether we're safe now.
  2242. for (auto t = Thread.sm_tbeg; t; t = t.next)
  2243. {
  2244. // The thread could have died in the meantime. Also see the note in
  2245. // the topmost loop that initially suspends the world.
  2246. if (t.isRunning)
  2247. suspend(t);
  2248. else
  2249. Thread.remove(t);
  2250. }
  2251. }
  2252. version( Posix )
  2253. {
  2254. // wait on semaphore -- see note in suspend for
  2255. // why this is currently not implemented
  2256. }
  2257. }
  2258. }
  2259. /**
  2260. * Resume the specified thread and unload stack and register information.
  2261. * If the supplied thread is the calling thread, stack and register
  2262. * information will be unloaded but the thread will not be resumed. If
  2263. * the resume operation fails and the thread is not running then it will
  2264. * be removed from the global thread list, otherwise an exception will be
  2265. * thrown.
  2266. *
  2267. * Params:
  2268. * t = The thread to resume.
  2269. *
  2270. * Throws:
  2271. * ThreadException if the resume fails for a running thread.
  2272. */
  2273. private void resume( Thread t )
  2274. {
  2275. version( Windows )
  2276. {
  2277. if( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF )
  2278. {
  2279. if( !t.isRunning )
  2280. {
  2281. Thread.remove( t );
  2282. return;
  2283. }
  2284. throw new ThreadException( "Unable to resume thread" );
  2285. }
  2286. if( !t.m_lock )
  2287. t.m_curr.tstack = t.m_curr.bstack;
  2288. t.m_reg[0 .. $] = 0;
  2289. }
  2290. else version( OSX )
  2291. {
  2292. if( t.m_addr != pthread_self() && thread_resume( t.m_tmach ) != KERN_SUCCESS )
  2293. {
  2294. if( !t.isRunning )
  2295. {
  2296. Thread.remove( t );
  2297. return;
  2298. }
  2299. throw new ThreadException( "Unable to resume thread" );
  2300. }
  2301. if( !t.m_lock )
  2302. t.m_curr.tstack = t.m_curr.bstack;
  2303. t.m_reg[0 .. $] = 0;
  2304. }
  2305. else version( Posix )
  2306. {
  2307. if( t.m_addr != pthread_self() )
  2308. {
  2309. if( pthread_kill( t.m_addr, SIGUSR2 ) != 0 )
  2310. {
  2311. if( !t.isRunning )
  2312. {
  2313. Thread.remove( t );
  2314. return;
  2315. }
  2316. throw new ThreadException( "Unable to resume thread" );
  2317. }
  2318. }
  2319. else if( !t.m_lock )
  2320. {
  2321. t.m_curr.tstack = t.m_curr.bstack;
  2322. }
  2323. }
  2324. }
  2325. /**
  2326. * Resume all threads but the calling thread for "stop the world" garbage
  2327. * collection runs. This function must be called once for each preceding
  2328. * call to thread_suspendAll before the threads are actually resumed.
  2329. *
  2330. * In:
  2331. * This routine must be preceded by a call to thread_suspendAll.
  2332. *
  2333. * Throws:
  2334. * ThreadException if the resume operation fails for a running thread.
  2335. */
  2336. extern (C) void thread_resumeAll()
  2337. in
  2338. {
  2339. assert( suspendDepth > 0 );
  2340. }
  2341. body
  2342. {
  2343. // NOTE: See thread_suspendAll for the logic behind this.
  2344. if( !multiThreadedFlag && Thread.sm_tbeg )
  2345. {
  2346. if( --suspendDepth == 0 )
  2347. resume( Thread.getThis() );
  2348. return;
  2349. }
  2350. scope(exit) Thread.slock.unlock();
  2351. {
  2352. if( --suspendDepth > 0 )
  2353. return;
  2354. for( Thread t = Thread.sm_tbeg; t; t = t.next )
  2355. {
  2356. // NOTE: We do not need to care about critical regions at all
  2357. // here. thread_suspendAll takes care of everything.
  2358. resume( t );
  2359. }
  2360. }
  2361. }
  2362. enum ScanType
  2363. {
  2364. stack,
  2365. tls,
  2366. }
  2367. alias void delegate(void*, void*) ScanAllThreadsFn;
  2368. alias void delegate(ScanType, void*, void*) ScanAllThreadsTypeFn;
  2369. extern (C) void thread_scanAllType( scope ScanAllThreadsTypeFn scan )
  2370. in
  2371. {
  2372. assert( suspendDepth > 0 );
  2373. }
  2374. body
  2375. {
  2376. callWithStackShell(sp => scanAllTypeImpl(scan, sp));
  2377. }
  2378. private void scanAllTypeImpl( scope ScanAllThreadsTypeFn scan, void* curStackTop )
  2379. {
  2380. Thread thisThread = null;
  2381. void* oldStackTop = null;
  2382. if( Thread.sm_tbeg )
  2383. {
  2384. thisThread = Thread.getThis();
  2385. if( !thisThread.m_lock )
  2386. {
  2387. oldStackTop = thisThread.m_curr.tstack;
  2388. thisThread.m_curr.tstack = curStackTop;
  2389. }
  2390. }
  2391. scope( exit )
  2392. {
  2393. if( Thread.sm_tbeg )
  2394. {
  2395. if( !thisThread.m_lock )
  2396. {
  2397. thisThread.m_curr.tstack = oldStackTop;
  2398. }
  2399. }
  2400. }
  2401. // NOTE: Synchronizing on Thread.slock is not needed because this
  2402. // function may only be called after all other threads have
  2403. // been suspended from within the same lock.
  2404. for( Thread.Context* c = Thread.sm_cbeg; c; c = c.next )
  2405. {
  2406. version( StackGrowsDown )
  2407. {
  2408. // NOTE: We can't index past the bottom of the stack
  2409. // so don't do the "+1" for StackGrowsDown.
  2410. if( c.tstack && c.tstack < c.bstack )
  2411. scan( ScanType.stack, c.tstack, c.bstack );
  2412. }
  2413. else
  2414. {
  2415. if( c.bstack && c.bstack < c.tstack )
  2416. scan( ScanType.stack, c.bstack, c.tstack + 1 );
  2417. }
  2418. }
  2419. for( Thread t = Thread.sm_tbeg; t; t = t.next )
  2420. {
  2421. scan( ScanType.tls, t.m_tls.ptr, t.m_tls.ptr + t.m_tls.length );
  2422. version( Windows )
  2423. {
  2424. // Ideally, we'd pass ScanType.regs or something like that, but this
  2425. // would make portability annoying because it only makes sense on Windows.
  2426. scan( ScanType.stack, t.m_reg.ptr, t.m_reg.ptr + t.m_reg.length );
  2427. }
  2428. rt.tlsgc.scan(t.m_tlsgcdata, (p1, p2) => scan(ScanType.tls, p1, p2));
  2429. }
  2430. }
  2431. extern (C) void thread_scanAll( scope ScanAllThreadsFn scan )
  2432. {
  2433. thread_scanAllType((type, p1, p2) => scan(p1, p2));
  2434. }
  2435. extern (C) void thread_enterCriticalRegion()
  2436. in
  2437. {
  2438. assert(Thread.getThis());
  2439. }
  2440. body
  2441. {
  2442. atomicStore(*cast(shared)&Thread.getThis().m_isInCriticalRegion, true);
  2443. }
  2444. extern (C) void thread_exitCriticalRegion()
  2445. in
  2446. {
  2447. assert(Thread.getThis());
  2448. }
  2449. body
  2450. {
  2451. atomicStore(*cast(shared)&Thread.getThis().m_isInCriticalRegion, false);
  2452. }
  2453. extern (C) bool thread_inCriticalRegion()
  2454. in
  2455. {
  2456. assert(Thread.getThis());
  2457. }
  2458. body
  2459. {
  2460. return atomicLoad(*cast(shared)&Thread.getThis().m_isInCriticalRegion);
  2461. }
  2462. unittest
  2463. {
  2464. assert(!thread_inCriticalRegion());
  2465. {
  2466. thread_enterCriticalRegion();
  2467. scope (exit)
  2468. thread_exitCriticalRegion();
  2469. assert(thread_inCriticalRegion());
  2470. }
  2471. assert(!thread_inCriticalRegion());
  2472. }
  2473. unittest
  2474. {
  2475. // NOTE: This entire test is based on the assumption that no
  2476. // memory is allocated after the child thread is
  2477. // started. If an allocation happens, a collection could
  2478. // trigger, which would cause the synchronization below
  2479. // to cause a deadlock.
  2480. // NOTE: DO NOT USE LOCKS IN CRITICAL REGIONS IN NORMAL CODE.
  2481. import core.sync.condition;
  2482. bool critical;
  2483. auto cond1 = new Condition(new Mutex());
  2484. bool stop;
  2485. auto cond2 = new Condition(new Mutex());
  2486. auto thr = new Thread(delegate void()
  2487. {
  2488. thread_enterCriticalRegion();
  2489. assert(thread_inCriticalRegion());
  2490. assert(atomicLoad(*cast(shared)&Thread.getThis().m_isInCriticalRegion));
  2491. synchronized (cond1.mutex)
  2492. {
  2493. critical = true;
  2494. cond1.notify();
  2495. }
  2496. synchronized (cond2.mutex)
  2497. while (!stop)
  2498. cond2.wait();
  2499. assert(thread_inCriticalRegion());
  2500. assert(atomicLoad(*cast(shared)&Thread.getThis().m_isInCriticalRegion));
  2501. thread_exitCriticalRegion();
  2502. assert(!thread_inCriticalRegion());
  2503. assert(!atomicLoad(*cast(shared)&Thread.getThis().m_isInCriticalRegion));
  2504. });
  2505. thr.start();
  2506. synchronized (cond1.mutex)
  2507. while (!critical)
  2508. cond1.wait();
  2509. assert(atomicLoad(*cast(shared)&thr.m_isInCriticalRegion));
  2510. synchronized (cond2.mutex)
  2511. {
  2512. stop = true;
  2513. cond2.notify();
  2514. }
  2515. thr.join();
  2516. }
  2517. /**
  2518. * This routine allows the runtime to process any special per-thread handling
  2519. * for the GC. This is needed for taking into account any memory that is
  2520. * referenced by non-scanned pointers but is about to be freed. That currently
  2521. * means the array append cache.
  2522. *
  2523. * Params:
  2524. * hasMarks = The probe function. It should return true for pointers into marked memory blocks.
  2525. *
  2526. * In:
  2527. * This routine must be called just prior to resuming all threads.
  2528. */
  2529. extern(C) void thread_processGCMarks(scope rt.tlsgc.IsMarkedDg dg)
  2530. {
  2531. for( Thread t = Thread.sm_tbeg; t; t = t.next )
  2532. {
  2533. /* Can be null if collection was triggered between adding a
  2534. * thread and calling rt.tlsgc.init.
  2535. */
  2536. if (t.m_tlsgcdata !is null)
  2537. rt.tlsgc.processGCMarks(t.m_tlsgcdata, dg);
  2538. }
  2539. }
  2540. extern (C)
  2541. {
  2542. version (linux) int pthread_getattr_np(pthread_t thread, pthread_attr_t* attr);
  2543. version (FreeBSD) int pthread_attr_get_np(pthread_t thread, pthread_attr_t* attr);
  2544. version (Solaris) int thr_stksegment(stack_t* stk);
  2545. }
  2546. private void* getStackTop()
  2547. {
  2548. version (LDC)
  2549. {
  2550. /* The inline assembler is written in a style that the code can be
  2551. * inlined.
  2552. * The use of intrinsic llvm_frameaddress is a reasonable default for
  2553. * cpu architectures without assembler support from LLVM. Because of
  2554. * the slightly different meaning the code must not be inlined.
  2555. */
  2556. version (D_InlineAsm_X86)
  2557. {
  2558. import ldc.llvmasm;
  2559. pragma(LDC_allow_inline);
  2560. return __asm!(void *)("movl %esp, $0", "=r");
  2561. }
  2562. else version (D_InlineAsm_X86_64)
  2563. {
  2564. import ldc.llvmasm;
  2565. pragma(LDC_allow_inline);
  2566. return __asm!(void *)("movq %rsp, $0", "=r");
  2567. }
  2568. else
  2569. {
  2570. import ldc.intrinsics;
  2571. pragma(LDC_never_inline);
  2572. return llvm_frameaddress(0);
  2573. }
  2574. }
  2575. else version (D_InlineAsm_X86)
  2576. asm { naked; mov EAX, ESP; ret; }
  2577. else version (D_InlineAsm_X86_64)
  2578. asm { naked; mov RAX, RSP; ret; }
  2579. else version (GNU)
  2580. return __builtin_frame_address(0);
  2581. else
  2582. static assert(false, "Architecture not supported.");
  2583. }
  2584. private void* getStackBottom()
  2585. {
  2586. version (Windows)
  2587. {
  2588. version (D_InlineAsm_X86)
  2589. asm { naked; mov EAX, FS:4; ret; }
  2590. else version(D_InlineAsm_X86_64)
  2591. asm
  2592. { naked;
  2593. mov RAX, 8;
  2594. mov RAX, GS:[RAX];
  2595. ret;
  2596. }
  2597. else
  2598. static assert(false, "Architecture not supported.");
  2599. }
  2600. else version (OSX)
  2601. {
  2602. import core.sys.osx.pthread;
  2603. return pthread_get_stackaddr_np(pthread_self());
  2604. }
  2605. else version (linux)
  2606. {
  2607. pthread_attr_t attr;
  2608. void* addr; size_t size;
  2609. pthread_getattr_np(pthread_self(), &attr);
  2610. pthread_attr_getstack(&attr, &addr, &size);
  2611. pthread_attr_destroy(&attr);
  2612. return addr + size;
  2613. }
  2614. else version (FreeBSD)
  2615. {
  2616. pthread_attr_t attr;
  2617. void* addr; size_t size;
  2618. pthread_attr_init(&attr);
  2619. pthread_attr_get_np(pthread_self(), &attr);
  2620. pthread_attr_getstack(&attr, &addr, &size);
  2621. pthread_attr_destroy(&attr);
  2622. return addr + size;
  2623. }
  2624. else version (Solaris)
  2625. {
  2626. stack_t stk;
  2627. thr_stksegment(&stk);
  2628. return stk.ss_sp;
  2629. }
  2630. else
  2631. static assert(false, "Platform not supported.");
  2632. }
  2633. extern (C) void* thread_stackTop()
  2634. in
  2635. {
  2636. // Not strictly required, but it gives us more flexibility.
  2637. assert(Thread.getThis());
  2638. }
  2639. body
  2640. {
  2641. return getStackTop();
  2642. }
  2643. extern (C) void* thread_stackBottom()
  2644. in
  2645. {
  2646. assert(Thread.getThis());
  2647. }
  2648. body
  2649. {
  2650. return Thread.getThis().topContext().bstack;
  2651. }
  2652. ///////////////////////////////////////////////////////////////////////////////
  2653. // Thread Group
  2654. ///////////////////////////////////////////////////////////////////////////////
  2655. /**
  2656. * This class is intended to simplify certain common programming techniques.
  2657. */
  2658. class ThreadGroup
  2659. {
  2660. /**
  2661. * Creates and starts a new Thread object that executes fn and adds it to
  2662. * the list of tracked threads.
  2663. *
  2664. * Params:
  2665. * fn = The thread function.
  2666. *
  2667. * Returns:
  2668. * A reference to the newly created thread.
  2669. */
  2670. final Thread create( void function() fn )
  2671. {
  2672. Thread t = new Thread( fn );
  2673. t.start();
  2674. synchronized( this )
  2675. {
  2676. m_all[t] = t;
  2677. }
  2678. return t;
  2679. }
  2680. /**
  2681. * Creates and starts a new Thread object that executes dg and adds it to
  2682. * the list of tracked threads.
  2683. *
  2684. * Params:
  2685. * dg = The thread function.
  2686. *
  2687. * Returns:
  2688. * A reference to the newly created thread.
  2689. */
  2690. final Thread create( void delegate() dg )
  2691. {
  2692. Thread t = new Thread( dg );
  2693. t.start();
  2694. synchronized( this )
  2695. {
  2696. m_all[t] = t;
  2697. }
  2698. return t;
  2699. }
  2700. /**
  2701. * Add t to the list of tracked threads if it is not already being tracked.
  2702. *
  2703. * Params:
  2704. * t = The thread to add.
  2705. *
  2706. * In:
  2707. * t must not be null.
  2708. */
  2709. final void add( Thread t )
  2710. in
  2711. {
  2712. assert( t );
  2713. }
  2714. body
  2715. {
  2716. synchronized( this )
  2717. {
  2718. m_all[t] = t;
  2719. }
  2720. }
  2721. /**
  2722. * Removes t from the list of tracked threads. No operation will be
  2723. * performed if t is not currently being tracked by this object.
  2724. *
  2725. * Params:
  2726. * t = The thread to remove.
  2727. *
  2728. * In:
  2729. * t must not be null.
  2730. */
  2731. final void remove( Thread t )
  2732. in
  2733. {
  2734. assert( t );
  2735. }
  2736. body
  2737. {
  2738. synchronized( this )
  2739. {
  2740. m_all.remove( t );
  2741. }
  2742. }
  2743. /**
  2744. * Operates on all threads currently tracked by this object.
  2745. */
  2746. final int opApply( scope int delegate( ref Thread ) dg )
  2747. {
  2748. synchronized( this )
  2749. {
  2750. int ret = 0;
  2751. // NOTE: This loop relies on the knowledge that m_all uses the
  2752. // Thread object for both the key and the mapped value.
  2753. foreach( Thread t; m_all.keys )
  2754. {
  2755. ret = dg( t );
  2756. if( ret )
  2757. break;
  2758. }
  2759. return ret;
  2760. }
  2761. }
  2762. /**
  2763. * Iteratively joins all tracked threads. This function will block add,
  2764. * remove, and opApply until it completes.
  2765. *
  2766. * Params:
  2767. * rethrow = Rethrow any unhandled exception which may have caused the
  2768. * current thread to terminate.
  2769. *
  2770. * Throws:
  2771. * Any exception not handled by the joined threads.
  2772. */
  2773. final void joinAll( bool rethrow = true )
  2774. {
  2775. synchronized( this )
  2776. {
  2777. // NOTE: This loop relies on the knowledge that m_all uses the
  2778. // Thread object for both the key and the mapped value.
  2779. foreach( Thread t; m_all.keys )
  2780. {
  2781. t.join( rethrow );
  2782. }
  2783. }
  2784. }
  2785. private:
  2786. Thread[Thread] m_all;
  2787. }
  2788. // These must be kept in sync with core/thread.di
  2789. version (D_LP64)
  2790. {
  2791. static assert(__traits(classInstanceSize, ThreadGroup) == 24);
  2792. }
  2793. else
  2794. {
  2795. static assert((void*).sizeof == 4); // 32-bit
  2796. static assert(__traits(classInstanceSize, ThreadGroup) == 12);
  2797. }
  2798. ///////////////////////////////////////////////////////////////////////////////
  2799. // Fiber Platform Detection and Memory Allocation
  2800. ///////////////////////////////////////////////////////////////////////////////
  2801. private
  2802. {
  2803. version( D_InlineAsm_X86 )
  2804. {
  2805. version( Windows )
  2806. version = AsmX86_Windows;
  2807. else version( Posix )
  2808. version = AsmX86_Posix;
  2809. version( OSX )
  2810. version = AlignFiberStackTo16Byte;
  2811. }
  2812. else version( D_InlineAsm_X86_64 )
  2813. {
  2814. version( Windows )
  2815. {
  2816. version = AsmX86_64_Windows;
  2817. version = AlignFiberStackTo16Byte;
  2818. }
  2819. else version( Posix )
  2820. {
  2821. version = AsmX86_64_Posix;
  2822. version = AlignFiberStackTo16Byte;
  2823. }
  2824. }
  2825. else version( PPC )
  2826. {
  2827. version( Posix )
  2828. {
  2829. version = AsmPPC_Posix;
  2830. version = AsmExternal;
  2831. }
  2832. }
  2833. else version( MIPS_O32 )
  2834. {
  2835. version( Posix )
  2836. {
  2837. version = AsmMIPS_O32_Posix;
  2838. version = AsmExternal;
  2839. }
  2840. }
  2841. version( Posix )
  2842. {
  2843. import core.sys.posix.unistd; // for sysconf
  2844. version( AsmX86_Windows ) {} else
  2845. version( AsmX86_Posix ) {} else
  2846. version( AsmX86_64_Windows ) {} else
  2847. version( AsmX86_64_Posix ) {} else
  2848. version( AsmExternal ) {} else
  2849. {
  2850. // NOTE: The ucontext implementation requires architecture specific
  2851. // data definitions to operate so testing for it must be done
  2852. // by checking for the existence of ucontext_t rather than by
  2853. // a version identifier. Please note that this is considered
  2854. // an obsolescent feature according to the POSIX spec, so a
  2855. // custom solution is still preferred.
  2856. import core.sys.posix.ucontext;
  2857. }
  2858. }
  2859. __gshared const size_t PAGESIZE;
  2860. }
  2861. shared static this()
  2862. {
  2863. static if( __traits( compiles, GetSystemInfo ) )
  2864. {
  2865. SYSTEM_INFO info;
  2866. GetSystemInfo( &info );
  2867. PAGESIZE = info.dwPageSize;
  2868. assert( PAGESIZE < int.max );
  2869. }
  2870. else static if( __traits( compiles, sysconf ) &&
  2871. __traits( compiles, _SC_PAGESIZE ) )
  2872. {
  2873. PAGESIZE = cast(size_t) sysconf( _SC_PAGESIZE );
  2874. assert( PAGESIZE < int.max );
  2875. }
  2876. else
  2877. {
  2878. version( PPC )
  2879. PAGESIZE = 8192;
  2880. else
  2881. PAGESIZE = 4096;
  2882. }
  2883. }
  2884. ///////////////////////////////////////////////////////////////////////////////
  2885. // Fiber Entry Point and Context Switch
  2886. ///////////////////////////////////////////////////////////////////////////////
  2887. private
  2888. {
  2889. extern (C) void fiber_entryPoint()
  2890. {
  2891. Fiber obj = Fiber.getThis();
  2892. assert( obj );
  2893. assert( Thread.getThis().m_curr is obj.m_ctxt );
  2894. atomicStore!(MemoryOrder.raw)(*cast(shared)&Thread.getThis().m_lock, false);
  2895. obj.m_ctxt.tstack = obj.m_ctxt.bstack;
  2896. obj.m_state = Fiber.State.EXEC;
  2897. try
  2898. {
  2899. obj.run();
  2900. }
  2901. catch( Throwable t )
  2902. {
  2903. obj.m_unhandled = t;
  2904. }
  2905. static if( __traits( compiles, ucontext_t ) )
  2906. obj.m_ucur = &obj.m_utxt;
  2907. obj.m_state = Fiber.State.TERM;
  2908. obj.switchOut();
  2909. }
  2910. version( AsmExternal )
  2911. extern (C) void fiber_switchContext( void** oldp, void* newp );
  2912. else
  2913. extern (C) void fiber_switchContext( void** oldp, void* newp )
  2914. {
  2915. // NOTE: The data pushed and popped in this routine must match the
  2916. // default stack created by Fiber.initStack or the initial
  2917. // switch into a new context will fail.
  2918. version( AsmX86_Windows )
  2919. {
  2920. asm
  2921. {
  2922. naked;
  2923. // save current stack state
  2924. push EBP;
  2925. mov EBP, ESP;
  2926. push EDI;
  2927. push ESI;
  2928. push EBX;
  2929. push dword ptr FS:[0];
  2930. push dword ptr FS:[4];
  2931. push dword ptr FS:[8];
  2932. push EAX;
  2933. // store oldp again with more accurate address
  2934. mov EAX, dword ptr 8[EBP];
  2935. mov [EAX], ESP;
  2936. // load newp to begin context switch
  2937. mov ESP, dword ptr 12[EBP];
  2938. // load saved state from new stack
  2939. pop EAX;
  2940. pop dword ptr FS:[8];
  2941. pop dword ptr FS:[4];
  2942. pop dword ptr FS:[0];
  2943. pop EBX;
  2944. pop ESI;
  2945. pop EDI;
  2946. pop EBP;
  2947. // 'return' to complete switch
  2948. ret;
  2949. }
  2950. }
  2951. else version( AsmX86_64_Windows )
  2952. {
  2953. asm
  2954. {
  2955. naked;
  2956. // save current stack state
  2957. push RBP;
  2958. mov RBP, RSP;
  2959. push RBX;
  2960. push R12;
  2961. push R13;
  2962. push R14;
  2963. push R15;
  2964. xor RCX,RCX;
  2965. push qword ptr GS:[RCX];
  2966. push qword ptr GS:8[RCX];
  2967. push qword ptr GS:16[RCX];
  2968. // store oldp
  2969. mov [RDI], RSP;
  2970. // load newp to begin context switch
  2971. mov RSP, RSI;
  2972. // load saved state from new stack
  2973. pop qword ptr GS:16[RCX];
  2974. pop qword ptr GS:8[RCX];
  2975. pop qword ptr GS:[RCX];
  2976. pop R15;
  2977. pop R14;
  2978. pop R13;
  2979. pop R12;
  2980. pop RBX;
  2981. pop RBP;
  2982. // 'return' to complete switch
  2983. pop RCX;
  2984. jmp RCX;
  2985. }
  2986. }
  2987. else version( AsmX86_Posix )
  2988. {
  2989. asm
  2990. {
  2991. naked;
  2992. // save current stack state
  2993. push EBP;
  2994. mov EBP, ESP;
  2995. push EDI;
  2996. push ESI;
  2997. push EBX;
  2998. push EAX;
  2999. // store oldp again with more accurate address
  3000. mov EAX, dword ptr 8[EBP];
  3001. mov [EAX], ESP;
  3002. // load newp to begin context switch
  3003. mov ESP, dword ptr 12[EBP];
  3004. // load saved state from new stack
  3005. pop EAX;
  3006. pop EBX;
  3007. pop ESI;
  3008. pop EDI;
  3009. pop EBP;
  3010. // 'return' to complete switch
  3011. pop ECX;
  3012. jmp ECX;
  3013. }
  3014. }
  3015. else version( AsmX86_64_Posix )
  3016. {
  3017. asm
  3018. {
  3019. naked;
  3020. // save current stack state
  3021. push RBP;
  3022. mov RBP, RSP;
  3023. push RBX;
  3024. push R12;
  3025. push R13;
  3026. push R14;
  3027. push R15;
  3028. // store oldp
  3029. mov [RDI], RSP;
  3030. // load newp to begin context switch
  3031. mov RSP, RSI;
  3032. // load saved state from new stack
  3033. pop R15;
  3034. pop R14;
  3035. pop R13;
  3036. pop R12;
  3037. pop RBX;
  3038. pop RBP;
  3039. // 'return' to complete switch
  3040. pop RCX;
  3041. jmp RCX;
  3042. }
  3043. }
  3044. else static if( __traits( compiles, ucontext_t ) )
  3045. {
  3046. Fiber cfib = Fiber.getThis();
  3047. void* ucur = cfib.m_ucur;
  3048. *oldp = &ucur;
  3049. swapcontext( **(cast(ucontext_t***) oldp),
  3050. *(cast(ucontext_t**) newp) );
  3051. }
  3052. else
  3053. static assert(0, "Not implemented");
  3054. }
  3055. }
  3056. ///////////////////////////////////////////////////////////////////////////////
  3057. // Fiber
  3058. ///////////////////////////////////////////////////////////////////////////////
  3059. /**
  3060. * This class provides a cooperative concurrency mechanism integrated with the
  3061. * threading and garbage collection functionality. Calling a fiber may be
  3062. * considered a blocking operation that returns when the fiber yields (via
  3063. * Fiber.yield()). Execution occurs within the context of the calling thread
  3064. * so synchronization is not necessary to guarantee memory visibility so long
  3065. * as the same thread calls the fiber each time. Please note that there is no
  3066. * requirement that a fiber be bound to one specific thread. Rather, fibers
  3067. * may be freely passed between threads so long as they are not currently
  3068. * executing. Like threads, a new fiber thread may be created using either
  3069. * derivation or composition, as in the following example.
  3070. *
  3071. * Example:
  3072. * ----------------------------------------------------------------------
  3073. *
  3074. * class DerivedFiber : Fiber
  3075. * {
  3076. * this()
  3077. * {
  3078. * super( &run );
  3079. * }
  3080. *
  3081. * private :
  3082. * void run()
  3083. * {
  3084. * printf( "Derived fiber running.\n" );
  3085. * }
  3086. * }
  3087. *
  3088. * void fiberFunc()
  3089. * {
  3090. * printf( "Composed fiber running.\n" );
  3091. * Fiber.yield();
  3092. * printf( "Composed fiber running.\n" );
  3093. * }
  3094. *
  3095. * // create instances of each type
  3096. * Fiber derived = new DerivedFiber();
  3097. * Fiber composed = new Fiber( &fiberFunc );
  3098. *
  3099. * // call both fibers once
  3100. * derived.call();
  3101. * composed.call();
  3102. * printf( "Execution returned to calling context.\n" );
  3103. * composed.call();
  3104. *
  3105. * // since each fiber has run to completion, each should have state TERM
  3106. * assert( derived.state == Fiber.State.TERM );
  3107. * assert( composed.state == Fiber.State.TERM );
  3108. *
  3109. * ----------------------------------------------------------------------
  3110. *
  3111. * Authors: Based on a design by Mikola Lysenko.
  3112. */
  3113. class Fiber
  3114. {
  3115. ///////////////////////////////////////////////////////////////////////////
  3116. // Initialization
  3117. ///////////////////////////////////////////////////////////////////////////
  3118. /**
  3119. * Initializes a fiber object which is associated with a static
  3120. * D function.
  3121. *
  3122. * Params:
  3123. * fn = The fiber function.
  3124. * sz = The stack size for this fiber.
  3125. *
  3126. * In:
  3127. * fn must not be null.
  3128. */
  3129. this( void function() fn, size_t sz = PAGESIZE*4 )
  3130. in
  3131. {
  3132. assert( fn );
  3133. }
  3134. body
  3135. {
  3136. allocStack( sz );
  3137. reset( fn );
  3138. }
  3139. /**
  3140. * Initializes a fiber object which is associated with a dynamic
  3141. * D function.
  3142. *
  3143. * Params:
  3144. * dg = The fiber function.
  3145. * sz = The stack size for this fiber.
  3146. *
  3147. * In:
  3148. * dg must not be null.
  3149. */
  3150. this( void delegate() dg, size_t sz = PAGESIZE*4 )
  3151. in
  3152. {
  3153. assert( dg );
  3154. }
  3155. body
  3156. {
  3157. allocStack( sz );
  3158. reset( dg );
  3159. }
  3160. /**
  3161. * Cleans up any remaining resources used by this object.
  3162. */
  3163. ~this()
  3164. {
  3165. // NOTE: A live reference to this object will exist on its associated
  3166. // stack from the first time its call() method has been called
  3167. // until its execution completes with State.TERM. Thus, the only
  3168. // times this dtor should be called are either if the fiber has
  3169. // terminated (and therefore has no active stack) or if the user
  3170. // explicitly deletes this object. The latter case is an error
  3171. // but is not easily tested for, since State.HOLD may imply that
  3172. // the fiber was just created but has never been run. There is
  3173. // not a compelling case to create a State.INIT just to offer a
  3174. // means of ensuring the user isn't violating this object's
  3175. // contract, so for now this requirement will be enforced by
  3176. // documentation only.
  3177. freeStack();
  3178. }
  3179. ///////////////////////////////////////////////////////////////////////////
  3180. // General Actions
  3181. ///////////////////////////////////////////////////////////////////////////
  3182. /**
  3183. * Transfers execution to this fiber object. The calling context will be
  3184. * suspended until the fiber calls Fiber.yield() or until it terminates
  3185. * via an unhandled exception.
  3186. *
  3187. * Params:
  3188. * rethrow = Rethrow any unhandled exception which may have caused this
  3189. * fiber to terminate.
  3190. *
  3191. * In:
  3192. * This fiber must be in state HOLD.
  3193. *
  3194. * Throws:
  3195. * Any exception not handled by the joined thread.
  3196. *
  3197. * Returns:
  3198. * Any exception not handled by this fiber if rethrow = false, null
  3199. * otherwise.
  3200. */
  3201. final Object call( bool rethrow = true )
  3202. in
  3203. {
  3204. assert( m_state == State.HOLD );
  3205. }
  3206. body
  3207. {
  3208. Fiber cur = getThis();
  3209. static if( __traits( compiles, ucontext_t ) )
  3210. m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt;
  3211. setThis( this );
  3212. this.switchIn();
  3213. setThis( cur );
  3214. static if( __traits( compiles, ucontext_t ) )
  3215. m_ucur = null;
  3216. // NOTE: If the fiber has terminated then the stack pointers must be
  3217. // reset. This ensures that the stack for this fiber is not
  3218. // scanned if the fiber has terminated. This is necessary to
  3219. // prevent any references lingering on the stack from delaying
  3220. // the collection of otherwise dead objects. The most notable
  3221. // being the current object, which is referenced at the top of
  3222. // fiber_entryPoint.
  3223. if( m_state == State.TERM )
  3224. {
  3225. m_ctxt.tstack = m_ctxt.bstack;
  3226. }
  3227. if( m_unhandled )
  3228. {
  3229. Throwable t = m_unhandled;
  3230. m_unhandled = null;
  3231. if( rethrow )
  3232. throw t;
  3233. return t;
  3234. }
  3235. return null;
  3236. }
  3237. /**
  3238. * Resets this fiber so that it may be re-used. This routine may only be
  3239. * called for fibers that have terminated, as doing otherwise could result
  3240. * in scope-dependent functionality that is not executed. Stack-based
  3241. * classes, for example, may not be cleaned up properly if a fiber is reset
  3242. * before it has terminated.
  3243. *
  3244. * Params:
  3245. * fn = The fiber function.
  3246. * dg = The fiber function.
  3247. *
  3248. * In:
  3249. * This fiber must be in state TERM.
  3250. */
  3251. final void reset()
  3252. in
  3253. {
  3254. assert( m_state == State.TERM || m_state == State.HOLD );
  3255. assert( m_ctxt.tstack == m_ctxt.bstack );
  3256. }
  3257. body
  3258. {
  3259. m_state = State.HOLD;
  3260. initStack();
  3261. m_unhandled = null;
  3262. }
  3263. /// ditto
  3264. final void reset( void function() fn )
  3265. {
  3266. reset();
  3267. m_fn = fn;
  3268. m_call = Call.FN;
  3269. }
  3270. /// ditto
  3271. final void reset( void delegate() dg )
  3272. {
  3273. reset();
  3274. m_dg = dg;
  3275. m_call = Call.DG;
  3276. }
  3277. ///////////////////////////////////////////////////////////////////////////
  3278. // General Properties
  3279. ///////////////////////////////////////////////////////////////////////////
  3280. /**
  3281. * A fiber may occupy one of three states: HOLD, EXEC, and TERM. The HOLD
  3282. * state applies to any fiber that is suspended and ready to be called.
  3283. * The EXEC state will be set for any fiber that is currently executing.
  3284. * And the TERM state is set when a fiber terminates. Once a fiber
  3285. * terminates, it must be reset before it may be called again.
  3286. */
  3287. enum State
  3288. {
  3289. HOLD, ///
  3290. EXEC, ///
  3291. TERM ///
  3292. }
  3293. /**
  3294. * Gets the current state of this fiber.
  3295. *
  3296. * Returns:
  3297. * The state of this fiber as an enumerated value.
  3298. */
  3299. final @property State state() const
  3300. {
  3301. return m_state;
  3302. }
  3303. ///////////////////////////////////////////////////////////////////////////
  3304. // Actions on Calling Fiber
  3305. ///////////////////////////////////////////////////////////////////////////
  3306. /**
  3307. * Forces a context switch to occur away from the calling fiber.
  3308. */
  3309. static void yield()
  3310. {
  3311. Fiber cur = getThis();
  3312. assert( cur, "Fiber.yield() called with no active fiber" );
  3313. assert( cur.m_state == State.EXEC );
  3314. static if( __traits( compiles, ucontext_t ) )
  3315. cur.m_ucur = &cur.m_utxt;
  3316. cur.m_state = State.HOLD;
  3317. cur.switchOut();
  3318. cur.m_state = State.EXEC;
  3319. }
  3320. /**
  3321. * Forces a context switch to occur away from the calling fiber and then
  3322. * throws obj in the calling fiber.
  3323. *
  3324. * Params:
  3325. * t = The object to throw.
  3326. *
  3327. * In:
  3328. * t must not be null.
  3329. */
  3330. static void yieldAndThrow( Throwable t )
  3331. in
  3332. {
  3333. assert( t );
  3334. }
  3335. body
  3336. {
  3337. Fiber cur = getThis();
  3338. assert( cur, "Fiber.yield() called with no active fiber" );
  3339. assert( cur.m_state == State.EXEC );
  3340. static if( __traits( compiles, ucontext_t ) )
  3341. cur.m_ucur = &cur.m_utxt;
  3342. cur.m_unhandled = t;
  3343. cur.m_state = State.HOLD;
  3344. cur.switchOut();
  3345. cur.m_state = State.EXEC;
  3346. }
  3347. ///////////////////////////////////////////////////////////////////////////
  3348. // Fiber Accessors
  3349. ///////////////////////////////////////////////////////////////////////////
  3350. /**
  3351. * Provides a reference to the calling fiber or null if no fiber is
  3352. * currently active.
  3353. *
  3354. * Returns:
  3355. * The fiber object representing the calling fiber or null if no fiber
  3356. * is currently active within this thread. The result of deleting this object is undefined.
  3357. */
  3358. static Fiber getThis()
  3359. {
  3360. return sm_this;
  3361. }
  3362. ///////////////////////////////////////////////////////////////////////////
  3363. // Static Initialization
  3364. ///////////////////////////////////////////////////////////////////////////
  3365. version( Posix )
  3366. {
  3367. static this()
  3368. {
  3369. static if( __traits( compiles, ucontext_t ) )
  3370. {
  3371. int status = getcontext( &sm_utxt );
  3372. assert( status == 0 );
  3373. }
  3374. }
  3375. }
  3376. private:
  3377. //
  3378. // Initializes a fiber object which has no associated executable function.
  3379. //
  3380. this()
  3381. {
  3382. m_call = Call.NO;
  3383. }
  3384. //
  3385. // Fiber entry point. Invokes the function or delegate passed on
  3386. // construction (if any).
  3387. //
  3388. final void run()
  3389. {
  3390. switch( m_call )
  3391. {
  3392. case Call.FN:
  3393. m_fn();
  3394. break;
  3395. case Call.DG:
  3396. m_dg();
  3397. break;
  3398. default:
  3399. break;
  3400. }
  3401. }
  3402. private:
  3403. //
  3404. // The type of routine passed on fiber construction.
  3405. //
  3406. enum Call
  3407. {
  3408. NO,
  3409. FN,
  3410. DG
  3411. }
  3412. //
  3413. // Standard fiber data
  3414. //
  3415. Call m_call;
  3416. union
  3417. {
  3418. void function() m_fn;
  3419. void delegate() m_dg;
  3420. }
  3421. bool m_isRunning;
  3422. Throwable m_unhandled;
  3423. State m_state;
  3424. private:
  3425. ///////////////////////////////////////////////////////////////////////////
  3426. // Stack Management
  3427. ///////////////////////////////////////////////////////////////////////////
  3428. //
  3429. // Allocate a new stack for this fiber.
  3430. //
  3431. final void allocStack( size_t sz )
  3432. in
  3433. {
  3434. assert( !m_pmem && !m_ctxt );
  3435. }
  3436. body
  3437. {
  3438. // adjust alloc size to a multiple of PAGESIZE
  3439. sz += PAGESIZE - 1;
  3440. sz -= sz % PAGESIZE;
  3441. // NOTE: This instance of Thread.Context is dynamic so Fiber objects
  3442. // can be collected by the GC so long as no user level references
  3443. // to the object exist. If m_ctxt were not dynamic then its
  3444. // presence in the global context list would be enough to keep
  3445. // this object alive indefinitely. An alternative to allocating
  3446. // room for this struct explicitly would be to mash it into the
  3447. // base of the stack being allocated below. However, doing so
  3448. // requires too much special logic to be worthwhile.
  3449. m_ctxt = new Thread.Context;
  3450. static if( __traits( compiles, VirtualAlloc ) )
  3451. {
  3452. // reserve memory for stack
  3453. m_pmem = VirtualAlloc( null,
  3454. sz + PAGESIZE,
  3455. MEM_RESERVE,
  3456. PAGE_NOACCESS );
  3457. if( !m_pmem )
  3458. {
  3459. throw new FiberException( "Unable to reserve memory for stack" );
  3460. }
  3461. version( StackGrowsDown )
  3462. {
  3463. void* stack = m_pmem + PAGESIZE;
  3464. void* guard = m_pmem;
  3465. void* pbase = stack + sz;
  3466. }
  3467. else
  3468. {
  3469. void* stack = m_pmem;
  3470. void* guard = m_pmem + sz;
  3471. void* pbase = stack;
  3472. }
  3473. // allocate reserved stack segment
  3474. stack = VirtualAlloc( stack,
  3475. sz,
  3476. MEM_COMMIT,
  3477. PAGE_READWRITE );
  3478. if( !stack )
  3479. {
  3480. throw new FiberException( "Unable to allocate memory for stack" );
  3481. }
  3482. // allocate reserved guard page
  3483. guard = VirtualAlloc( guard,
  3484. PAGESIZE,
  3485. MEM_COMMIT,
  3486. PAGE_READWRITE | PAGE_GUARD );
  3487. if( !guard )
  3488. {
  3489. throw new FiberException( "Unable to create guard page for stack" );
  3490. }
  3491. m_ctxt.bstack = pbase;
  3492. m_ctxt.tstack = pbase;
  3493. m_size = sz;
  3494. }
  3495. else
  3496. {
  3497. version (Posix) import core.sys.posix.sys.mman; // mmap
  3498. static if( __traits( compiles, mmap ) )
  3499. {
  3500. m_pmem = mmap( null,
  3501. sz,
  3502. PROT_READ | PROT_WRITE,
  3503. MAP_PRIVATE | MAP_ANON,
  3504. -1,
  3505. 0 );
  3506. if( m_pmem == MAP_FAILED )
  3507. m_pmem = null;
  3508. }
  3509. else static if( __traits( compiles, valloc ) )
  3510. {
  3511. m_pmem = valloc( sz );
  3512. }
  3513. else static if( __traits( compiles, malloc ) )
  3514. {
  3515. m_pmem = malloc( sz );
  3516. }
  3517. else
  3518. {
  3519. m_pmem = null;
  3520. }
  3521. if( !m_pmem )
  3522. {
  3523. throw new FiberException( "Unable to allocate memory for stack" );
  3524. }
  3525. version( StackGrowsDown )
  3526. {
  3527. m_ctxt.bstack = m_pmem + sz;
  3528. m_ctxt.tstack = m_pmem + sz;
  3529. }
  3530. else
  3531. {
  3532. m_ctxt.bstack = m_pmem;
  3533. m_ctxt.tstack = m_pmem;
  3534. }
  3535. m_size = sz;
  3536. }
  3537. Thread.add( m_ctxt );
  3538. }
  3539. //
  3540. // Free this fiber's stack.
  3541. //
  3542. final void freeStack()
  3543. in
  3544. {
  3545. assert( m_pmem && m_ctxt );
  3546. }
  3547. body
  3548. {
  3549. // NOTE: m_ctxt is guaranteed to be alive because it is held in the
  3550. // global context list.
  3551. Thread.remove( m_ctxt );
  3552. static if( __traits( compiles, VirtualAlloc ) )
  3553. {
  3554. VirtualFree( m_pmem, 0, MEM_RELEASE );
  3555. }
  3556. else
  3557. {
  3558. import core.sys.posix.sys.mman; // munmap
  3559. static if( __traits( compiles, mmap ) )
  3560. {
  3561. munmap( m_pmem, m_size );
  3562. }
  3563. else static if( __traits( compiles, valloc ) )
  3564. {
  3565. free( m_pmem );
  3566. }
  3567. else static if( __traits( compiles, malloc ) )
  3568. {
  3569. free( m_pmem );
  3570. }
  3571. }
  3572. m_pmem = null;
  3573. m_ctxt = null;
  3574. }
  3575. //
  3576. // Initialize the allocated stack.
  3577. //
  3578. final void initStack()
  3579. in
  3580. {
  3581. assert( m_ctxt.tstack && m_ctxt.tstack == m_ctxt.bstack );
  3582. assert( cast(size_t) m_ctxt.bstack % (void*).sizeof == 0 );
  3583. }
  3584. body
  3585. {
  3586. void* pstack = m_ctxt.tstack;
  3587. scope( exit ) m_ctxt.tstack = pstack;
  3588. void push( size_t val )
  3589. {
  3590. version( StackGrowsDown )
  3591. {
  3592. pstack -= size_t.sizeof;
  3593. *(cast(size_t*) pstack) = val;
  3594. }
  3595. else
  3596. {
  3597. pstack += size_t.sizeof;
  3598. *(cast(size_t*) pstack) = val;
  3599. }
  3600. }
  3601. // NOTE: On OS X the stack must be 16-byte aligned according
  3602. // to the IA-32 call spec. For x86_64 the stack also needs to
  3603. // be aligned to 16-byte according to SysV AMD64 ABI.
  3604. version( AlignFiberStackTo16Byte )
  3605. {
  3606. version( StackGrowsDown )
  3607. {
  3608. pstack = cast(void*)(cast(size_t)(pstack) - (cast(size_t)(pstack) & 0x0F));
  3609. }
  3610. else
  3611. {
  3612. pstack = cast(void*)(cast(size_t)(pstack) + (cast(size_t)(pstack) & 0x0F));
  3613. }
  3614. }
  3615. version( AsmX86_Windows )
  3616. {
  3617. version( StackGrowsDown ) {} else static assert( false );
  3618. // On Windows Server 2008 and 2008 R2, an exploit mitigation
  3619. // technique known as SEHOP is activated by default. To avoid
  3620. // hijacking of the exception handler chain, the presence of a
  3621. // Windows-internal handler (ntdll.dll!FinalExceptionHandler) at
  3622. // its end is tested by RaiseException. If it is not present, all
  3623. // handlers are disregarded, and the program is thus aborted
  3624. // (see http://blogs.technet.com/b/srd/archive/2009/02/02/
  3625. // preventing-the-exploitation-of-seh-overwrites-with-sehop.aspx).
  3626. // For new threads, this handler is installed by Windows immediately
  3627. // after creation. To make exception handling work in fibers, we
  3628. // have to insert it for our new stacks manually as well.
  3629. //
  3630. // To do this, we first determine the handler by traversing the SEH
  3631. // chain of the current thread until its end, and then construct a
  3632. // registration block for the last handler on the newly created
  3633. // thread. We then continue to push all the initial register values
  3634. // for the first context switch as for the other implementations.
  3635. //
  3636. // Note that this handler is never actually invoked, as we install
  3637. // our own one on top of it in the fiber entry point function.
  3638. // Thus, it should not have any effects on OSes not implementing
  3639. // exception chain verification.
  3640. alias void function() fp_t; // Actual signature not relevant.
  3641. static struct EXCEPTION_REGISTRATION
  3642. {
  3643. EXCEPTION_REGISTRATION* next; // sehChainEnd if last one.
  3644. fp_t handler;
  3645. }
  3646. enum sehChainEnd = cast(EXCEPTION_REGISTRATION*) 0xFFFFFFFF;
  3647. __gshared static fp_t finalHandler = null;
  3648. if ( finalHandler is null )
  3649. {
  3650. static EXCEPTION_REGISTRATION* fs0()
  3651. {
  3652. asm
  3653. {
  3654. naked;
  3655. mov EAX, FS:[0];
  3656. ret;
  3657. }
  3658. }
  3659. auto reg = fs0();
  3660. while ( reg.next != sehChainEnd ) reg = reg.next;
  3661. // Benign races are okay here, just to avoid re-lookup on every
  3662. // fiber creation.
  3663. finalHandler = reg.handler;
  3664. }
  3665. pstack -= EXCEPTION_REGISTRATION.sizeof;
  3666. *(cast(EXCEPTION_REGISTRATION*)pstack) =
  3667. EXCEPTION_REGISTRATION( sehChainEnd, finalHandler );
  3668. push( cast(size_t) &fiber_entryPoint ); // EIP
  3669. push( cast(size_t) m_ctxt.bstack - EXCEPTION_REGISTRATION.sizeof ); // EBP
  3670. push( 0x00000000 ); // EDI
  3671. push( 0x00000000 ); // ESI
  3672. push( 0x00000000 ); // EBX
  3673. push( cast(size_t) m_ctxt.bstack - EXCEPTION_REGISTRATION.sizeof ); // FS:[0]
  3674. push( cast(size_t) m_ctxt.bstack ); // FS:[4]
  3675. push( cast(size_t) m_ctxt.bstack - m_size ); // FS:[8]
  3676. push( 0x00000000 ); // EAX
  3677. }
  3678. else version( AsmX86_64_Windows )
  3679. {
  3680. push( 0x00000000_00000000 ); // Return address of fiber_entryPoint call
  3681. push( cast(size_t) &fiber_entryPoint ); // RIP
  3682. push( 0x00000000_00000000 ); // RBP
  3683. push( 0x00000000_00000000 ); // RBX
  3684. push( 0x00000000_00000000 ); // R12
  3685. push( 0x00000000_00000000 ); // R13
  3686. push( 0x00000000_00000000 ); // R14
  3687. push( 0x00000000_00000000 ); // R15
  3688. push( 0xFFFFFFFF_FFFFFFFF ); // GS:[0]
  3689. version( StackGrowsDown )
  3690. {
  3691. push( cast(size_t) m_ctxt.bstack ); // GS:[8]
  3692. push( cast(size_t) m_ctxt.bstack - m_size ); // GS:[16]
  3693. }
  3694. else
  3695. {
  3696. push( cast(size_t) m_ctxt.bstack ); // GS:[8]
  3697. push( cast(size_t) m_ctxt.bstack + m_size ); // GS:[16]
  3698. }
  3699. }
  3700. else version( AsmX86_Posix )
  3701. {
  3702. push( 0x00000000 ); // Return address of fiber_entryPoint call
  3703. push( cast(size_t) &fiber_entryPoint ); // EIP
  3704. push( cast(size_t) m_ctxt.bstack ); // EBP
  3705. push( 0x00000000 ); // EDI
  3706. push( 0x00000000 ); // ESI
  3707. push( 0x00000000 ); // EBX
  3708. push( 0x00000000 ); // EAX
  3709. }
  3710. else version( AsmX86_64_Posix )
  3711. {
  3712. push( 0x00000000_00000000 ); // Return address of fiber_entryPoint call
  3713. push( cast(size_t) &fiber_entryPoint ); // RIP
  3714. push( cast(size_t) m_ctxt.bstack ); // RBP
  3715. push( 0x00000000_00000000 ); // RBX
  3716. push( 0x00000000_00000000 ); // R12
  3717. push( 0x00000000_00000000 ); // R13
  3718. push( 0x00000000_00000000 ); // R14
  3719. push( 0x00000000_00000000 ); // R15
  3720. }
  3721. else version( AsmPPC_Posix )
  3722. {
  3723. version( StackGrowsDown )
  3724. {
  3725. pstack -= int.sizeof * 5;
  3726. }
  3727. else
  3728. {
  3729. pstack += int.sizeof * 5;
  3730. }
  3731. push( cast(size_t) &fiber_entryPoint ); // link register
  3732. push( 0x00000000 ); // control register
  3733. push( 0x00000000 ); // old stack pointer
  3734. // GPR values
  3735. version( StackGrowsDown )
  3736. {
  3737. pstack -= int.sizeof * 20;
  3738. }
  3739. else
  3740. {
  3741. pstack += int.sizeof * 20;
  3742. }
  3743. assert( (cast(size_t) pstack & 0x0f) == 0 );
  3744. }
  3745. else version( AsmMIPS_O32_Posix )
  3746. {
  3747. version (StackGrowsDown) {}
  3748. else static assert(0);
  3749. /* We keep the FP registers and the return address below
  3750. * the stack pointer, so they don't get scanned by the
  3751. * GC. The last frame before swapping the stack pointer is
  3752. * organized like the following.
  3753. *
  3754. * |-----------|<= frame pointer
  3755. * | $gp |
  3756. * | $s0-8 |
  3757. * |-----------|<= stack pointer
  3758. * | $ra |
  3759. * | align(8) |
  3760. * | $f20-30 |
  3761. * |-----------|
  3762. *
  3763. */
  3764. enum SZ_GP = 10 * size_t.sizeof; // $gp + $s0-8
  3765. enum SZ_RA = size_t.sizeof; // $ra
  3766. version (MIPS_HardFloat)
  3767. {
  3768. enum SZ_FP = 6 * 8; // $f20-30
  3769. enum ALIGN = -(SZ_FP + SZ_RA) & (8 - 1);
  3770. }
  3771. else
  3772. {
  3773. enum SZ_FP = 0;
  3774. enum ALIGN = 0;
  3775. }
  3776. enum BELOW = SZ_FP + ALIGN + SZ_RA;
  3777. enum ABOVE = SZ_GP;
  3778. enum SZ = BELOW + ABOVE;
  3779. (cast(ubyte*)pstack - SZ)[0 .. SZ] = 0;
  3780. pstack -= ABOVE;
  3781. *cast(size_t*)(pstack - SZ_RA) = cast(size_t)&fiber_entryPoint;
  3782. }
  3783. else static if( __traits( compiles, ucontext_t ) )
  3784. {
  3785. getcontext( &m_utxt );
  3786. m_utxt.uc_stack.ss_sp = m_pmem;
  3787. m_utxt.uc_stack.ss_size = m_size;
  3788. makecontext( &m_utxt, &fiber_entryPoint, 0 );
  3789. // NOTE: If ucontext is being used then the top of the stack will
  3790. // be a pointer to the ucontext_t struct for that fiber.
  3791. push( cast(size_t) &m_utxt );
  3792. }
  3793. else
  3794. static assert(0, "Not implemented");
  3795. }
  3796. Thread.Context* m_ctxt;
  3797. size_t m_size;
  3798. void* m_pmem;
  3799. static if( __traits( compiles, ucontext_t ) )
  3800. {
  3801. // NOTE: The static ucontext instance is used to represent the context
  3802. // of the executing thread.
  3803. static ucontext_t sm_utxt = void;
  3804. ucontext_t m_utxt = void;
  3805. ucontext_t* m_ucur = null;
  3806. }
  3807. private:
  3808. ///////////////////////////////////////////////////////////////////////////
  3809. // Storage of Active Fiber
  3810. ///////////////////////////////////////////////////////////////////////////
  3811. //
  3812. // Sets a thread-local reference to the current fiber object.
  3813. //
  3814. static void setThis( Fiber f )
  3815. {
  3816. sm_this = f;
  3817. }
  3818. static Fiber sm_this;
  3819. private:
  3820. ///////////////////////////////////////////////////////////////////////////
  3821. // Context Switching
  3822. ///////////////////////////////////////////////////////////////////////////
  3823. //
  3824. // Switches into the stack held by this fiber.
  3825. //
  3826. final void switchIn()
  3827. {
  3828. Thread tobj = Thread.getThis();
  3829. void** oldp = &tobj.m_curr.tstack;
  3830. void* newp = m_ctxt.tstack;
  3831. // NOTE: The order of operations here is very important. The current
  3832. // stack top must be stored before m_lock is set, and pushContext
  3833. // must not be called until after m_lock is set. This process
  3834. // is intended to prevent a race condition with the suspend
  3835. // mechanism used for garbage collection. If it is not followed,
  3836. // a badly timed collection could cause the GC to scan from the
  3837. // bottom of one stack to the top of another, or to miss scanning
  3838. // a stack that still contains valid data. The old stack pointer
  3839. // oldp will be set again before the context switch to guarantee
  3840. // that it points to exactly the correct stack location so the
  3841. // successive pop operations will succeed.
  3842. *oldp = getStackTop();
  3843. atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, true);
  3844. tobj.pushContext( m_ctxt );
  3845. fiber_switchContext( oldp, newp );
  3846. // NOTE: As above, these operations must be performed in a strict order
  3847. // to prevent Bad Things from happening.
  3848. tobj.popContext();
  3849. atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, false);
  3850. tobj.m_curr.tstack = tobj.m_curr.bstack;
  3851. }
  3852. //
  3853. // Switches out of the current stack and into the enclosing stack.
  3854. //
  3855. final void switchOut()
  3856. {
  3857. Thread tobj = Thread.getThis();
  3858. void** oldp = &m_ctxt.tstack;
  3859. void* newp = tobj.m_curr.within.tstack;
  3860. // NOTE: The order of operations here is very important. The current
  3861. // stack top must be stored before m_lock is set, and pushContext
  3862. // must not be called until after m_lock is set. This process
  3863. // is intended to prevent a race condition with the suspend
  3864. // mechanism used for garbage collection. If it is not followed,
  3865. // a badly timed collection could cause the GC to scan from the
  3866. // bottom of one stack to the top of another, or to miss scanning
  3867. // a stack that still contains valid data. The old stack pointer
  3868. // oldp will be set again before the context switch to guarantee
  3869. // that it points to exactly the correct stack location so the
  3870. // successive pop operations will succeed.
  3871. *oldp = getStackTop();
  3872. atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, true);
  3873. fiber_switchContext( oldp, newp );
  3874. // NOTE: As above, these operations must be performed in a strict order
  3875. // to prevent Bad Things from happening.
  3876. // NOTE: If use of this fiber is multiplexed across threads, the thread
  3877. // executing here may be different from the one above, so get the
  3878. // current thread handle before unlocking, etc.
  3879. tobj = Thread.getThis();
  3880. atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, false);
  3881. tobj.m_curr.tstack = tobj.m_curr.bstack;
  3882. }
  3883. }
  3884. // These must be kept in sync with core/thread.di
  3885. version (D_LP64)
  3886. {
  3887. version (Windows)
  3888. static assert(__traits(classInstanceSize, Fiber) == 88);
  3889. else version (OSX)
  3890. static assert(__traits(classInstanceSize, Fiber) == 88);
  3891. else version (Posix)
  3892. static assert(__traits(classInstanceSize, Fiber) == 88);
  3893. else
  3894. static assert(0, "Platform not supported.");
  3895. }
  3896. else
  3897. {
  3898. static assert((void*).sizeof == 4); // 32-bit
  3899. version (Windows)
  3900. static assert(__traits(classInstanceSize, Fiber) == 44);
  3901. else version (OSX)
  3902. static assert(__traits(classInstanceSize, Fiber) == 44);
  3903. else version (Posix)
  3904. static assert(__traits(classInstanceSize, Fiber) == 44);
  3905. else
  3906. static assert(0, "Platform not supported.");
  3907. }
  3908. version(Win64) {}
  3909. else {
  3910. version( unittest )
  3911. {
  3912. class TestFiber : Fiber
  3913. {
  3914. this()
  3915. {
  3916. super(&run);
  3917. }
  3918. void run()
  3919. {
  3920. foreach(i; 0 .. 1000)
  3921. {
  3922. sum += i;
  3923. Fiber.yield();
  3924. }
  3925. }
  3926. enum expSum = 1000 * 999 / 2;
  3927. size_t sum;
  3928. }
  3929. void runTen()
  3930. {
  3931. TestFiber[10] fibs;
  3932. foreach(ref fib; fibs)
  3933. fib = new TestFiber();
  3934. bool cont;
  3935. do {
  3936. cont = false;
  3937. foreach(fib; fibs) {
  3938. if (fib.state == Fiber.State.HOLD)
  3939. {
  3940. fib.call();
  3941. cont |= fib.state != Fiber.State.TERM;
  3942. }
  3943. }
  3944. } while (cont);
  3945. foreach(fib; fibs)
  3946. {
  3947. assert(fib.sum == TestFiber.expSum);
  3948. }
  3949. }
  3950. }
  3951. // Single thread running separate fibers
  3952. unittest
  3953. {
  3954. runTen();
  3955. }
  3956. // Multiple threads running separate fibers
  3957. unittest
  3958. {
  3959. auto group = new ThreadGroup();
  3960. foreach(_; 0 .. 4)
  3961. {
  3962. group.create(&runTen);
  3963. }
  3964. group.joinAll();
  3965. }
  3966. // Multiple threads running shared fibers
  3967. unittest
  3968. {
  3969. shared bool[10] locks;
  3970. TestFiber[10] fibs;
  3971. void runShared()
  3972. {
  3973. bool cont;
  3974. do {
  3975. cont = false;
  3976. foreach(idx; 0 .. 10)
  3977. {
  3978. if (cas(&locks[idx], false, true))
  3979. {
  3980. if (fibs[idx].state == Fiber.State.HOLD)
  3981. {
  3982. fibs[idx].call();
  3983. cont |= fibs[idx].state != Fiber.State.TERM;
  3984. }
  3985. locks[idx] = false;
  3986. }
  3987. else
  3988. {
  3989. cont = true;
  3990. }
  3991. }
  3992. } while (cont);
  3993. }
  3994. foreach(ref fib; fibs)
  3995. {
  3996. fib = new TestFiber();
  3997. }
  3998. auto group = new ThreadGroup();
  3999. foreach(_; 0 .. 4)
  4000. {
  4001. group.create(&runShared);
  4002. }
  4003. group.joinAll();
  4004. foreach(fib; fibs)
  4005. {
  4006. assert(fib.sum == TestFiber.expSum);
  4007. }
  4008. }
  4009. // Test exception handling inside fibers.
  4010. unittest
  4011. {
  4012. enum MSG = "Test message.";
  4013. string caughtMsg;
  4014. (new Fiber({
  4015. try
  4016. {
  4017. throw new Exception(MSG);
  4018. }
  4019. catch (Exception e)
  4020. {
  4021. caughtMsg = e.msg;
  4022. }
  4023. })).call();
  4024. assert(caughtMsg == MSG);
  4025. }
  4026. unittest
  4027. {
  4028. int x = 0;
  4029. (new Fiber({
  4030. x++;
  4031. })).call();
  4032. assert( x == 1 );
  4033. }
  4034. unittest
  4035. {
  4036. enum MSG = "Test message.";
  4037. try
  4038. {
  4039. (new Fiber({
  4040. throw new Exception( MSG );
  4041. })).call();
  4042. assert( false, "Expected rethrown exception." );
  4043. }
  4044. catch( Throwable t )
  4045. {
  4046. assert( t.msg == MSG );
  4047. }
  4048. }
  4049. // Test Fiber resetting
  4050. unittest
  4051. {
  4052. static string method;
  4053. static void foo()
  4054. {
  4055. method = "foo";
  4056. }
  4057. void bar()
  4058. {
  4059. method = "bar";
  4060. }
  4061. static void expect(Fiber fib, string s)
  4062. {
  4063. assert(fib.state == Fiber.State.HOLD);
  4064. fib.call();
  4065. assert(fib.state == Fiber.State.TERM);
  4066. assert(method == s); method = null;
  4067. }
  4068. auto fib = new Fiber(&foo);
  4069. expect(fib, "foo");
  4070. fib.reset();
  4071. expect(fib, "foo");
  4072. fib.reset(&foo);
  4073. expect(fib, "foo");
  4074. fib.reset(&bar);
  4075. expect(fib, "bar");
  4076. fib.reset(function void(){method = "function";});
  4077. expect(fib, "function");
  4078. fib.reset(delegate void(){method = "delegate";});
  4079. expect(fib, "delegate");
  4080. }
  4081. }
  4082. version( AsmX86_64_Posix )
  4083. {
  4084. unittest
  4085. {
  4086. void testStackAlignment()
  4087. {
  4088. void* pRSP;
  4089. asm
  4090. {
  4091. mov pRSP, RSP;
  4092. }
  4093. assert((cast(size_t)pRSP & 0xF) == 0);
  4094. }
  4095. auto fib = new Fiber(&testStackAlignment);
  4096. fib.call();
  4097. }
  4098. }
  4099. version (LDC) {} else
  4100. version( OSX )
  4101. {
  4102. // NOTE: The Mach-O object file format does not allow for thread local
  4103. // storage declarations. So instead we roll our own by putting tls
  4104. // into the sections bracketed by _tls_beg and _tls_end.
  4105. //
  4106. // This function is called by the code emitted by the compiler. It
  4107. // is expected to translate an address into the TLS static data to
  4108. // the corresponding address in the TLS dynamic per-thread data.
  4109. extern (D) void* ___tls_get_addr( void* p )
  4110. {
  4111. // NOTE: p is an address in the TLS static data emitted by the
  4112. // compiler. If it isn't, something is disastrously wrong.
  4113. auto obj = Thread.getThis();
  4114. immutable off0 = cast(size_t)(p - _tls_data_array[0].ptr);
  4115. if (off0 < _tls_data_array[0].length)
  4116. {
  4117. return obj.m_tls.ptr + off0;
  4118. }
  4119. immutable off1 = cast(size_t)(p - _tls_data_array[1].ptr);
  4120. if (off1 < _tls_data_array[1].length)
  4121. {
  4122. size_t sz = (_tls_data_array[0].length + 15) & ~cast(size_t)15;
  4123. return obj.m_tls.ptr + sz + off1;
  4124. }
  4125. else
  4126. assert(0);
  4127. //assert( p >= cast(void*) &_tls_beg && p < cast(void*) &_tls_end );
  4128. //return obj.m_tls.ptr + (p - cast(void*) &_tls_beg);
  4129. }
  4130. }