/src/core/thread.d
D | 4697 lines | 2890 code | 567 blank | 1240 comment | 347 complexity | 672b56f280060a7ede3f5dea172df202 MD5 | raw file
Large files files are truncated, but you can click here to view the full 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 12module core.thread; 13 14 15public import core.time; // for Duration 16static import rt.tlsgc; 17 18// this should be true for most architectures 19version = StackGrowsDown; 20 21/** 22 * Returns the process ID of the calling process, which is guaranteed to be 23 * unique on the system. This call is always successful. 24 * 25 * Example: 26 * --- 27 * writefln("Current process id: %s", getpid()); 28 * --- 29 */ 30version(Posix) 31{ 32 alias core.sys.posix.unistd.getpid getpid; 33} 34else version (Windows) 35{ 36 alias core.sys.windows.windows.GetCurrentProcessId getpid; 37} 38 39 40/////////////////////////////////////////////////////////////////////////////// 41// Thread and Fiber Exceptions 42/////////////////////////////////////////////////////////////////////////////// 43 44 45/** 46 * Base class for thread exceptions. 47 */ 48class ThreadException : Exception 49{ 50 this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) 51 { 52 super(msg, file, line, next); 53 } 54 55 this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) 56 { 57 super(msg, file, line, next); 58 } 59} 60 61 62/** 63 * Base class for fiber exceptions. 64 */ 65class FiberException : Exception 66{ 67 this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) 68 { 69 super(msg, file, line, next); 70 } 71 72 this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) 73 { 74 super(msg, file, line, next); 75 } 76} 77 78 79private 80{ 81 import core.sync.mutex; 82 import core.atomic; 83 84 // 85 // from core.memory 86 // 87 extern (C) void gc_enable(); 88 extern (C) void gc_disable(); 89 extern (C) void* gc_malloc(size_t sz, uint ba = 0); 90 91 // 92 // from core.stdc.string 93 // 94 extern (C) void* memcpy(void*, const void*, size_t); 95 96 // 97 // exposed by compiler runtime 98 // 99 extern (C) void rt_moduleTlsCtor(); 100 extern (C) void rt_moduleTlsDtor(); 101 102 alias void delegate() gc_atom; 103 extern (C) void function(scope gc_atom) gc_atomic; 104} 105 106 107/////////////////////////////////////////////////////////////////////////////// 108// Thread Entry Point and Signal Handlers 109/////////////////////////////////////////////////////////////////////////////// 110 111 112version( Windows ) 113{ 114 private 115 { 116 import core.stdc.stdint : uintptr_t; // for _beginthreadex decl below 117 import core.stdc.stdlib; // for malloc, atexit 118 import core.sys.windows.windows; 119 import core.sys.windows.threadaux; // for OpenThreadHandle 120 121 const DWORD TLS_OUT_OF_INDEXES = 0xFFFFFFFF; 122 const CREATE_SUSPENDED = 0x00000004; 123 124 extern (Windows) alias uint function(void*) btex_fptr; 125 extern (C) uintptr_t _beginthreadex(void*, uint, btex_fptr, void*, uint, uint*); 126 127 version( DigitalMars ) 128 { 129 version (Win32) 130 { 131 // NOTE: The memory between the addresses of _tlsstart and _tlsend 132 // is the storage for thread-local data in D 2.0. Both of 133 // these are defined in dm\src\win32\tlsseg.asm by DMC. 134 extern (C) 135 { 136 extern int _tlsstart; 137 extern int _tlsend; 138 } 139 } 140 version (Win64) 141 { 142 // NOTE: The memory between the addresses of _tls_start and _tls_end 143 // is the storage for thread-local data in D 2.0. Both of 144 // these are defined in LIBCMT:tlssub.obj 145 extern (C) 146 { 147 extern int _tls_start; 148 extern int _tls_end; 149 } 150 alias _tls_start _tlsstart; 151 alias _tls_end _tlsend; 152 } 153 } 154 else version (MinGW) 155 { 156 extern (C) 157 { 158 extern int _tls_start; 159 extern int _tls_end; 160 } 161 alias _tls_start _tlsstart; 162 alias _tls_end _tlsend; 163 } 164 else 165 { 166 __gshared int _tlsstart; 167 alias _tlsstart _tlsend; 168 } 169 170 171 // 172 // Entry point for Windows threads 173 // 174 extern (Windows) uint thread_entryPoint( void* arg ) 175 { 176 Thread obj = cast(Thread) arg; 177 assert( obj ); 178 179 assert( obj.m_curr is &obj.m_main ); 180 obj.m_main.bstack = getStackBottom(); 181 obj.m_main.tstack = obj.m_main.bstack; 182 183 void* pstart = cast(void*) &_tlsstart; 184 void* pend = cast(void*) &_tlsend; 185 obj.m_tls = pstart[0 .. pend - pstart]; 186 187 Thread.setThis( obj ); 188 //Thread.add( obj ); 189 scope( exit ) 190 { 191 Thread.remove( obj ); 192 } 193 Thread.add( &obj.m_main ); 194 obj.m_tlsgcdata = rt.tlsgc.init(); 195 196 // NOTE: No GC allocations may occur until the stack pointers have 197 // been set and Thread.getThis returns a valid reference to 198 // this thread object (this latter condition is not strictly 199 // necessary on Windows but it should be followed for the 200 // sake of consistency). 201 202 // TODO: Consider putting an auto exception object here (using 203 // alloca) forOutOfMemoryError plus something to track 204 // whether an exception is in-flight? 205 206 void append( Throwable t ) 207 { 208 if( obj.m_unhandled is null ) 209 obj.m_unhandled = t; 210 else 211 { 212 Throwable last = obj.m_unhandled; 213 while( last.next !is null ) 214 last = last.next; 215 last.next = t; 216 } 217 } 218 219 version( D_InlineAsm_X86 ) 220 { 221 asm { fninit; } 222 } 223 224 try 225 { 226 rt_moduleTlsCtor(); 227 try 228 { 229 obj.run(); 230 } 231 catch( Throwable t ) 232 { 233 append( t ); 234 } 235 rt_moduleTlsDtor(); 236 } 237 catch( Throwable t ) 238 { 239 append( t ); 240 } 241 return 0; 242 } 243 244 245 HANDLE GetCurrentThreadHandle() 246 { 247 const uint DUPLICATE_SAME_ACCESS = 0x00000002; 248 249 HANDLE curr = GetCurrentThread(), 250 proc = GetCurrentProcess(), 251 hndl; 252 253 DuplicateHandle( proc, curr, proc, &hndl, 0, TRUE, DUPLICATE_SAME_ACCESS ); 254 return hndl; 255 } 256 } 257} 258else version( Posix ) 259{ 260 private 261 { 262 import core.stdc.errno; 263 import core.sys.posix.semaphore; 264 import core.sys.posix.stdlib; // for malloc, valloc, free, atexit 265 import core.sys.posix.pthread; 266 import core.sys.posix.signal; 267 import core.sys.posix.time; 268 269 version( OSX ) 270 { 271 import core.sys.osx.mach.thread_act; 272 extern (C) mach_port_t pthread_mach_thread_np(pthread_t); 273 } 274 275 version( GNU ) 276 { 277 import gcc.builtins; 278 } 279 280 version( DigitalMars ) 281 { 282 version( linux ) 283 { 284 extern (C) 285 { 286 extern int _tlsstart; 287 extern int _tlsend; 288 } 289 } 290 else version( OSX ) 291 { 292 extern (C) 293 { 294 __gshared void[][2] _tls_data_array; 295 } 296 } 297 else version( FreeBSD ) 298 { 299 extern (C) 300 { 301 extern void* _tlsstart; 302 extern void* _tlsend; 303 } 304 } 305 else 306 { 307 __gshared int _tlsstart; 308 alias _tlsstart _tlsend; 309 } 310 } 311 else version (LDC) 312 { 313 version = LDC_NoTlsBracketSyms; 314 } 315 else 316 { 317 __gshared int _tlsstart; 318 alias _tlsstart _tlsend; 319 } 320 321 322 // 323 // Entry point for POSIX threads 324 // 325 extern (C) void* thread_entryPoint( void* arg ) 326 { 327 Thread obj = cast(Thread) arg; 328 assert( obj ); 329 330 assert( obj.m_curr is &obj.m_main ); 331 obj.m_main.bstack = getStackBottom(); 332 obj.m_main.tstack = obj.m_main.bstack; 333 334 version (LDC_NoTlsBracketSyms) 335 { 336 version (OSX) 337 { 338 import ldc.memory; 339 obj.m_tls = getCurrentTLSRange(); 340 } 341 else 342 { 343 // Nothing to do here for Linux – glibc allocates the TLS 344 // data at the start of the stack area, so we scan it anyway. 345 } 346 } 347 else version(OSX) 348 { 349 // NOTE: OSX does not support TLS, so we do it ourselves. The TLS 350 // data output by the compiler is bracketed by _tls_data_array[2], 351 // so make a copy of it for each thread. 352 const sz0 = (_tls_data_array[0].length + 15) & ~cast(size_t)15; 353 const sz2 = sz0 + _tls_data_array[1].length; 354 auto p = malloc( sz2 ); 355 assert( p ); 356 obj.m_tls = p[0 .. sz2]; 357 memcpy( p, _tls_data_array[0].ptr, _tls_data_array[0].length ); 358 memcpy( p + sz0, _tls_data_array[1].ptr, _tls_data_array[1].length ); 359 scope (exit) { free( p ); obj.m_tls = null; } 360 } 361 else 362 { 363 auto pstart = cast(void*) &_tlsstart; 364 auto pend = cast(void*) &_tlsend; 365 obj.m_tls = pstart[0 .. pend - pstart]; 366 } 367 368 obj.m_isRunning = true; 369 Thread.setThis( obj ); 370 //Thread.add( obj ); 371 scope( exit ) 372 { 373 // NOTE: isRunning should be set to false after the thread is 374 // removed or a double-removal could occur between this 375 // function and thread_suspendAll. 376 Thread.remove( obj ); 377 obj.m_isRunning = false; 378 } 379 Thread.add( &obj.m_main ); 380 obj.m_tlsgcdata = rt.tlsgc.init(); 381 382 static extern (C) void thread_cleanupHandler( void* arg ) nothrow 383 { 384 Thread obj = cast(Thread) arg; 385 assert( obj ); 386 387 // NOTE: If the thread terminated abnormally, just set it as 388 // not running and let thread_suspendAll remove it from 389 // the thread list. This is safer and is consistent 390 // with the Windows thread code. 391 obj.m_isRunning = false; 392 } 393 394 // NOTE: Using void to skip the initialization here relies on 395 // knowledge of how pthread_cleanup is implemented. It may 396 // not be appropriate for all platforms. However, it does 397 // avoid the need to link the pthread module. If any 398 // implementation actually requires default initialization 399 // then pthread_cleanup should be restructured to maintain 400 // the current lack of a link dependency. 401 static if( __traits( compiles, pthread_cleanup ) ) 402 { 403 pthread_cleanup cleanup = void; 404 cleanup.push( &thread_cleanupHandler, cast(void*) obj ); 405 } 406 else static if( __traits( compiles, pthread_cleanup_push ) ) 407 { 408 pthread_cleanup_push( &thread_cleanupHandler, cast(void*) obj ); 409 } 410 else 411 { 412 static assert( false, "Platform not supported." ); 413 } 414 415 // NOTE: No GC allocations may occur until the stack pointers have 416 // been set and Thread.getThis returns a valid reference to 417 // this thread object (this latter condition is not strictly 418 // necessary on Windows but it should be followed for the 419 // sake of consistency). 420 421 // TODO: Consider putting an auto exception object here (using 422 // alloca) forOutOfMemoryError plus something to track 423 // whether an exception is in-flight? 424 425 void append( Throwable t ) 426 { 427 if( obj.m_unhandled is null ) 428 obj.m_unhandled = t; 429 else 430 { 431 Throwable last = obj.m_unhandled; 432 while( last.next !is null ) 433 last = last.next; 434 last.next = t; 435 } 436 } 437 438 try 439 { 440 rt_moduleTlsCtor(); 441 try 442 { 443 obj.run(); 444 } 445 catch( Throwable t ) 446 { 447 append( t ); 448 } 449 rt_moduleTlsDtor(); 450 } 451 catch( Throwable t ) 452 { 453 append( t ); 454 } 455 456 // NOTE: Normal cleanup is handled by scope(exit). 457 458 static if( __traits( compiles, pthread_cleanup ) ) 459 { 460 cleanup.pop( 0 ); 461 } 462 else static if( __traits( compiles, pthread_cleanup_push ) ) 463 { 464 pthread_cleanup_pop( 0 ); 465 } 466 467 return null; 468 } 469 470 471 // 472 // Used to track the number of suspended threads 473 // 474 __gshared sem_t suspendCount; 475 476 477 extern (C) void thread_suspendHandler( int sig ) 478 in 479 { 480 assert( sig == SIGUSR1 ); 481 } 482 body 483 { 484 void op(void* sp) 485 { 486 // NOTE: Since registers are being pushed and popped from the 487 // stack, any other stack data used by this function should 488 // be gone before the stack cleanup code is called below. 489 Thread obj = Thread.getThis(); 490 491 // NOTE: The thread reference returned by getThis is set within 492 // the thread startup code, so it is possible that this 493 // handler may be called before the reference is set. In 494 // this case it is safe to simply suspend and not worry 495 // about the stack pointers as the thread will not have 496 // any references to GC-managed data. 497 if( obj && !obj.m_lock ) 498 { 499 obj.m_curr.tstack = getStackTop(); 500 } 501 502 sigset_t sigres = void; 503 int status; 504 505 status = sigfillset( &sigres ); 506 assert( status == 0 ); 507 508 status = sigdelset( &sigres, SIGUSR2 ); 509 assert( status == 0 ); 510 511 status = sem_post( &suspendCount ); 512 assert( status == 0 ); 513 514 sigsuspend( &sigres ); 515 516 if( obj && !obj.m_lock ) 517 { 518 obj.m_curr.tstack = obj.m_curr.bstack; 519 } 520 } 521 522 callWithStackShell(&op); 523 } 524 525 526 extern (C) void thread_resumeHandler( int sig ) 527 in 528 { 529 assert( sig == SIGUSR2 ); 530 } 531 body 532 { 533 534 } 535 } 536} 537else 538{ 539 // NOTE: This is the only place threading versions are checked. If a new 540 // version is added, the module code will need to be searched for 541 // places where version-specific code may be required. This can be 542 // easily accomlished by searching for 'Windows' or 'Posix'. 543 static assert( false, "Unknown threading implementation." ); 544} 545 546 547/////////////////////////////////////////////////////////////////////////////// 548// Thread 549/////////////////////////////////////////////////////////////////////////////// 550 551 552/** 553 * This class encapsulates all threading functionality for the D 554 * programming language. As thread manipulation is a required facility 555 * for garbage collection, all user threads should derive from this 556 * class, and instances of this class should never be explicitly deleted. 557 * A new thread may be created using either derivation or composition, as 558 * in the following example. 559 * 560 * Example: 561 * ---------------------------------------------------------------------------- 562 * 563 * class DerivedThread : Thread 564 * { 565 * this() 566 * { 567 * super( &run ); 568 * } 569 * 570 * private : 571 * void run() 572 * { 573 * printf( "Derived thread running.\n" ); 574 * } 575 * } 576 * 577 * void threadFunc() 578 * { 579 * printf( "Composed thread running.\n" ); 580 * } 581 * 582 * // create instances of each type 583 * Thread derived = new DerivedThread(); 584 * Thread composed = new Thread( &threadFunc ); 585 * 586 * // start both threads 587 * derived.start(); 588 * composed.start(); 589 * 590 * ---------------------------------------------------------------------------- 591 */ 592class Thread 593{ 594 /////////////////////////////////////////////////////////////////////////// 595 // Initialization 596 /////////////////////////////////////////////////////////////////////////// 597 598 599 /** 600 * Initializes a thread object which is associated with a static 601 * D function. 602 * 603 * Params: 604 * fn = The thread function. 605 * sz = The stack size for this thread. 606 * 607 * In: 608 * fn must not be null. 609 */ 610 this( void function() fn, size_t sz = 0 ) 611 in 612 { 613 assert( fn ); 614 } 615 body 616 { 617 this(); 618 m_fn = fn; 619 m_sz = sz; 620 m_call = Call.FN; 621 m_curr = &m_main; 622 } 623 624 625 /** 626 * Initializes a thread object which is associated with a dynamic 627 * D function. 628 * 629 * Params: 630 * dg = The thread function. 631 * sz = The stack size for this thread. 632 * 633 * In: 634 * dg must not be null. 635 */ 636 this( void delegate() dg, size_t sz = 0 ) 637 in 638 { 639 assert( dg ); 640 } 641 body 642 { 643 this(); 644 m_dg = dg; 645 m_sz = sz; 646 m_call = Call.DG; 647 m_curr = &m_main; 648 } 649 650 651 /** 652 * Cleans up any remaining resources used by this object. 653 */ 654 ~this() 655 { 656 if( m_addr == m_addr.init ) 657 { 658 return; 659 } 660 661 version( Windows ) 662 { 663 m_addr = m_addr.init; 664 CloseHandle( m_hndl ); 665 m_hndl = m_hndl.init; 666 } 667 else version( Posix ) 668 { 669 pthread_detach( m_addr ); 670 m_addr = m_addr.init; 671 } 672 version( OSX ) 673 { 674 m_tmach = m_tmach.init; 675 } 676 rt.tlsgc.destroy( m_tlsgcdata ); 677 m_tlsgcdata = null; 678 } 679 680 681 /////////////////////////////////////////////////////////////////////////// 682 // General Actions 683 /////////////////////////////////////////////////////////////////////////// 684 685 686 /** 687 * Starts the thread and invokes the function or delegate passed upon 688 * construction. 689 * 690 * In: 691 * This routine may only be called once per thread instance. 692 * 693 * Throws: 694 * ThreadException if the thread fails to start. 695 */ 696 final void start() 697 in 698 { 699 assert( !next && !prev ); 700 } 701 body 702 { 703 auto wasThreaded = multiThreadedFlag; 704 multiThreadedFlag = true; 705 scope( failure ) 706 { 707 if( !wasThreaded ) 708 multiThreadedFlag = false; 709 } 710 711 version( Windows ) {} else 712 version( Posix ) 713 { 714 pthread_attr_t attr; 715 716 if( pthread_attr_init( &attr ) ) 717 throw new ThreadException( "Error initializing thread attributes" ); 718 if( m_sz && pthread_attr_setstacksize( &attr, m_sz ) ) 719 throw new ThreadException( "Error initializing thread stack size" ); 720 if( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) ) 721 throw new ThreadException( "Error setting thread joinable" ); 722 } 723 724 version( Windows ) 725 { 726 // NOTE: If a thread is just executing DllMain() 727 // while another thread is started here, it holds an OS internal 728 // lock that serializes DllMain with CreateThread. As the code 729 // might request a synchronization on slock (e.g. in thread_findByAddr()), 730 // we cannot hold that lock while creating the thread without 731 // creating a deadlock 732 // 733 // Solution: Create the thread in suspended state and then 734 // add and resume it with slock acquired 735 assert(m_sz <= uint.max, "m_sz must be less than or equal to uint.max"); 736 m_hndl = cast(HANDLE) _beginthreadex( null, cast(uint) m_sz, &thread_entryPoint, cast(void*) this, CREATE_SUSPENDED, &m_addr ); 737 if( cast(size_t) m_hndl == 0 ) 738 throw new ThreadException( "Error creating thread" ); 739 } 740 741 // NOTE: The starting thread must be added to the global thread list 742 // here rather than within thread_entryPoint to prevent a race 743 // with the main thread, which could finish and terminat the 744 // app without ever knowing that it should have waited for this 745 // starting thread. In effect, not doing the add here risks 746 // having thread being treated like a daemon thread. 747 synchronized( slock ) 748 { 749 version( Windows ) 750 { 751 if( ResumeThread( m_hndl ) == -1 ) 752 throw new ThreadException( "Error resuming thread" ); 753 } 754 else version( Posix ) 755 { 756 // NOTE: This is also set to true by thread_entryPoint, but set it 757 // here as well so the calling thread will see the isRunning 758 // state immediately. 759 m_isRunning = true; 760 scope( failure ) m_isRunning = false; 761 762 if( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 ) 763 throw new ThreadException( "Error creating thread" ); 764 } 765 version( OSX ) 766 { 767 m_tmach = pthread_mach_thread_np( m_addr ); 768 if( m_tmach == m_tmach.init ) 769 throw new ThreadException( "Error creating thread" ); 770 } 771 772 // NOTE: when creating threads from inside a DLL, DllMain(THREAD_ATTACH) 773 // might be called before ResumeThread returns, but the dll 774 // helper functions need to know whether the thread is created 775 // from the runtime itself or from another DLL or the application 776 // to just attach to it 777 // as a consequence, the new Thread object is added before actual 778 // creation of the thread. There should be no problem with the GC 779 // calling thread_suspendAll, because of the slock synchronization 780 // 781 // VERIFY: does this actually also apply to other platforms? 782 add( this ); 783 } 784 } 785 786 787 /** 788 * Waits for this thread to complete. If the thread terminated as the 789 * result of an unhandled exception, this exception will be rethrown. 790 * 791 * Params: 792 * rethrow = Rethrow any unhandled exception which may have caused this 793 * thread to terminate. 794 * 795 * Throws: 796 * ThreadException if the operation fails. 797 * Any exception not handled by the joined thread. 798 * 799 * Returns: 800 * Any exception not handled by this thread if rethrow = false, null 801 * otherwise. 802 */ 803 final Throwable join( bool rethrow = true ) 804 { 805 version( Windows ) 806 { 807 if( WaitForSingleObject( m_hndl, INFINITE ) != WAIT_OBJECT_0 ) 808 throw new ThreadException( "Unable to join thread" ); 809 // NOTE: m_addr must be cleared before m_hndl is closed to avoid 810 // a race condition with isRunning. The operation is done 811 // with atomicStore to prevent compiler reordering. 812 atomicStore!(MemoryOrder.raw)(*cast(shared)&m_addr, m_addr.init); 813 CloseHandle( m_hndl ); 814 m_hndl = m_hndl.init; 815 } 816 else version( Posix ) 817 { 818 if( pthread_join( m_addr, null ) != 0 ) 819 throw new ThreadException( "Unable to join thread" ); 820 // NOTE: pthread_join acts as a substitute for pthread_detach, 821 // which is normally called by the dtor. Setting m_addr 822 // to zero ensures that pthread_detach will not be called 823 // on object destruction. 824 m_addr = m_addr.init; 825 } 826 if( m_unhandled ) 827 { 828 if( rethrow ) 829 throw m_unhandled; 830 return m_unhandled; 831 } 832 return null; 833 } 834 835 836 /////////////////////////////////////////////////////////////////////////// 837 // General Properties 838 /////////////////////////////////////////////////////////////////////////// 839 840 841 /** 842 * Gets the user-readable label for this thread. 843 * 844 * Returns: 845 * The name of this thread. 846 */ 847 final @property string name() 848 { 849 synchronized( this ) 850 { 851 return m_name; 852 } 853 } 854 855 856 /** 857 * Sets the user-readable label for this thread. 858 * 859 * Params: 860 * val = The new name of this thread. 861 */ 862 final @property void name( string val ) 863 { 864 synchronized( this ) 865 { 866 m_name = val; 867 } 868 } 869 870 871 /** 872 * Gets the daemon status for this thread. While the runtime will wait for 873 * all normal threads to complete before tearing down the process, daemon 874 * threads are effectively ignored and thus will not prevent the process 875 * from terminating. In effect, daemon threads will be terminated 876 * automatically by the OS when the process exits. 877 * 878 * Returns: 879 * true if this is a daemon thread. 880 */ 881 final @property bool isDaemon() 882 { 883 synchronized( this ) 884 { 885 return m_isDaemon; 886 } 887 } 888 889 890 /** 891 * Sets the daemon status for this thread. While the runtime will wait for 892 * all normal threads to complete before tearing down the process, daemon 893 * threads are effectively ignored and thus will not prevent the process 894 * from terminating. In effect, daemon threads will be terminated 895 * automatically by the OS when the process exits. 896 * 897 * Params: 898 * val = The new daemon status for this thread. 899 */ 900 final @property void isDaemon( bool val ) 901 { 902 synchronized( this ) 903 { 904 m_isDaemon = val; 905 } 906 } 907 908 909 /** 910 * Tests whether this thread is running. 911 * 912 * Returns: 913 * true if the thread is running, false if not. 914 */ 915 final @property bool isRunning() 916 { 917 if( m_addr == m_addr.init ) 918 { 919 return false; 920 } 921 922 version( Windows ) 923 { 924 uint ecode = 0; 925 GetExitCodeThread( m_hndl, &ecode ); 926 return ecode == STILL_ACTIVE; 927 } 928 else version( Posix ) 929 { 930 // NOTE: It should be safe to access this value without 931 // memory barriers because word-tearing and such 932 // really isn't an issue for boolean values. 933 return m_isRunning; 934 } 935 } 936 937 938 /////////////////////////////////////////////////////////////////////////// 939 // Thread Priority Actions 940 /////////////////////////////////////////////////////////////////////////// 941 942 943 /** 944 * The minimum scheduling priority that may be set for a thread. On 945 * systems where multiple scheduling policies are defined, this value 946 * represents the minimum valid priority for the scheduling policy of 947 * the process. 948 */ 949 __gshared const int PRIORITY_MIN; 950 951 952 /** 953 * The maximum scheduling priority that may be set for a thread. On 954 * systems where multiple scheduling policies are defined, this value 955 * represents the minimum valid priority for the scheduling policy of 956 * the process. 957 */ 958 __gshared const int PRIORITY_MAX; 959 960 961 /** 962 * Gets the scheduling priority for the associated thread. 963 * 964 * Returns: 965 * The scheduling priority of this thread. 966 */ 967 final @property int priority() 968 { 969 version( Windows ) 970 { 971 return GetThreadPriority( m_hndl ); 972 } 973 else version( Posix ) 974 { 975 int policy; 976 sched_param param; 977 978 if( pthread_getschedparam( m_addr, &policy, ¶m ) ) 979 throw new ThreadException( "Unable to get thread priority" ); 980 return param.sched_priority; 981 } 982 } 983 984 985 /** 986 * Sets the scheduling priority for the associated thread. 987 * 988 * Params: 989 * val = The new scheduling priority of this thread. 990 */ 991 final @property void priority( int val ) 992 { 993 version( Windows ) 994 { 995 if( !SetThreadPriority( m_hndl, val ) ) 996 throw new ThreadException( "Unable to set thread priority" ); 997 } 998 else version( Posix ) 999 { 1000 // NOTE: pthread_setschedprio is not implemented on linux, so use 1001 // the more complicated get/set sequence below. 1002 //if( pthread_setschedprio( m_addr, val ) ) 1003 // throw new ThreadException( "Unable to set thread priority" ); 1004 1005 int policy; 1006 sched_param param; 1007 1008 if( pthread_getschedparam( m_addr, &policy, ¶m ) ) 1009 throw new ThreadException( "Unable to set thread priority" ); 1010 param.sched_priority = val; 1011 if( pthread_setschedparam( m_addr, policy, ¶m ) ) 1012 throw new ThreadException( "Unable to set thread priority" ); 1013 } 1014 } 1015 1016 1017 /////////////////////////////////////////////////////////////////////////// 1018 // Actions on Calling Thread 1019 /////////////////////////////////////////////////////////////////////////// 1020 1021 1022 /** 1023 * Suspends the calling thread for at least the supplied period. This may 1024 * result in multiple OS calls if period is greater than the maximum sleep 1025 * duration supported by the operating system. 1026 * 1027 * Params: 1028 * val = The minimum duration the calling thread should be suspended. 1029 * 1030 * In: 1031 * period must be non-negative. 1032 * 1033 * Example: 1034 * ------------------------------------------------------------------------ 1035 * 1036 * Thread.sleep( dur!("msecs")( 50 ) ); // sleep for 50 milliseconds 1037 * Thread.sleep( dur!("seconds")( 5 ) ); // sleep for 5 seconds 1038 * 1039 * ------------------------------------------------------------------------ 1040 */ 1041 static void sleep( Duration val ) 1042 in 1043 { 1044 assert( !val.isNegative ); 1045 } 1046 body 1047 { 1048 version( Windows ) 1049 { 1050 auto maxSleepMillis = dur!("msecs")( uint.max - 1 ); 1051 1052 // NOTE: In instances where all other threads in the process have a 1053 // lower priority than the current thread, the current thread 1054 // will not yield with a sleep time of zero. However, unlike 1055 // yield(), the user is not asking for a yield to occur but 1056 // only for execution to suspend for the requested interval. 1057 // Therefore, expected performance may not be met if a yield 1058 // is forced upon the user. 1059 while( val > maxSleepMillis ) 1060 { 1061 Sleep( cast(uint) 1062 maxSleepMillis.total!"msecs" ); 1063 val -= maxSleepMillis; 1064 } 1065 Sleep( cast(uint) val.total!"msecs" ); 1066 } 1067 else version( Posix ) 1068 { 1069 timespec tin = void; 1070 timespec tout = void; 1071 1072 if( val.total!"seconds" > tin.tv_sec.max ) 1073 { 1074 tin.tv_sec = tin.tv_sec.max; 1075 tin.tv_nsec = cast(typeof(tin.tv_nsec)) val.fracSec.nsecs; 1076 } 1077 else 1078 { 1079 tin.tv_sec = cast(typeof(tin.tv_sec)) val.total!"seconds"; 1080 tin.tv_nsec = cast(typeof(tin.tv_nsec)) val.fracSec.nsecs; 1081 } 1082 while( true ) 1083 { 1084 if( !nanosleep( &tin, &tout ) ) 1085 return; 1086 if( errno != EINTR ) 1087 throw new ThreadException( "Unable to sleep for the specified duration" ); 1088 tin = tout; 1089 } 1090 } 1091 } 1092 1093 1094 /** 1095 * $(RED Deprecated. It will be removed in December 2012. Please use the 1096 * version which takes a $(D Duration) instead.) 1097 * 1098 * Suspends the calling thread for at least the supplied period. This may 1099 * result in multiple OS calls if period is greater than the maximum sleep 1100 * duration supported by the operating system. 1101 * 1102 * Params: 1103 * period = The minimum duration the calling thread should be suspended, 1104 * in 100 nanosecond intervals. 1105 * 1106 * In: 1107 * period must be non-negative. 1108 * 1109 * Example: 1110 * ------------------------------------------------------------------------ 1111 * 1112 * Thread.sleep( 500_000 ); // sleep for 50 milliseconds 1113 * Thread.sleep( 50_000_000 ); // sleep for 5 seconds 1114 * 1115 * ------------------------------------------------------------------------ 1116 */ 1117 deprecated("Please use the overload of sleep which takes a Duration.") 1118 static void sleep( long period ) 1119 in 1120 { 1121 assert( period >= 0 ); 1122 } 1123 body 1124 { 1125 sleep( dur!"hnsecs"( period ) ); 1126 } 1127 1128 1129 /** 1130 * Forces a context switch to occur away from the calling thread. 1131 */ 1132 static void yield() 1133 { 1134 version( Windows ) 1135 SwitchToThread(); 1136 else version( Posix ) 1137 sched_yield(); 1138 } 1139 1140 1141 /////////////////////////////////////////////////////////////////////////// 1142 // Thread Accessors 1143 /////////////////////////////////////////////////////////////////////////// 1144 1145 1146 /** 1147 * Provides a reference to the calling thread. 1148 * 1149 * Returns: 1150 * The thread object representing the calling thread. The result of 1151 * deleting this object is undefined. If the current thread is not 1152 * attached to the runtime, a null reference is returned. 1153 */ 1154 static Thread getThis() 1155 { 1156 // NOTE: This function may not be called until thread_init has 1157 // completed. See thread_suspendAll for more information 1158 // on why this might occur. 1159 version( Windows ) 1160 { 1161 auto t = cast(Thread) TlsGetValue( sm_this ); 1162 1163 // NOTE: If this thread was attached via thread_attachByAddr then 1164 // this TLS lookup won't initially be set, so when the TLS 1165 // lookup fails, try an exhaustive search. 1166 if( t is null ) 1167 { 1168 t = thread_findByAddr( GetCurrentThreadId() ); 1169 setThis( t ); 1170 } 1171 return t; 1172 } 1173 else version( Posix ) 1174 { 1175 auto t = cast(Thread) pthread_getspecific( sm_this ); 1176 1177 // NOTE: See the comment near thread_findByAddr() for why the 1178 // secondary thread_findByAddr lookup can't be done on 1179 // Posix. However, because thread_attachByAddr() is for 1180 // Windows only, the secondary lookup is pointless anyway. 1181 return t; 1182 } 1183 } 1184 1185 1186 /** 1187 * Provides a list of all threads currently being tracked by the system. 1188 * 1189 * Returns: 1190 * An array containing references to all threads currently being 1191 * tracked by the system. The result of deleting any contained 1192 * objects is undefined. 1193 */ 1194 static Thread[] getAll() 1195 { 1196 synchronized( slock ) 1197 { 1198 size_t pos = 0; 1199 Thread[] buf = new Thread[sm_tlen]; 1200 1201 foreach( Thread t; Thread ) 1202 { 1203 buf[pos++] = t; 1204 } 1205 return buf; 1206 } 1207 } 1208 1209 1210 /** 1211 * Operates on all threads currently being tracked by the system. The 1212 * result of deleting any Thread object is undefined. 1213 * 1214 * Params: 1215 * dg = The supplied code as a delegate. 1216 * 1217 * Returns: 1218 * Zero if all elemented are visited, nonzero if not. 1219 */ 1220 static int opApply( scope int delegate( ref Thread ) dg ) 1221 { 1222 synchronized( slock ) 1223 { 1224 int ret = 0; 1225 1226 for( Thread t = sm_tbeg; t; t = t.next ) 1227 { 1228 ret = dg( t ); 1229 if( ret ) 1230 break; 1231 } 1232 return ret; 1233 } 1234 } 1235 1236 1237 /////////////////////////////////////////////////////////////////////////// 1238 // Static Initalizer 1239 /////////////////////////////////////////////////////////////////////////// 1240 1241 1242 /** 1243 * This initializer is used to set thread constants. All functional 1244 * initialization occurs within thread_init(). 1245 */ 1246 shared static this() 1247 { 1248 version( Windows ) 1249 { 1250 PRIORITY_MIN = -15; 1251 PRIORITY_MAX = 15; 1252 } 1253 else version( Posix ) 1254 { 1255 int policy; 1256 sched_param param; 1257 pthread_t self = pthread_self(); 1258 1259 int status = pthread_getschedparam( self, &policy, ¶m ); 1260 assert( status == 0 ); 1261 1262 PRIORITY_MIN = sched_get_priority_min( policy ); 1263 assert( PRIORITY_MIN != -1 ); 1264 1265 PRIORITY_MAX = sched_get_priority_max( policy ); 1266 assert( PRIORITY_MAX != -1 ); 1267 } 1268 } 1269 1270 1271 /////////////////////////////////////////////////////////////////////////// 1272 // Stuff That Should Go Away 1273 /////////////////////////////////////////////////////////////////////////// 1274 1275 1276private: 1277 // 1278 // Initializes a thread object which has no associated executable function. 1279 // This is used for the main thread initialized in thread_init(). 1280 // 1281 this() 1282 { 1283 m_call = Call.NO; 1284 m_curr = &m_main; 1285 1286 version (LDC_NoTlsBracketSyms) {} else 1287 version (OSX) 1288 { 1289 //printf("test2 %p %p\n", _tls_data_array[0].ptr, &_tls_data_array[1][length]); 1290 //printf("test2 %p %p\n", &_tls_beg, &_tls_end); 1291 // NOTE: OSX does not support TLS, so we do it ourselves. The TLS 1292 // data output by the compiler is bracketed by _tls_data_array2], 1293 // so make a copy of it for each thread. 1294 const sz0 = (_tls_data_array[0].length + 15) & ~cast(size_t)15; 1295 const sz2 = sz0 + _tls_data_array[1].length; 1296 auto p = malloc( sz2 ); 1297 assert( p ); 1298 m_tls = p[0 .. sz2]; 1299 memcpy( p, _tls_data_array[0].ptr, _tls_data_array[0].length ); 1300 memcpy( p + sz0, _tls_data_array[1].ptr, _tls_data_array[1].length ); 1301 // The free must happen at program end, if anywhere. 1302 } 1303 else 1304 { 1305 auto pstart = cast(void*) &_tlsstart; 1306 auto pend = cast(void*) &_tlsend; 1307 m_tls = pstart[0 .. pend - pstart]; 1308 } 1309 } 1310 1311 1312 // 1313 // Thread entry point. Invokes the function or delegate passed on 1314 // construction (if any). 1315 // 1316 final void run() 1317 { 1318 switch( m_call ) 1319 { 1320 case Call.FN: 1321 m_fn(); 1322 break; 1323 case Call.DG: 1324 m_dg(); 1325 break; 1326 default: 1327 break; 1328 } 1329 } 1330 1331 1332private: 1333 // 1334 // The type of routine passed on thread construction. 1335 // 1336 enum Call 1337 { 1338 NO, 1339 FN, 1340 DG 1341 } 1342 1343 1344 // 1345 // Standard types 1346 // 1347 version( Windows ) 1348 { 1349 alias uint TLSKey; 1350 alias uint ThreadAddr; 1351 } 1352 else version( Posix ) 1353 { 1354 alias pthread_key_t TLSKey; 1355 alias pthread_t ThreadAddr; 1356 } 1357 1358 1359 // 1360 // Local storage 1361 // 1362 __gshared TLSKey sm_this; 1363 1364 1365 // 1366 // Main process thread 1367 // 1368 __gshared Thread sm_main; 1369 1370 1371 // 1372 // Standard thread data 1373 // 1374 version( Windows ) 1375 { 1376 HANDLE m_hndl; 1377 } 1378 else version( OSX ) 1379 { 1380 mach_port_t m_tmach; 1381 } 1382 ThreadAddr m_addr; 1383 Call m_call; 1384 string m_name; 1385 union 1386 { 1387 void function() m_fn; 1388 void delegate() m_dg; 1389 } 1390 size_t m_sz; 1391 version( Posix ) 1392 { 1393 bool m_isRunning; 1394 } 1395 bool m_isDaemon; 1396 bool m_isInCriticalRegion; 1397 Throwable m_unhandled; 1398 1399 1400private: 1401 /////////////////////////////////////////////////////////////////////////// 1402 // Storage of Active Thread 1403 /////////////////////////////////////////////////////////////////////////// 1404 1405 1406 // 1407 // Sets a thread-local reference to the current thread object. 1408 // 1409 static void setThis( Thread t ) 1410 { 1411 version( Windows ) 1412 { 1413 TlsSetValue( sm_this, cast(void*) t ); 1414 } 1415 else version( Posix ) 1416 { 1417 pthread_setspecific( sm_this, cast(void*) t ); 1418 } 1419 } 1420 1421 1422private: 1423 /////////////////////////////////////////////////////////////////////////// 1424 // Thread Context and GC Scanning Support 1425 /////////////////////////////////////////////////////////////////////////// 1426 1427 1428 final void pushContext( Context* c ) 1429 in 1430 { 1431 assert( !c.within ); 1432 } 1433 body 1434 { 1435 c.within = m_curr; 1436 m_curr = c; 1437 } 1438 1439 1440 final void popContext() 1441 in 1442 { 1443 assert( m_curr && m_curr.within ); 1444 } 1445 body 1446 { 1447 Context* c = m_curr; 1448 m_curr = c.within; 1449 c.within = null; 1450 } 1451 1452 1453 final Context* topContext() 1454 in 1455 { 1456 assert( m_curr ); 1457 } 1458 body 1459 { 1460 return m_curr; 1461 } 1462 1463 1464 static struct Context 1465 { 1466 void* bstack, 1467 tstack; 1468 Context* within; 1469 Context* next, 1470 prev; 1471 } 1472 1473 1474 Context m_main; 1475 Context* m_curr; 1476 bool m_lock; 1477 void[] m_tls; // spans implicit thread local storage 1478 rt.tlsgc.Data* m_tlsgcdata; 1479 1480 version( Windows ) 1481 { 1482 version( X86 ) 1483 { 1484 uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax 1485 } 1486 else version( X86_64 ) 1487 { 1488 ulong[16] m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax 1489 // r8,r9,r10,r11,r12,r13,r14,r15 1490 } 1491 else 1492 { 1493 static assert(false, "Architecture not supported." ); 1494 } 1495 } 1496 else version( OSX ) 1497 { 1498 version( X86 ) 1499 { 1500 uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax 1501 } 1502 else version( X86_64 ) 1503 { 1504 ulong[16] m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax 1505 // r8,r9,r10,r11,r12,r13,r14,r15 1506 } 1507 else 1508 { 1509 static assert(false, "Architecture not supported." ); 1510 } 1511 } 1512 1513 1514private: 1515 /////////////////////////////////////////////////////////////////////////// 1516 // GC Scanning Support 1517 /////////////////////////////////////////////////////////////////////////// 1518 1519 1520 // NOTE: The GC scanning process works like so: 1521 // 1522 // 1. Suspend all threads. 1523 // 2. Scan the stacks of all suspended threads for roots. 1524 // 3. Resume all threads. 1525 // 1526 // Step 1 and 3 require a list of all threads in the system, while 1527 // step 2 requires a list of all thread stacks (each represented by 1528 // a Context struct). Traditionally, there was one stack per thread 1529 // and the Context structs were not necessary. However, Fibers have 1530 // changed things so that each thread has its own 'main' stack plus 1531 // an arbitrary number of nested stacks (normally referenced via 1532 // m_curr). Also, there may be 'free-floating' stacks in the system, 1533 // which are Fibers that are not currently executing on any specific 1534 // thread but are still being processed and still contain valid 1535 // roots. 1536 // 1537 // To support all of this, the Context struct has been created to 1538 // represent a stack range, and a global list of Context structs has 1539 // been added to enable scanning of these stack ranges. The lifetime 1540 // (and presence in the Context list) of a thread's 'main' stack will 1541 // be equivalent to the thread's lifetime. So the Ccontext will be 1542 // added to the list on thread entry, and removed from the list on 1543 // thread exit (which is essentially the same as the presence of a 1544 // Thread object in its own global list). The lifetime of a Fiber's 1545 // context, however, will be tied to the lifetime of the Fiber object 1546 // itself, and Fibers are expected to add/remove their Context struct 1547 // on construction/deletion. 1548 1549 1550 // 1551 // All use of the global lists should synchronize on this lock. 1552 // 1553 @property static Mutex slock() 1554 { 1555 __gshared Mutex m; 1556 __gshared byte[__traits(classInstanceSize, Mutex)] ms; 1557 1558 if (m is null) 1559 { 1560 // Initialization doesn't need to be synchronized because 1561 // creating a thread will lock this mutex. 1562 ms[] = Mutex.classinfo.init[]; 1563 m = cast(Mutex)ms.ptr; 1564 m.__ctor(); 1565 1566 extern(C) void destroy() { m.__dtor(); } 1567 atexit(&destroy); 1568 } 1569 return m; 1570 } 1571 1572 __gshared Context* sm_cbeg; 1573 __gshared size_t sm_clen; 1574 1575 __gshared Thread sm_tbeg; 1576 __gshared size_t sm_tlen; 1577 1578 // 1579 // Used for ordering threads in the global thread list. 1580 // 1581 Thread prev; 1582 Thread next; 1583 1584 1585 /////////////////////////////////////////////////////////////////////////// 1586 // Global Context List Operations 1587 /////////////////////////////////////////////////////////////////////////// 1588 1589 1590 // 1591 // Add a context to the global context list. 1592 // 1593 static void add( Context* c ) 1594 in 1595 { 1596 assert( c ); 1597 assert( !c.next && !c.prev ); 1598 } 1599 body 1600 { 1601 // NOTE: This loop is necessary to avoid a race between newly created 1602 // threads and the GC. If a collection starts between the time 1603 // Thread.start is called and the new thread calls Thread.add, 1604 // the thread will have its stack scanned without first having 1605 // been properly suspended. Testing has shown this to sometimes 1606 // cause a deadlock. 1607 1608 while( true ) 1609 { 1610 synchronized( slock ) 1611 { 1612 if( !suspendDepth ) 1613 { 1614 if( sm_cbeg ) 1615 { 1616 c.next = sm_cbeg; 1617 sm_cbeg.prev = c; 1618 } 1619 sm_cbeg = c; 1620 ++sm_clen; 1621 return; 1622 } 1623 } 1624 yield(); 1625 } 1626 } 1627 1628 1629 // 1630 // Remove a context from the global context list. 1631 // 1632 static void remove( Context* c ) 1633 in 1634 { 1635 assert( c ); 1636 assert( c.next || c.prev ); 1637 } 1638 body 1639 { 1640 synchronized( slock ) 1641 { 1642 if( c.prev ) 1643 c.prev.next = c.next; 1644 if( c.next ) 1645 c.next.prev = c.prev; 1646 if( sm_cbeg == c ) 1647 sm_cbeg = c.next; 1648 --sm_clen; 1649 } 1650 // NOTE: Don't null out c.next or c.prev because opApply currently 1651 // follows c.next after removing a node. This could be easily 1652 // addressed by simply returning the next node from this 1653 // function, however, a context should never be re-added to the 1654 // list anyway and having next and prev be non-null is a good way 1655 // to ensure that. 1656 } 1657 1658 1659 /////////////////////////////////////////////////////////////////////////// 1660 // Global Thread List Operations 1661 /////////////////////////////////////////////////////////////////////////// 1662 1663 1664 // 1665 // Add a thread to the global thread list. 1666 // 1667 static void add( Thread t ) 1668 in 1669 { 1670 assert( t ); 1671 assert( !t.next && !t.prev ); 1672 //assert( t.isRunning ); 1673 } 1674 body 1675 { 1676 // NOTE: This loop is necessary to avoid a race between newly created 1677 // threads and the GC. If a collection starts between the time 1678 // Thread.start is called and the new thread calls Thread.add, 1679 // the thread could manipulate global state while the collection 1680 // is running, and by being…
Large files files are truncated, but you can click here to view the full file