1 /** 2 * The osthread module provides low-level, OS-dependent code 3 * for thread creation and management. 4 * 5 * Copyright: Copyright Sean Kelly 2005 - 2012. 6 * License: Distributed under the 7 * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). 8 * (See accompanying file LICENSE) 9 * Authors: Sean Kelly, Walter Bright, Alex Rnne Petersen, Martin Nowak 10 * Source: $(DRUNTIMESRC core/thread/osthread.d) 11 */ 12 13 /* NOTE: This file has been patched from the original DMD distribution to 14 * work with the GDC compiler. 15 */ 16 module core.thread.osthread; 17 18 import core.thread.threadbase; 19 import core.thread.context; 20 import core.thread.types; 21 import core.atomic; 22 import core.memory : GC; 23 import core.time; 24 import core.exception : onOutOfMemoryError; 25 import core.internal.traits : externDFunc; 26 27 28 /////////////////////////////////////////////////////////////////////////////// 29 // Platform Detection and Memory Allocation 30 /////////////////////////////////////////////////////////////////////////////// 31 32 version (OSX) 33 version = Darwin; 34 else version (iOS) 35 version = Darwin; 36 else version (TVOS) 37 version = Darwin; 38 else version (WatchOS) 39 version = Darwin; 40 41 version (Shared) 42 version (GNU) 43 version = GNUShared; 44 45 version (D_InlineAsm_X86) 46 { 47 version (Windows) 48 version = AsmX86_Windows; 49 else version (Posix) 50 version = AsmX86_Posix; 51 } 52 else version (D_InlineAsm_X86_64) 53 { 54 version (Windows) 55 { 56 version = AsmX86_64_Windows; 57 } 58 else version (Posix) 59 { 60 version = AsmX86_64_Posix; 61 } 62 } 63 else version (X86) 64 { 65 version (CET) {} else 66 { 67 version = AsmExternal; 68 } 69 } 70 else version (X86_64) 71 { 72 version (CET) {} else 73 version (D_X32) {} else 74 { 75 version = AsmExternal; 76 } 77 } 78 else version (PPC) 79 { 80 version (Posix) 81 { 82 version = AsmExternal; 83 } 84 } 85 else version (MIPS_O32) 86 { 87 version (Posix) 88 { 89 version = AsmExternal; 90 } 91 } 92 else version (AArch64) 93 { 94 version (Posix) 95 { 96 version = AsmExternal; 97 } 98 } 99 else version (ARM) 100 { 101 version (Posix) 102 { 103 version = AsmExternal; 104 } 105 } 106 107 version (Posix) 108 { 109 version (AsmX86_Windows) {} else 110 version (AsmX86_Posix) {} else 111 version (AsmX86_64_Windows) {} else 112 version (AsmX86_64_Posix) {} else 113 version (AsmExternal) {} else 114 { 115 // NOTE: The ucontext implementation requires architecture specific 116 // data definitions to operate so testing for it must be done 117 // by checking for the existence of ucontext_t rather than by 118 // a version identifier. Please note that this is considered 119 // an obsolescent feature according to the POSIX spec, so a 120 // custom solution is still preferred. 121 import core.sys.posix.ucontext; 122 } 123 } 124 125 version (Windows) 126 { 127 import core.stdc.stdint : uintptr_t; // for _beginthreadex decl below 128 import core.stdc.stdlib; // for malloc, atexit 129 import core.sys.windows.basetsd /+: HANDLE+/; 130 import core.sys.windows.threadaux /+: getThreadStackBottom, impersonate_thread, OpenThreadHandle+/; 131 import core.sys.windows.winbase /+: CloseHandle, CREATE_SUSPENDED, DuplicateHandle, GetCurrentThread, 132 GetCurrentThreadId, GetCurrentProcess, GetExitCodeThread, GetSystemInfo, GetThreadContext, 133 GetThreadPriority, INFINITE, ResumeThread, SetThreadPriority, Sleep, STILL_ACTIVE, 134 SuspendThread, SwitchToThread, SYSTEM_INFO, THREAD_PRIORITY_IDLE, THREAD_PRIORITY_NORMAL, 135 THREAD_PRIORITY_TIME_CRITICAL, WAIT_OBJECT_0, WaitForSingleObject+/; 136 import core.sys.windows.windef /+: TRUE+/; 137 import core.sys.windows.winnt /+: CONTEXT, CONTEXT_CONTROL, CONTEXT_INTEGER+/; 138 139 private extern (Windows) alias btex_fptr = uint function(void*); 140 private extern (C) uintptr_t _beginthreadex(void*, uint, btex_fptr, void*, uint, uint*) nothrow @nogc; 141 } 142 else version (Posix) 143 { 144 import core.stdc.errno; 145 import core.sys.posix.semaphore; 146 import core.sys.posix.stdlib; // for malloc, valloc, free, atexit 147 import core.sys.posix.pthread; 148 import core.sys.posix.signal; 149 import core.sys.posix.time; 150 151 version (Darwin) 152 { 153 import core.sys.darwin.mach.thread_act; 154 import core.sys.darwin.pthread : pthread_mach_thread_np; 155 } 156 } 157 158 version (Solaris) 159 { 160 import core.sys.solaris.sys.priocntl; 161 import core.sys.solaris.sys.types; 162 import core.sys.posix.sys.wait : idtype_t; 163 } 164 165 version (GNU) 166 { 167 import gcc.builtins; 168 } 169 170 /** 171 * Hook for whatever EH implementation is used to save/restore some data 172 * per stack. 173 * 174 * Params: 175 * newContext = The return value of the prior call to this function 176 * where the stack was last swapped out, or null when a fiber stack 177 * is switched in for the first time. 178 */ 179 private extern(C) void* _d_eh_swapContext(void* newContext) nothrow @nogc; 180 181 version (DigitalMars) 182 { 183 version (Windows) 184 { 185 extern(D) void* swapContext(void* newContext) nothrow @nogc 186 { 187 return _d_eh_swapContext(newContext); 188 } 189 } 190 else 191 { 192 extern(C) void* _d_eh_swapContextDwarf(void* newContext) nothrow @nogc; 193 194 extern(D) void* swapContext(void* newContext) nothrow @nogc 195 { 196 /* Detect at runtime which scheme is being used. 197 * Eventually, determine it statically. 198 */ 199 static int which = 0; 200 final switch (which) 201 { 202 case 0: 203 { 204 assert(newContext == null); 205 auto p = _d_eh_swapContext(newContext); 206 auto pdwarf = _d_eh_swapContextDwarf(newContext); 207 if (p) 208 { 209 which = 1; 210 return p; 211 } 212 else if (pdwarf) 213 { 214 which = 2; 215 return pdwarf; 216 } 217 return null; 218 } 219 case 1: 220 return _d_eh_swapContext(newContext); 221 case 2: 222 return _d_eh_swapContextDwarf(newContext); 223 } 224 } 225 } 226 } 227 else 228 { 229 extern(D) void* swapContext(void* newContext) nothrow @nogc 230 { 231 return _d_eh_swapContext(newContext); 232 } 233 } 234 235 /////////////////////////////////////////////////////////////////////////////// 236 // Thread 237 /////////////////////////////////////////////////////////////////////////////// 238 239 /** 240 * This class encapsulates all threading functionality for the D 241 * programming language. As thread manipulation is a required facility 242 * for garbage collection, all user threads should derive from this 243 * class, and instances of this class should never be explicitly deleted. 244 * A new thread may be created using either derivation or composition, as 245 * in the following example. 246 */ 247 class Thread : ThreadBase 248 { 249 // 250 // Standard thread data 251 // 252 version (Windows) 253 { 254 private HANDLE m_hndl; 255 } 256 257 version (Posix) 258 { 259 private shared bool m_isRunning; 260 } 261 262 version (Darwin) 263 { 264 private mach_port_t m_tmach; 265 } 266 267 version (Solaris) 268 { 269 private __gshared bool m_isRTClass; 270 } 271 272 // 273 // Standard types 274 // 275 version (Windows) 276 { 277 alias TLSKey = uint; 278 } 279 else version (Posix) 280 { 281 alias TLSKey = pthread_key_t; 282 } 283 284 /////////////////////////////////////////////////////////////////////////// 285 // Initialization 286 /////////////////////////////////////////////////////////////////////////// 287 288 289 /** 290 * Initializes a thread object which is associated with a static 291 * D function. 292 * 293 * Params: 294 * fn = The thread function. 295 * sz = The stack size for this thread. 296 * 297 * In: 298 * fn must not be null. 299 */ 300 this( void function() fn, size_t sz = 0 ) @safe pure nothrow @nogc 301 { 302 super(fn, sz); 303 } 304 305 306 /** 307 * Initializes a thread object which is associated with a dynamic 308 * D function. 309 * 310 * Params: 311 * dg = The thread function. 312 * sz = The stack size for this thread. 313 * 314 * In: 315 * dg must not be null. 316 */ 317 this( void delegate() dg, size_t sz = 0 ) @safe pure nothrow @nogc 318 { 319 super(dg, sz); 320 } 321 322 package this( size_t sz = 0 ) @safe pure nothrow @nogc 323 { 324 super(sz); 325 } 326 327 /** 328 * Cleans up any remaining resources used by this object. 329 */ 330 ~this() nothrow @nogc 331 { 332 if (super.destructBeforeDtor()) 333 return; 334 335 version (Windows) 336 { 337 m_addr = m_addr.init; 338 CloseHandle( m_hndl ); 339 m_hndl = m_hndl.init; 340 } 341 else version (Posix) 342 { 343 if (m_addr != m_addr.init) 344 pthread_detach( m_addr ); 345 m_addr = m_addr.init; 346 } 347 version (Darwin) 348 { 349 m_tmach = m_tmach.init; 350 } 351 } 352 353 // 354 // Thread entry point. Invokes the function or delegate passed on 355 // construction (if any). 356 // 357 private final void run() 358 { 359 super.run(); 360 } 361 362 /** 363 * Provides a reference to the calling thread. 364 * 365 * Returns: 366 * The thread object representing the calling thread. The result of 367 * deleting this object is undefined. If the current thread is not 368 * attached to the runtime, a null reference is returned. 369 */ 370 static Thread getThis() @safe nothrow @nogc 371 { 372 return ThreadBase.getThis().toThread; 373 } 374 375 /////////////////////////////////////////////////////////////////////////// 376 // Thread Context and GC Scanning Support 377 /////////////////////////////////////////////////////////////////////////// 378 379 380 version (Windows) 381 { 382 version (X86) 383 { 384 uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax 385 } 386 else version (X86_64) 387 { 388 ulong[16] m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax 389 // r8,r9,r10,r11,r12,r13,r14,r15 390 } 391 else 392 { 393 static assert(false, "Architecture not supported." ); 394 } 395 } 396 else version (Darwin) 397 { 398 version (X86) 399 { 400 uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax 401 } 402 else version (X86_64) 403 { 404 ulong[16] m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax 405 // r8,r9,r10,r11,r12,r13,r14,r15 406 } 407 else version (AArch64) 408 { 409 ulong[33] m_reg; // x0-x31, pc 410 } 411 else version (ARM) 412 { 413 uint[16] m_reg; // r0-r15 414 } 415 else version (PPC) 416 { 417 // Make the assumption that we only care about non-fp and non-vr regs. 418 // ??? : it seems plausible that a valid address can be copied into a VR. 419 uint[32] m_reg; // r0-31 420 } 421 else version (PPC64) 422 { 423 // As above. 424 ulong[32] m_reg; // r0-31 425 } 426 else 427 { 428 static assert(false, "Architecture not supported." ); 429 } 430 } 431 432 433 /////////////////////////////////////////////////////////////////////////// 434 // General Actions 435 /////////////////////////////////////////////////////////////////////////// 436 437 438 /** 439 * Starts the thread and invokes the function or delegate passed upon 440 * construction. 441 * 442 * In: 443 * This routine may only be called once per thread instance. 444 * 445 * Throws: 446 * ThreadException if the thread fails to start. 447 */ 448 final Thread start() nothrow 449 in 450 { 451 assert( !next && !prev ); 452 } 453 do 454 { 455 auto wasThreaded = multiThreadedFlag; 456 multiThreadedFlag = true; 457 scope( failure ) 458 { 459 if ( !wasThreaded ) 460 multiThreadedFlag = false; 461 } 462 463 version (Windows) {} else 464 version (Posix) 465 { 466 size_t stksz = adjustStackSize( m_sz ); 467 468 pthread_attr_t attr; 469 470 if ( pthread_attr_init( &attr ) ) 471 onThreadError( "Error initializing thread attributes" ); 472 if ( stksz && pthread_attr_setstacksize( &attr, stksz ) ) 473 onThreadError( "Error initializing thread stack size" ); 474 } 475 476 version (Windows) 477 { 478 // NOTE: If a thread is just executing DllMain() 479 // while another thread is started here, it holds an OS internal 480 // lock that serializes DllMain with CreateThread. As the code 481 // might request a synchronization on slock (e.g. in thread_findByAddr()), 482 // we cannot hold that lock while creating the thread without 483 // creating a deadlock 484 // 485 // Solution: Create the thread in suspended state and then 486 // add and resume it with slock acquired 487 assert(m_sz <= uint.max, "m_sz must be less than or equal to uint.max"); 488 m_hndl = cast(HANDLE) _beginthreadex( null, cast(uint) m_sz, &thread_entryPoint, cast(void*) this, CREATE_SUSPENDED, &m_addr ); 489 if ( cast(size_t) m_hndl == 0 ) 490 onThreadError( "Error creating thread" ); 491 } 492 493 slock.lock_nothrow(); 494 scope(exit) slock.unlock_nothrow(); 495 { 496 ++nAboutToStart; 497 pAboutToStart = cast(ThreadBase*)realloc(pAboutToStart, Thread.sizeof * nAboutToStart); 498 pAboutToStart[nAboutToStart - 1] = this; 499 version (Windows) 500 { 501 if ( ResumeThread( m_hndl ) == -1 ) 502 onThreadError( "Error resuming thread" ); 503 } 504 else version (Posix) 505 { 506 // NOTE: This is also set to true by thread_entryPoint, but set it 507 // here as well so the calling thread will see the isRunning 508 // state immediately. 509 atomicStore!(MemoryOrder.raw)(m_isRunning, true); 510 scope( failure ) atomicStore!(MemoryOrder.raw)(m_isRunning, false); 511 512 version (Shared) 513 { 514 version (GNU) 515 { 516 auto libs = externDFunc!("gcc.sections.pinLoadedLibraries", 517 void* function() @nogc nothrow)(); 518 } 519 else 520 { 521 auto libs = externDFunc!("rt.sections_elf_shared.pinLoadedLibraries", 522 void* function() @nogc nothrow)(); 523 } 524 525 auto ps = cast(void**).malloc(2 * size_t.sizeof); 526 if (ps is null) onOutOfMemoryError(); 527 ps[0] = cast(void*)this; 528 ps[1] = cast(void*)libs; 529 if ( pthread_create( &m_addr, &attr, &thread_entryPoint, ps ) != 0 ) 530 { 531 version (GNU) 532 { 533 externDFunc!("gcc.sections.unpinLoadedLibraries", 534 void function(void*) @nogc nothrow)(libs); 535 } 536 else 537 { 538 externDFunc!("rt.sections_elf_shared.unpinLoadedLibraries", 539 void function(void*) @nogc nothrow)(libs); 540 } 541 .free(ps); 542 onThreadError( "Error creating thread" ); 543 } 544 } 545 else 546 { 547 if ( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 ) 548 onThreadError( "Error creating thread" ); 549 } 550 if ( pthread_attr_destroy( &attr ) != 0 ) 551 onThreadError( "Error destroying thread attributes" ); 552 } 553 version (Darwin) 554 { 555 m_tmach = pthread_mach_thread_np( m_addr ); 556 if ( m_tmach == m_tmach.init ) 557 onThreadError( "Error creating thread" ); 558 } 559 560 return this; 561 } 562 } 563 564 /** 565 * Waits for this thread to complete. If the thread terminated as the 566 * result of an unhandled exception, this exception will be rethrown. 567 * 568 * Params: 569 * rethrow = Rethrow any unhandled exception which may have caused this 570 * thread to terminate. 571 * 572 * Throws: 573 * ThreadException if the operation fails. 574 * Any exception not handled by the joined thread. 575 * 576 * Returns: 577 * Any exception not handled by this thread if rethrow = false, null 578 * otherwise. 579 */ 580 override final Throwable join( bool rethrow = true ) 581 { 582 version (Windows) 583 { 584 if ( m_addr != m_addr.init && WaitForSingleObject( m_hndl, INFINITE ) != WAIT_OBJECT_0 ) 585 throw new ThreadException( "Unable to join thread" ); 586 // NOTE: m_addr must be cleared before m_hndl is closed to avoid 587 // a race condition with isRunning. The operation is done 588 // with atomicStore to prevent compiler reordering. 589 atomicStore!(MemoryOrder.raw)(*cast(shared)&m_addr, m_addr.init); 590 CloseHandle( m_hndl ); 591 m_hndl = m_hndl.init; 592 } 593 else version (Posix) 594 { 595 if ( m_addr != m_addr.init && pthread_join( m_addr, null ) != 0 ) 596 throw new ThreadException( "Unable to join thread" ); 597 // NOTE: pthread_join acts as a substitute for pthread_detach, 598 // which is normally called by the dtor. Setting m_addr 599 // to zero ensures that pthread_detach will not be called 600 // on object destruction. 601 m_addr = m_addr.init; 602 } 603 if ( m_unhandled ) 604 { 605 if ( rethrow ) 606 throw m_unhandled; 607 return m_unhandled; 608 } 609 return null; 610 } 611 612 613 /////////////////////////////////////////////////////////////////////////// 614 // Thread Priority Actions 615 /////////////////////////////////////////////////////////////////////////// 616 617 version (Windows) 618 { 619 @property static int PRIORITY_MIN() @nogc nothrow pure @safe 620 { 621 return THREAD_PRIORITY_IDLE; 622 } 623 624 @property static const(int) PRIORITY_MAX() @nogc nothrow pure @safe 625 { 626 return THREAD_PRIORITY_TIME_CRITICAL; 627 } 628 629 @property static int PRIORITY_DEFAULT() @nogc nothrow pure @safe 630 { 631 return THREAD_PRIORITY_NORMAL; 632 } 633 } 634 else 635 { 636 private struct Priority 637 { 638 int PRIORITY_MIN = int.min; 639 int PRIORITY_DEFAULT = int.min; 640 int PRIORITY_MAX = int.min; 641 } 642 643 /* 644 Lazily loads one of the members stored in a hidden global variable of 645 type `Priority`. Upon the first access of either member, the entire 646 `Priority` structure is initialized. Multiple initializations from 647 different threads calling this function are tolerated. 648 649 `which` must be one of `PRIORITY_MIN`, `PRIORITY_DEFAULT`, 650 `PRIORITY_MAX`. 651 */ 652 private static shared Priority cache; 653 private static int loadGlobal(string which)() 654 { 655 auto local = atomicLoad(mixin("cache." ~ which)); 656 if (local != local.min) return local; 657 // There will be benign races 658 cache = loadPriorities; 659 return atomicLoad(mixin("cache." ~ which)); 660 } 661 662 /* 663 Loads all priorities and returns them as a `Priority` structure. This 664 function is thread-neutral. 665 */ 666 private static Priority loadPriorities() @nogc nothrow @trusted 667 { 668 Priority result; 669 version (Solaris) 670 { 671 pcparms_t pcParms; 672 pcinfo_t pcInfo; 673 674 pcParms.pc_cid = PC_CLNULL; 675 if (priocntl(idtype_t.P_PID, P_MYID, PC_GETPARMS, &pcParms) == -1) 676 assert( 0, "Unable to get scheduling class" ); 677 678 pcInfo.pc_cid = pcParms.pc_cid; 679 // PC_GETCLINFO ignores the first two args, use dummy values 680 if (priocntl(idtype_t.P_PID, 0, PC_GETCLINFO, &pcInfo) == -1) 681 assert( 0, "Unable to get scheduling class info" ); 682 683 pri_t* clparms = cast(pri_t*)&pcParms.pc_clparms; 684 pri_t* clinfo = cast(pri_t*)&pcInfo.pc_clinfo; 685 686 result.PRIORITY_MAX = clparms[0]; 687 688 if (pcInfo.pc_clname == "RT") 689 { 690 m_isRTClass = true; 691 692 // For RT class, just assume it can't be changed 693 result.PRIORITY_MIN = clparms[0]; 694 result.PRIORITY_DEFAULT = clparms[0]; 695 } 696 else 697 { 698 m_isRTClass = false; 699 700 // For all other scheduling classes, there are 701 // two key values -- uprilim and maxupri. 702 // maxupri is the maximum possible priority defined 703 // for the scheduling class, and valid priorities 704 // range are in [-maxupri, maxupri]. 705 // 706 // However, uprilim is an upper limit that the 707 // current thread can set for the current scheduling 708 // class, which can be less than maxupri. As such, 709 // use this value for priorityMax since this is 710 // the effective maximum. 711 712 // maxupri 713 result.PRIORITY_MIN = -cast(int)(clinfo[0]); 714 // by definition 715 result.PRIORITY_DEFAULT = 0; 716 } 717 } 718 else version (Posix) 719 { 720 int policy; 721 sched_param param; 722 pthread_getschedparam( pthread_self(), &policy, ¶m ) == 0 723 || assert(0, "Internal error in pthread_getschedparam"); 724 725 result.PRIORITY_MIN = sched_get_priority_min( policy ); 726 result.PRIORITY_MIN != -1 727 || assert(0, "Internal error in sched_get_priority_min"); 728 result.PRIORITY_DEFAULT = param.sched_priority; 729 result.PRIORITY_MAX = sched_get_priority_max( policy ); 730 result.PRIORITY_MAX != -1 || 731 assert(0, "Internal error in sched_get_priority_max"); 732 } 733 else 734 { 735 static assert(0, "Your code here."); 736 } 737 return result; 738 } 739 740 /** 741 * The minimum scheduling priority that may be set for a thread. On 742 * systems where multiple scheduling policies are defined, this value 743 * represents the minimum valid priority for the scheduling policy of 744 * the process. 745 */ 746 @property static int PRIORITY_MIN() @nogc nothrow pure @trusted 747 { 748 return (cast(int function() @nogc nothrow pure @safe) 749 &loadGlobal!"PRIORITY_MIN")(); 750 } 751 752 /** 753 * The maximum scheduling priority that may be set for a thread. On 754 * systems where multiple scheduling policies are defined, this value 755 * represents the maximum valid priority for the scheduling policy of 756 * the process. 757 */ 758 @property static const(int) PRIORITY_MAX() @nogc nothrow pure @trusted 759 { 760 return (cast(int function() @nogc nothrow pure @safe) 761 &loadGlobal!"PRIORITY_MAX")(); 762 } 763 764 /** 765 * The default scheduling priority that is set for a thread. On 766 * systems where multiple scheduling policies are defined, this value 767 * represents the default priority for the scheduling policy of 768 * the process. 769 */ 770 @property static int PRIORITY_DEFAULT() @nogc nothrow pure @trusted 771 { 772 return (cast(int function() @nogc nothrow pure @safe) 773 &loadGlobal!"PRIORITY_DEFAULT")(); 774 } 775 } 776 777 version (NetBSD) 778 { 779 //NetBSD does not support priority for default policy 780 // and it is not possible change policy without root access 781 int fakePriority = int.max; 782 } 783 784 /** 785 * Gets the scheduling priority for the associated thread. 786 * 787 * Note: Getting the priority of a thread that already terminated 788 * might return the default priority. 789 * 790 * Returns: 791 * The scheduling priority of this thread. 792 */ 793 final @property int priority() 794 { 795 version (Windows) 796 { 797 return GetThreadPriority( m_hndl ); 798 } 799 else version (NetBSD) 800 { 801 return fakePriority==int.max? PRIORITY_DEFAULT : fakePriority; 802 } 803 else version (Posix) 804 { 805 int policy; 806 sched_param param; 807 808 if (auto err = pthread_getschedparam(m_addr, &policy, ¶m)) 809 { 810 // ignore error if thread is not running => Bugzilla 8960 811 if (!atomicLoad(m_isRunning)) return PRIORITY_DEFAULT; 812 throw new ThreadException("Unable to get thread priority"); 813 } 814 return param.sched_priority; 815 } 816 } 817 818 819 /** 820 * Sets the scheduling priority for the associated thread. 821 * 822 * Note: Setting the priority of a thread that already terminated 823 * might have no effect. 824 * 825 * Params: 826 * val = The new scheduling priority of this thread. 827 */ 828 final @property void priority( int val ) 829 in 830 { 831 assert(val >= PRIORITY_MIN); 832 assert(val <= PRIORITY_MAX); 833 } 834 do 835 { 836 version (Windows) 837 { 838 if ( !SetThreadPriority( m_hndl, val ) ) 839 throw new ThreadException( "Unable to set thread priority" ); 840 } 841 else version (Solaris) 842 { 843 // the pthread_setschedprio(3c) and pthread_setschedparam functions 844 // are broken for the default (TS / time sharing) scheduling class. 845 // instead, we use priocntl(2) which gives us the desired behavior. 846 847 // We hardcode the min and max priorities to the current value 848 // so this is a no-op for RT threads. 849 if (m_isRTClass) 850 return; 851 852 pcparms_t pcparm; 853 854 pcparm.pc_cid = PC_CLNULL; 855 if (priocntl(idtype_t.P_LWPID, P_MYID, PC_GETPARMS, &pcparm) == -1) 856 throw new ThreadException( "Unable to get scheduling class" ); 857 858 pri_t* clparms = cast(pri_t*)&pcparm.pc_clparms; 859 860 // clparms is filled in by the PC_GETPARMS call, only necessary 861 // to adjust the element that contains the thread priority 862 clparms[1] = cast(pri_t) val; 863 864 if (priocntl(idtype_t.P_LWPID, P_MYID, PC_SETPARMS, &pcparm) == -1) 865 throw new ThreadException( "Unable to set scheduling class" ); 866 } 867 else version (NetBSD) 868 { 869 fakePriority = val; 870 } 871 else version (Posix) 872 { 873 static if (__traits(compiles, pthread_setschedprio)) 874 { 875 if (auto err = pthread_setschedprio(m_addr, val)) 876 { 877 // ignore error if thread is not running => Bugzilla 8960 878 if (!atomicLoad(m_isRunning)) return; 879 throw new ThreadException("Unable to set thread priority"); 880 } 881 } 882 else 883 { 884 // NOTE: pthread_setschedprio is not implemented on Darwin, FreeBSD, OpenBSD, 885 // or DragonFlyBSD, so use the more complicated get/set sequence below. 886 int policy; 887 sched_param param; 888 889 if (auto err = pthread_getschedparam(m_addr, &policy, ¶m)) 890 { 891 // ignore error if thread is not running => Bugzilla 8960 892 if (!atomicLoad(m_isRunning)) return; 893 throw new ThreadException("Unable to set thread priority"); 894 } 895 param.sched_priority = val; 896 if (auto err = pthread_setschedparam(m_addr, policy, ¶m)) 897 { 898 // ignore error if thread is not running => Bugzilla 8960 899 if (!atomicLoad(m_isRunning)) return; 900 throw new ThreadException("Unable to set thread priority"); 901 } 902 } 903 } 904 } 905 906 907 unittest 908 { 909 auto thr = Thread.getThis(); 910 immutable prio = thr.priority; 911 scope (exit) thr.priority = prio; 912 913 assert(prio == PRIORITY_DEFAULT); 914 assert(prio >= PRIORITY_MIN && prio <= PRIORITY_MAX); 915 thr.priority = PRIORITY_MIN; 916 assert(thr.priority == PRIORITY_MIN); 917 thr.priority = PRIORITY_MAX; 918 assert(thr.priority == PRIORITY_MAX); 919 } 920 921 unittest // Bugzilla 8960 922 { 923 import core.sync.semaphore; 924 925 auto thr = new Thread({}); 926 thr.start(); 927 Thread.sleep(1.msecs); // wait a little so the thread likely has finished 928 thr.priority = PRIORITY_MAX; // setting priority doesn't cause error 929 auto prio = thr.priority; // getting priority doesn't cause error 930 assert(prio >= PRIORITY_MIN && prio <= PRIORITY_MAX); 931 } 932 933 /** 934 * Tests whether this thread is running. 935 * 936 * Returns: 937 * true if the thread is running, false if not. 938 */ 939 override final @property bool isRunning() nothrow @nogc 940 { 941 if (!super.isRunning()) 942 return false; 943 944 version (Windows) 945 { 946 uint ecode = 0; 947 GetExitCodeThread( m_hndl, &ecode ); 948 return ecode == STILL_ACTIVE; 949 } 950 else version (Posix) 951 { 952 return atomicLoad(m_isRunning); 953 } 954 } 955 956 957 /////////////////////////////////////////////////////////////////////////// 958 // Actions on Calling Thread 959 /////////////////////////////////////////////////////////////////////////// 960 961 962 /** 963 * Suspends the calling thread for at least the supplied period. This may 964 * result in multiple OS calls if period is greater than the maximum sleep 965 * duration supported by the operating system. 966 * 967 * Params: 968 * val = The minimum duration the calling thread should be suspended. 969 * 970 * In: 971 * period must be non-negative. 972 * 973 * Example: 974 * ------------------------------------------------------------------------ 975 * 976 * Thread.sleep( dur!("msecs")( 50 ) ); // sleep for 50 milliseconds 977 * Thread.sleep( dur!("seconds")( 5 ) ); // sleep for 5 seconds 978 * 979 * ------------------------------------------------------------------------ 980 */ 981 static void sleep( Duration val ) @nogc nothrow 982 in 983 { 984 assert( !val.isNegative ); 985 } 986 do 987 { 988 version (Windows) 989 { 990 auto maxSleepMillis = dur!("msecs")( uint.max - 1 ); 991 992 // avoid a non-zero time to be round down to 0 993 if ( val > dur!"msecs"( 0 ) && val < dur!"msecs"( 1 ) ) 994 val = dur!"msecs"( 1 ); 995 996 // NOTE: In instances where all other threads in the process have a 997 // lower priority than the current thread, the current thread 998 // will not yield with a sleep time of zero. However, unlike 999 // yield(), the user is not asking for a yield to occur but 1000 // only for execution to suspend for the requested interval. 1001 // Therefore, expected performance may not be met if a yield 1002 // is forced upon the user. 1003 while ( val > maxSleepMillis ) 1004 { 1005 Sleep( cast(uint) 1006 maxSleepMillis.total!"msecs" ); 1007 val -= maxSleepMillis; 1008 } 1009 Sleep( cast(uint) val.total!"msecs" ); 1010 } 1011 else version (Posix) 1012 { 1013 timespec tin = void; 1014 timespec tout = void; 1015 1016 val.split!("seconds", "nsecs")(tin.tv_sec, tin.tv_nsec); 1017 if ( val.total!"seconds" > tin.tv_sec.max ) 1018 tin.tv_sec = tin.tv_sec.max; 1019 while ( true ) 1020 { 1021 if ( !nanosleep( &tin, &tout ) ) 1022 return; 1023 if ( errno != EINTR ) 1024 assert(0, "Unable to sleep for the specified duration"); 1025 tin = tout; 1026 } 1027 } 1028 } 1029 1030 1031 /** 1032 * Forces a context switch to occur away from the calling thread. 1033 */ 1034 static void yield() @nogc nothrow 1035 { 1036 version (Windows) 1037 SwitchToThread(); 1038 else version (Posix) 1039 sched_yield(); 1040 } 1041 } 1042 1043 private Thread toThread(return scope ThreadBase t) @trusted nothrow @nogc pure 1044 { 1045 return cast(Thread) cast(void*) t; 1046 } 1047 1048 private extern(D) static void thread_yield() @nogc nothrow 1049 { 1050 Thread.yield(); 1051 } 1052 1053 /// 1054 unittest 1055 { 1056 class DerivedThread : Thread 1057 { 1058 this() 1059 { 1060 super(&run); 1061 } 1062 1063 private: 1064 void run() 1065 { 1066 // Derived thread running. 1067 } 1068 } 1069 1070 void threadFunc() 1071 { 1072 // Composed thread running. 1073 } 1074 1075 // create and start instances of each type 1076 auto derived = new DerivedThread().start(); 1077 auto composed = new Thread(&threadFunc).start(); 1078 new Thread({ 1079 // Codes to run in the newly created thread. 1080 }).start(); 1081 } 1082 1083 unittest 1084 { 1085 int x = 0; 1086 1087 new Thread( 1088 { 1089 x++; 1090 }).start().join(); 1091 assert( x == 1 ); 1092 } 1093 1094 1095 unittest 1096 { 1097 enum MSG = "Test message."; 1098 string caughtMsg; 1099 1100 try 1101 { 1102 new Thread( 1103 function() 1104 { 1105 throw new Exception( MSG ); 1106 }).start().join(); 1107 assert( false, "Expected rethrown exception." ); 1108 } 1109 catch ( Throwable t ) 1110 { 1111 assert( t.msg == MSG ); 1112 } 1113 } 1114 1115 1116 unittest 1117 { 1118 // use >PAGESIZE to avoid stack overflow (e.g. in an syscall) 1119 auto thr = new Thread(function{}, 4096 + 1).start(); 1120 thr.join(); 1121 } 1122 1123 1124 unittest 1125 { 1126 import core.memory : GC; 1127 1128 auto t1 = new Thread({ 1129 foreach (_; 0 .. 20) 1130 ThreadBase.getAll; 1131 }).start; 1132 auto t2 = new Thread({ 1133 foreach (_; 0 .. 20) 1134 GC.collect; 1135 }).start; 1136 t1.join(); 1137 t2.join(); 1138 } 1139 1140 unittest 1141 { 1142 import core.sync.semaphore; 1143 auto sem = new Semaphore(); 1144 1145 auto t = new Thread( 1146 { 1147 sem.notify(); 1148 Thread.sleep(100.msecs); 1149 }).start(); 1150 1151 sem.wait(); // thread cannot be detached while being started 1152 thread_detachInstance(t); 1153 foreach (t2; Thread) 1154 assert(t !is t2); 1155 t.join(); 1156 } 1157 1158 unittest 1159 { 1160 // NOTE: This entire test is based on the assumption that no 1161 // memory is allocated after the child thread is 1162 // started. If an allocation happens, a collection could 1163 // trigger, which would cause the synchronization below 1164 // to cause a deadlock. 1165 // NOTE: DO NOT USE LOCKS IN CRITICAL REGIONS IN NORMAL CODE. 1166 1167 import core.sync.semaphore; 1168 1169 auto sema = new Semaphore(), 1170 semb = new Semaphore(); 1171 1172 auto thr = new Thread( 1173 { 1174 thread_enterCriticalRegion(); 1175 assert(thread_inCriticalRegion()); 1176 sema.notify(); 1177 1178 semb.wait(); 1179 assert(thread_inCriticalRegion()); 1180 1181 thread_exitCriticalRegion(); 1182 assert(!thread_inCriticalRegion()); 1183 sema.notify(); 1184 1185 semb.wait(); 1186 assert(!thread_inCriticalRegion()); 1187 }); 1188 1189 thr.start(); 1190 1191 sema.wait(); 1192 synchronized (ThreadBase.criticalRegionLock) 1193 assert(thr.m_isInCriticalRegion); 1194 semb.notify(); 1195 1196 sema.wait(); 1197 synchronized (ThreadBase.criticalRegionLock) 1198 assert(!thr.m_isInCriticalRegion); 1199 semb.notify(); 1200 1201 thr.join(); 1202 } 1203 1204 // https://issues.dlang.org/show_bug.cgi?id=22124 1205 unittest 1206 { 1207 Thread thread = new Thread({}); 1208 auto fun(Thread t, int x) 1209 { 1210 t.__ctor({x = 3;}); 1211 return t; 1212 } 1213 static assert(!__traits(compiles, () @nogc => fun(thread, 3) )); 1214 } 1215 1216 unittest 1217 { 1218 import core.sync.semaphore; 1219 1220 shared bool inCriticalRegion; 1221 auto sema = new Semaphore(), 1222 semb = new Semaphore(); 1223 1224 auto thr = new Thread( 1225 { 1226 thread_enterCriticalRegion(); 1227 inCriticalRegion = true; 1228 sema.notify(); 1229 semb.wait(); 1230 1231 Thread.sleep(dur!"msecs"(1)); 1232 inCriticalRegion = false; 1233 thread_exitCriticalRegion(); 1234 }); 1235 thr.start(); 1236 1237 sema.wait(); 1238 assert(inCriticalRegion); 1239 semb.notify(); 1240 1241 thread_suspendAll(); 1242 assert(!inCriticalRegion); 1243 thread_resumeAll(); 1244 } 1245 1246 /////////////////////////////////////////////////////////////////////////////// 1247 // GC Support Routines 1248 /////////////////////////////////////////////////////////////////////////////// 1249 1250 version (CoreDdoc) 1251 { 1252 /** 1253 * Instruct the thread module, when initialized, to use a different set of 1254 * signals besides SIGUSR1 and SIGUSR2 for suspension and resumption of threads. 1255 * This function should be called at most once, prior to thread_init(). 1256 * This function is Posix-only. 1257 */ 1258 extern (C) void thread_setGCSignals(int suspendSignalNo, int resumeSignalNo) nothrow @nogc 1259 { 1260 } 1261 } 1262 else version (Posix) 1263 { 1264 extern (C) void thread_setGCSignals(int suspendSignalNo, int resumeSignalNo) nothrow @nogc 1265 in 1266 { 1267 assert(suspendSignalNo != 0); 1268 assert(resumeSignalNo != 0); 1269 } 1270 out 1271 { 1272 assert(suspendSignalNumber != 0); 1273 assert(resumeSignalNumber != 0); 1274 } 1275 do 1276 { 1277 suspendSignalNumber = suspendSignalNo; 1278 resumeSignalNumber = resumeSignalNo; 1279 } 1280 } 1281 1282 version (Posix) 1283 { 1284 private __gshared int suspendSignalNumber = SIGUSR1; 1285 private __gshared int resumeSignalNumber = SIGUSR2; 1286 } 1287 1288 private extern (D) ThreadBase attachThread(ThreadBase _thisThread) @nogc nothrow 1289 { 1290 Thread thisThread = _thisThread.toThread(); 1291 1292 StackContext* thisContext = &thisThread.m_main; 1293 assert( thisContext == thisThread.m_curr ); 1294 1295 version (Windows) 1296 { 1297 thisThread.m_addr = GetCurrentThreadId(); 1298 thisThread.m_hndl = GetCurrentThreadHandle(); 1299 thisContext.bstack = getStackBottom(); 1300 thisContext.tstack = thisContext.bstack; 1301 } 1302 else version (Posix) 1303 { 1304 thisThread.m_addr = pthread_self(); 1305 thisContext.bstack = getStackBottom(); 1306 thisContext.tstack = thisContext.bstack; 1307 1308 atomicStore!(MemoryOrder.raw)(thisThread.toThread.m_isRunning, true); 1309 } 1310 thisThread.m_isDaemon = true; 1311 thisThread.tlsGCdataInit(); 1312 Thread.setThis( thisThread ); 1313 1314 version (Darwin) 1315 { 1316 thisThread.m_tmach = pthread_mach_thread_np( thisThread.m_addr ); 1317 assert( thisThread.m_tmach != thisThread.m_tmach.init ); 1318 } 1319 1320 Thread.add( thisThread, false ); 1321 Thread.add( thisContext ); 1322 if ( Thread.sm_main !is null ) 1323 multiThreadedFlag = true; 1324 return thisThread; 1325 } 1326 1327 /** 1328 * Registers the calling thread for use with the D Runtime. If this routine 1329 * is called for a thread which is already registered, no action is performed. 1330 * 1331 * NOTE: This routine does not run thread-local static constructors when called. 1332 * If full functionality as a D thread is desired, the following function 1333 * must be called after thread_attachThis: 1334 * 1335 * extern (C) void rt_moduleTlsCtor(); 1336 */ 1337 extern(C) Thread thread_attachThis() 1338 { 1339 return thread_attachThis_tpl!Thread(); 1340 } 1341 1342 1343 version (Windows) 1344 { 1345 // NOTE: These calls are not safe on Posix systems that use signals to 1346 // perform garbage collection. The suspendHandler uses getThis() 1347 // to get the thread handle so getThis() must be a simple call. 1348 // Mutexes can't safely be acquired inside signal handlers, and 1349 // even if they could, the mutex needed (Thread.slock) is held by 1350 // thread_suspendAll(). So in short, these routines will remain 1351 // Windows-specific. If they are truly needed elsewhere, the 1352 // suspendHandler will need a way to call a version of getThis() 1353 // that only does the TLS lookup without the fancy fallback stuff. 1354 1355 /// ditto 1356 extern (C) Thread thread_attachByAddr( ThreadID addr ) 1357 { 1358 return thread_attachByAddrB( addr, getThreadStackBottom( addr ) ); 1359 } 1360 1361 1362 /// ditto 1363 extern (C) Thread thread_attachByAddrB( ThreadID addr, void* bstack ) 1364 { 1365 GC.disable(); scope(exit) GC.enable(); 1366 1367 if (auto t = thread_findByAddr(addr).toThread) 1368 return t; 1369 1370 Thread thisThread = new Thread(); 1371 StackContext* thisContext = &thisThread.m_main; 1372 assert( thisContext == thisThread.m_curr ); 1373 1374 thisThread.m_addr = addr; 1375 thisContext.bstack = bstack; 1376 thisContext.tstack = thisContext.bstack; 1377 1378 thisThread.m_isDaemon = true; 1379 1380 if ( addr == GetCurrentThreadId() ) 1381 { 1382 thisThread.m_hndl = GetCurrentThreadHandle(); 1383 thisThread.tlsGCdataInit(); 1384 Thread.setThis( thisThread ); 1385 } 1386 else 1387 { 1388 thisThread.m_hndl = OpenThreadHandle( addr ); 1389 impersonate_thread(addr, 1390 { 1391 thisThread.tlsGCdataInit(); 1392 Thread.setThis( thisThread ); 1393 }); 1394 } 1395 1396 Thread.add( thisThread, false ); 1397 Thread.add( thisContext ); 1398 if ( Thread.sm_main !is null ) 1399 multiThreadedFlag = true; 1400 return thisThread; 1401 } 1402 } 1403 1404 1405 // Calls the given delegate, passing the current thread's stack pointer to it. 1406 package extern(D) void callWithStackShell(scope callWithStackShellDg fn) nothrow 1407 in (fn) 1408 { 1409 // The purpose of the 'shell' is to ensure all the registers get 1410 // put on the stack so they'll be scanned. We only need to push 1411 // the callee-save registers. 1412 void *sp = void; 1413 version (GNU) 1414 { 1415 // The generic solution below using a call to __builtin_unwind_init () 1416 // followed by an assignment to sp has two issues: 1417 // 1) On some archs it stores a huge amount of FP and Vector state which 1418 // is not the subject of the scan - and, indeed might produce false 1419 // hits. 1420 // 2) Even on archs like X86, where there are no callee-saved FPRs/VRs there 1421 // tend to be 'holes' in the frame allocations (to deal with alignment) which 1422 // also will contain random data which could produce false positives. 1423 // This solution stores only the integer callee-saved registers. 1424 version (X86) 1425 { 1426 void*[3] regs = void; 1427 asm pure nothrow @nogc 1428 { 1429 "movl %%ebx, %0" : "=m" (regs[0]); 1430 "movl %%esi, %0" : "=m" (regs[1]); 1431 "movl %%edi, %0" : "=m" (regs[2]); 1432 } 1433 sp = cast(void*)®s[0]; 1434 } 1435 else version (X86_64) 1436 { 1437 void*[5] regs = void; 1438 asm pure nothrow @nogc 1439 { 1440 "movq %%rbx, %0" : "=m" (regs[0]); 1441 "movq %%r12, %0" : "=m" (regs[1]); 1442 "movq %%r13, %0" : "=m" (regs[2]); 1443 "movq %%r14, %0" : "=m" (regs[3]); 1444 "movq %%r15, %0" : "=m" (regs[4]); 1445 } 1446 sp = cast(void*)®s[0]; 1447 } 1448 else version (PPC) 1449 { 1450 void*[19] regs = void; 1451 version (Darwin) 1452 enum regname = "r"; 1453 else 1454 enum regname = ""; 1455 static foreach (i; 0 .. regs.length) 1456 {{ 1457 enum int j = 13 + i; // source register 1458 asm pure nothrow @nogc 1459 { 1460 "stw "~regname~j.stringof~", %0" : "=m" (regs[i]); 1461 } 1462 }} 1463 sp = cast(void*)®s[0]; 1464 } 1465 else version (PPC64) 1466 { 1467 void*[19] regs = void; 1468 version (Darwin) 1469 enum regname = "r"; 1470 else 1471 enum regname = ""; 1472 static foreach (i; 0 .. regs.length) 1473 {{ 1474 enum int j = 13 + i; // source register 1475 asm pure nothrow @nogc 1476 { 1477 "std "~regname~j.stringof~", %0" : "=m" (regs[i]); 1478 } 1479 }} 1480 sp = cast(void*)®s[0]; 1481 } 1482 else version (AArch64) 1483 { 1484 // Callee-save registers, x19-x28 according to AAPCS64, section 1485 // 5.1.1. Include x29 fp because it optionally can be a callee 1486 // saved reg 1487 size_t[11] regs = void; 1488 // store the registers in pairs 1489 asm pure nothrow @nogc 1490 { 1491 "stp x19, x20, %0" : "=m" (regs[ 0]), "=m" (regs[1]); 1492 "stp x21, x22, %0" : "=m" (regs[ 2]), "=m" (regs[3]); 1493 "stp x23, x24, %0" : "=m" (regs[ 4]), "=m" (regs[5]); 1494 "stp x25, x26, %0" : "=m" (regs[ 6]), "=m" (regs[7]); 1495 "stp x27, x28, %0" : "=m" (regs[ 8]), "=m" (regs[9]); 1496 "str x29, %0" : "=m" (regs[10]); 1497 "mov %0, sp" : "=r" (sp); 1498 } 1499 } 1500 else version (ARM) 1501 { 1502 // Callee-save registers, according to AAPCS, section 5.1.1. 1503 // arm and thumb2 instructions 1504 size_t[8] regs = void; 1505 asm pure nothrow @nogc 1506 { 1507 "stm %0, {r4-r11}" : : "r" (regs.ptr) : "memory"; 1508 "mov %0, sp" : "=r" (sp); 1509 } 1510 } 1511 else 1512 { 1513 __builtin_unwind_init(); 1514 sp = &sp; 1515 } 1516 } 1517 else version (AsmX86_Posix) 1518 { 1519 size_t[3] regs = void; 1520 asm pure nothrow @nogc 1521 { 1522 mov [regs + 0 * 4], EBX; 1523 mov [regs + 1 * 4], ESI; 1524 mov [regs + 2 * 4], EDI; 1525 1526 mov sp[EBP], ESP; 1527 } 1528 } 1529 else version (AsmX86_Windows) 1530 { 1531 size_t[3] regs = void; 1532 asm pure nothrow @nogc 1533 { 1534 mov [regs + 0 * 4], EBX; 1535 mov [regs + 1 * 4], ESI; 1536 mov [regs + 2 * 4], EDI; 1537 1538 mov sp[EBP], ESP; 1539 } 1540 } 1541 else version (AsmX86_64_Posix) 1542 { 1543 size_t[5] regs = void; 1544 asm pure nothrow @nogc 1545 { 1546 mov [regs + 0 * 8], RBX; 1547 mov [regs + 1 * 8], R12; 1548 mov [regs + 2 * 8], R13; 1549 mov [regs + 3 * 8], R14; 1550 mov [regs + 4 * 8], R15; 1551 1552 mov sp[RBP], RSP; 1553 } 1554 } 1555 else version (AsmX86_64_Windows) 1556 { 1557 size_t[7] regs = void; 1558 asm pure nothrow @nogc 1559 { 1560 mov [regs + 0 * 8], RBX; 1561 mov [regs + 1 * 8], RSI; 1562 mov [regs + 2 * 8], RDI; 1563 mov [regs + 3 * 8], R12; 1564 mov [regs + 4 * 8], R13; 1565 mov [regs + 5 * 8], R14; 1566 mov [regs + 6 * 8], R15; 1567 1568 mov sp[RBP], RSP; 1569 } 1570 } 1571 else 1572 { 1573 static assert(false, "Architecture not supported."); 1574 } 1575 1576 fn(sp); 1577 } 1578 1579 version (Windows) 1580 private extern (D) void scanWindowsOnly(scope ScanAllThreadsTypeFn scan, ThreadBase _t) nothrow 1581 { 1582 auto t = _t.toThread; 1583 1584 scan( ScanType.stack, t.m_reg.ptr, t.m_reg.ptr + t.m_reg.length ); 1585 } 1586 1587 1588 /** 1589 * Returns the process ID of the calling process, which is guaranteed to be 1590 * unique on the system. This call is always successful. 1591 * 1592 * Example: 1593 * --- 1594 * writefln("Current process id: %s", getpid()); 1595 * --- 1596 */ 1597 version (Posix) 1598 { 1599 import core.sys.posix.unistd; 1600 1601 alias getpid = core.sys.posix.unistd.getpid; 1602 } 1603 else version (Windows) 1604 { 1605 alias getpid = core.sys.windows.winbase.GetCurrentProcessId; 1606 } 1607 1608 extern (C) @nogc nothrow 1609 { 1610 version (CRuntime_Glibc) version = PThread_Getattr_NP; 1611 version (CRuntime_Bionic) version = PThread_Getattr_NP; 1612 version (CRuntime_Musl) version = PThread_Getattr_NP; 1613 version (CRuntime_UClibc) version = PThread_Getattr_NP; 1614 1615 version (FreeBSD) version = PThread_Attr_Get_NP; 1616 version (NetBSD) version = PThread_Attr_Get_NP; 1617 version (DragonFlyBSD) version = PThread_Attr_Get_NP; 1618 1619 version (PThread_Getattr_NP) int pthread_getattr_np(pthread_t thread, pthread_attr_t* attr); 1620 version (PThread_Attr_Get_NP) int pthread_attr_get_np(pthread_t thread, pthread_attr_t* attr); 1621 version (Solaris) int thr_stksegment(stack_t* stk); 1622 version (OpenBSD) int pthread_stackseg_np(pthread_t thread, stack_t* sinfo); 1623 } 1624 1625 1626 package extern(D) void* getStackTop() nothrow @nogc 1627 { 1628 version (D_InlineAsm_X86) 1629 asm pure nothrow @nogc { naked; mov EAX, ESP; ret; } 1630 else version (D_InlineAsm_X86_64) 1631 asm pure nothrow @nogc { naked; mov RAX, RSP; ret; } 1632 else version (GNU) 1633 return __builtin_frame_address(0); 1634 else 1635 static assert(false, "Architecture not supported."); 1636 } 1637 1638 1639 package extern(D) void* getStackBottom() nothrow @nogc 1640 { 1641 version (Windows) 1642 { 1643 version (D_InlineAsm_X86) 1644 asm pure nothrow @nogc { naked; mov EAX, FS:4; ret; } 1645 else version (D_InlineAsm_X86_64) 1646 asm pure nothrow @nogc 1647 { naked; 1648 mov RAX, 8; 1649 mov RAX, GS:[RAX]; 1650 ret; 1651 } 1652 else version (GNU_InlineAsm) 1653 { 1654 void *bottom; 1655 1656 version (X86) 1657 asm pure nothrow @nogc { "movl %%fs:4, %0;" : "=r" (bottom); } 1658 else version (X86_64) 1659 asm pure nothrow @nogc { "movq %%gs:8, %0;" : "=r" (bottom); } 1660 else 1661 static assert(false, "Platform not supported."); 1662 1663 return bottom; 1664 } 1665 else 1666 static assert(false, "Architecture not supported."); 1667 } 1668 else version (Darwin) 1669 { 1670 import core.sys.darwin.pthread; 1671 return pthread_get_stackaddr_np(pthread_self()); 1672 } 1673 else version (PThread_Getattr_NP) 1674 { 1675 pthread_attr_t attr; 1676 void* addr; size_t size; 1677 1678 pthread_attr_init(&attr); 1679 pthread_getattr_np(pthread_self(), &attr); 1680 pthread_attr_getstack(&attr, &addr, &size); 1681 pthread_attr_destroy(&attr); 1682 static if (isStackGrowingDown) 1683 addr += size; 1684 return addr; 1685 } 1686 else version (PThread_Attr_Get_NP) 1687 { 1688 pthread_attr_t attr; 1689 void* addr; size_t size; 1690 1691 pthread_attr_init(&attr); 1692 pthread_attr_get_np(pthread_self(), &attr); 1693 pthread_attr_getstack(&attr, &addr, &size); 1694 pthread_attr_destroy(&attr); 1695 static if (isStackGrowingDown) 1696 addr += size; 1697 return addr; 1698 } 1699 else version (OpenBSD) 1700 { 1701 stack_t stk; 1702 1703 pthread_stackseg_np(pthread_self(), &stk); 1704 return stk.ss_sp; 1705 } 1706 else version (Solaris) 1707 { 1708 stack_t stk; 1709 1710 thr_stksegment(&stk); 1711 return stk.ss_sp; 1712 } 1713 else 1714 static assert(false, "Platform not supported."); 1715 } 1716 1717 /** 1718 * Suspend the specified thread and load stack and register information for 1719 * use by thread_scanAll. If the supplied thread is the calling thread, 1720 * stack and register information will be loaded but the thread will not 1721 * be suspended. If the suspend operation fails and the thread is not 1722 * running then it will be removed from the global thread list, otherwise 1723 * an exception will be thrown. 1724 * 1725 * Params: 1726 * t = The thread to suspend. 1727 * 1728 * Throws: 1729 * ThreadError if the suspend operation fails for a running thread. 1730 * Returns: 1731 * Whether the thread is now suspended (true) or terminated (false). 1732 */ 1733 private extern (D) bool suspend( Thread t ) nothrow @nogc 1734 { 1735 Duration waittime = dur!"usecs"(10); 1736 Lagain: 1737 if (!t.isRunning) 1738 { 1739 Thread.remove(t); 1740 return false; 1741 } 1742 else if (t.m_isInCriticalRegion) 1743 { 1744 Thread.criticalRegionLock.unlock_nothrow(); 1745 Thread.sleep(waittime); 1746 if (waittime < dur!"msecs"(10)) waittime *= 2; 1747 Thread.criticalRegionLock.lock_nothrow(); 1748 goto Lagain; 1749 } 1750 1751 version (Windows) 1752 { 1753 if ( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF ) 1754 { 1755 if ( !t.isRunning ) 1756 { 1757 Thread.remove( t ); 1758 return false; 1759 } 1760 onThreadError( "Unable to suspend thread" ); 1761 } 1762 1763 CONTEXT context = void; 1764 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; 1765 1766 if ( !GetThreadContext( t.m_hndl, &context ) ) 1767 onThreadError( "Unable to load thread context" ); 1768 version (X86) 1769 { 1770 if ( !t.m_lock ) 1771 t.m_curr.tstack = cast(void*) context.Esp; 1772 // eax,ebx,ecx,edx,edi,esi,ebp,esp 1773 t.m_reg[0] = context.Eax; 1774 t.m_reg[1] = context.Ebx; 1775 t.m_reg[2] = context.Ecx; 1776 t.m_reg[3] = context.Edx; 1777 t.m_reg[4] = context.Edi; 1778 t.m_reg[5] = context.Esi; 1779 t.m_reg[6] = context.Ebp; 1780 t.m_reg[7] = context.Esp; 1781 } 1782 else version (X86_64) 1783 { 1784 if ( !t.m_lock ) 1785 t.m_curr.tstack = cast(void*) context.Rsp; 1786 // rax,rbx,rcx,rdx,rdi,rsi,rbp,rsp 1787 t.m_reg[0] = context.Rax; 1788 t.m_reg[1] = context.Rbx; 1789 t.m_reg[2] = context.Rcx; 1790 t.m_reg[3] = context.Rdx; 1791 t.m_reg[4] = context.Rdi; 1792 t.m_reg[5] = context.Rsi; 1793 t.m_reg[6] = context.Rbp; 1794 t.m_reg[7] = context.Rsp; 1795 // r8,r9,r10,r11,r12,r13,r14,r15 1796 t.m_reg[8] = context.R8; 1797 t.m_reg[9] = context.R9; 1798 t.m_reg[10] = context.R10; 1799 t.m_reg[11] = context.R11; 1800 t.m_reg[12] = context.R12; 1801 t.m_reg[13] = context.R13; 1802 t.m_reg[14] = context.R14; 1803 t.m_reg[15] = context.R15; 1804 } 1805 else 1806 { 1807 static assert(false, "Architecture not supported." ); 1808 } 1809 } 1810 else version (Darwin) 1811 { 1812 if ( t.m_addr != pthread_self() && thread_suspend( t.m_tmach ) != KERN_SUCCESS ) 1813 { 1814 if ( !t.isRunning ) 1815 { 1816 Thread.remove( t ); 1817 return false; 1818 } 1819 onThreadError( "Unable to suspend thread" ); 1820 } 1821 1822 version (X86) 1823 { 1824 x86_thread_state32_t state = void; 1825 mach_msg_type_number_t count = x86_THREAD_STATE32_COUNT; 1826 1827 if ( thread_get_state( t.m_tmach, x86_THREAD_STATE32, &state, &count ) != KERN_SUCCESS ) 1828 onThreadError( "Unable to load thread state" ); 1829 if ( !t.m_lock ) 1830 t.m_curr.tstack = cast(void*) state.esp; 1831 // eax,ebx,ecx,edx,edi,esi,ebp,esp 1832 t.m_reg[0] = state.eax; 1833 t.m_reg[1] = state.ebx; 1834 t.m_reg[2] = state.ecx; 1835 t.m_reg[3] = state.edx; 1836 t.m_reg[4] = state.edi; 1837 t.m_reg[5] = state.esi; 1838 t.m_reg[6] = state.ebp; 1839 t.m_reg[7] = state.esp; 1840 } 1841 else version (X86_64) 1842 { 1843 x86_thread_state64_t state = void; 1844 mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT; 1845 1846 if ( thread_get_state( t.m_tmach, x86_THREAD_STATE64, &state, &count ) != KERN_SUCCESS ) 1847 onThreadError( "Unable to load thread state" ); 1848 if ( !t.m_lock ) 1849 t.m_curr.tstack = cast(void*) state.rsp; 1850 // rax,rbx,rcx,rdx,rdi,rsi,rbp,rsp 1851 t.m_reg[0] = state.rax; 1852 t.m_reg[1] = state.rbx; 1853 t.m_reg[2] = state.rcx; 1854 t.m_reg[3] = state.rdx; 1855 t.m_reg[4] = state.rdi; 1856 t.m_reg[5] = state.rsi; 1857 t.m_reg[6] = state.rbp; 1858 t.m_reg[7] = state.rsp; 1859 // r8,r9,r10,r11,r12,r13,r14,r15 1860 t.m_reg[8] = state.r8; 1861 t.m_reg[9] = state.r9; 1862 t.m_reg[10] = state.r10; 1863 t.m_reg[11] = state.r11; 1864 t.m_reg[12] = state.r12; 1865 t.m_reg[13] = state.r13; 1866 t.m_reg[14] = state.r14; 1867 t.m_reg[15] = state.r15; 1868 } 1869 else version (AArch64) 1870 { 1871 arm_thread_state64_t state = void; 1872 mach_msg_type_number_t count = ARM_THREAD_STATE64_COUNT; 1873 1874 if (thread_get_state(t.m_tmach, ARM_THREAD_STATE64, &state, &count) != KERN_SUCCESS) 1875 onThreadError("Unable to load thread state"); 1876 // TODO: ThreadException here recurses forever! Does it 1877 //still using onThreadError? 1878 //printf("state count %d (expect %d)\n", count ,ARM_THREAD_STATE64_COUNT); 1879 if (!t.m_lock) 1880 t.m_curr.tstack = cast(void*) state.sp; 1881 1882 t.m_reg[0..29] = state.x; // x0-x28 1883 t.m_reg[29] = state.fp; // x29 1884 t.m_reg[30] = state.lr; // x30 1885 t.m_reg[31] = state.sp; // x31 1886 t.m_reg[32] = state.pc; 1887 } 1888 else version (ARM) 1889 { 1890 arm_thread_state32_t state = void; 1891 mach_msg_type_number_t count = ARM_THREAD_STATE32_COUNT; 1892 1893 // Thought this would be ARM_THREAD_STATE32, but that fails. 1894 // Mystery 1895 if (thread_get_state(t.m_tmach, ARM_THREAD_STATE, &state, &count) != KERN_SUCCESS) 1896 onThreadError("Unable to load thread state"); 1897 // TODO: in past, ThreadException here recurses forever! Does it 1898 //still using onThreadError? 1899 //printf("state count %d (expect %d)\n", count ,ARM_THREAD_STATE32_COUNT); 1900 if (!t.m_lock) 1901 t.m_curr.tstack = cast(void*) state.sp; 1902 1903 t.m_reg[0..13] = state.r; // r0 - r13 1904 t.m_reg[13] = state.sp; 1905 t.m_reg[14] = state.lr; 1906 t.m_reg[15] = state.pc; 1907 } 1908 else version (PPC) 1909 { 1910 ppc_thread_state_t state = void; 1911 mach_msg_type_number_t count = PPC_THREAD_STATE_COUNT; 1912 1913 if (thread_get_state(t.m_tmach, PPC_THREAD_STATE, &state, &count) != KERN_SUCCESS) 1914 onThreadError("Unable to load thread state"); 1915 if (!t.m_lock) 1916 t.m_curr.tstack = cast(void*) state.r[1]; 1917 t.m_reg[] = state.r[]; 1918 } 1919 else version (PPC64) 1920 { 1921 ppc_thread_state64_t state = void; 1922 mach_msg_type_number_t count = PPC_THREAD_STATE64_COUNT; 1923 1924 if (thread_get_state(t.m_tmach, PPC_THREAD_STATE64, &state, &count) != KERN_SUCCESS) 1925 onThreadError("Unable to load thread state"); 1926 if (!t.m_lock) 1927 t.m_curr.tstack = cast(void*) state.r[1]; 1928 t.m_reg[] = state.r[]; 1929 } 1930 else 1931 { 1932 static assert(false, "Architecture not supported." ); 1933 } 1934 } 1935 else version (Posix) 1936 { 1937 if ( t.m_addr != pthread_self() ) 1938 { 1939 if ( pthread_kill( t.m_addr, suspendSignalNumber ) != 0 ) 1940 { 1941 if ( !t.isRunning ) 1942 { 1943 Thread.remove( t ); 1944 return false; 1945 } 1946 onThreadError( "Unable to suspend thread" ); 1947 } 1948 } 1949 else if ( !t.m_lock ) 1950 { 1951 t.m_curr.tstack = getStackTop(); 1952 } 1953 } 1954 return true; 1955 } 1956 1957 /** 1958 * Suspend all threads but the calling thread for "stop the world" garbage 1959 * collection runs. This function may be called multiple times, and must 1960 * be followed by a matching number of calls to thread_resumeAll before 1961 * processing is resumed. 1962 * 1963 * Throws: 1964 * ThreadError if the suspend operation fails for a running thread. 1965 */ 1966 extern (C) void thread_suspendAll() nothrow 1967 { 1968 // NOTE: We've got an odd chicken & egg problem here, because while the GC 1969 // is required to call thread_init before calling any other thread 1970 // routines, thread_init may allocate memory which could in turn 1971 // trigger a collection. Thus, thread_suspendAll, thread_scanAll, 1972 // and thread_resumeAll must be callable before thread_init 1973 // completes, with the assumption that no other GC memory has yet 1974 // been allocated by the system, and thus there is no risk of losing 1975 // data if the global thread list is empty. The check of 1976 // Thread.sm_tbeg below is done to ensure thread_init has completed, 1977 // and therefore that calling Thread.getThis will not result in an 1978 // error. For the short time when Thread.sm_tbeg is null, there is 1979 // no reason not to simply call the multithreaded code below, with 1980 // the expectation that the foreach loop will never be entered. 1981 if ( !multiThreadedFlag && Thread.sm_tbeg ) 1982 { 1983 if ( ++suspendDepth == 1 ) 1984 suspend( Thread.getThis() ); 1985 1986 return; 1987 } 1988 1989 Thread.slock.lock_nothrow(); 1990 { 1991 if ( ++suspendDepth > 1 ) 1992 return; 1993 1994 Thread.criticalRegionLock.lock_nothrow(); 1995 scope (exit) Thread.criticalRegionLock.unlock_nothrow(); 1996 size_t cnt; 1997 Thread t = ThreadBase.sm_tbeg.toThread; 1998 while (t) 1999 { 2000 auto tn = t.next.toThread; 2001 if (suspend(t)) 2002 ++cnt; 2003 t = tn; 2004 } 2005 2006 version (Darwin) 2007 {} 2008 else version (Posix) 2009 { 2010 // subtract own thread 2011 assert(cnt >= 1); 2012 --cnt; 2013 // wait for semaphore notifications 2014 for (; cnt; --cnt) 2015 { 2016 while (sem_wait(&suspendCount) != 0) 2017 { 2018 if (errno != EINTR) 2019 onThreadError("Unable to wait for semaphore"); 2020 errno = 0; 2021 } 2022 } 2023 } 2024 } 2025 } 2026 2027 /** 2028 * Resume the specified thread and unload stack and register information. 2029 * If the supplied thread is the calling thread, stack and register 2030 * information will be unloaded but the thread will not be resumed. If 2031 * the resume operation fails and the thread is not running then it will 2032 * be removed from the global thread list, otherwise an exception will be 2033 * thrown. 2034 * 2035 * Params: 2036 * t = The thread to resume. 2037 * 2038 * Throws: 2039 * ThreadError if the resume fails for a running thread. 2040 */ 2041 private extern (D) void resume(ThreadBase _t) nothrow @nogc 2042 { 2043 Thread t = _t.toThread; 2044 2045 version (Windows) 2046 { 2047 if ( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF ) 2048 { 2049 if ( !t.isRunning ) 2050 { 2051 Thread.remove( t ); 2052 return; 2053 } 2054 onThreadError( "Unable to resume thread" ); 2055 } 2056 2057 if ( !t.m_lock ) 2058 t.m_curr.tstack = t.m_curr.bstack; 2059 t.m_reg[0 .. $] = 0; 2060 } 2061 else version (Darwin) 2062 { 2063 if ( t.m_addr != pthread_self() && thread_resume( t.m_tmach ) != KERN_SUCCESS ) 2064 { 2065 if ( !t.isRunning ) 2066 { 2067 Thread.remove( t ); 2068 return; 2069 } 2070 onThreadError( "Unable to resume thread" ); 2071 } 2072 2073 if ( !t.m_lock ) 2074 t.m_curr.tstack = t.m_curr.bstack; 2075 t.m_reg[0 .. $] = 0; 2076 } 2077 else version (Posix) 2078 { 2079 if ( t.m_addr != pthread_self() ) 2080 { 2081 if ( pthread_kill( t.m_addr, resumeSignalNumber ) != 0 ) 2082 { 2083 if ( !t.isRunning ) 2084 { 2085 Thread.remove( t ); 2086 return; 2087 } 2088 onThreadError( "Unable to resume thread" ); 2089 } 2090 } 2091 else if ( !t.m_lock ) 2092 { 2093 t.m_curr.tstack = t.m_curr.bstack; 2094 } 2095 } 2096 } 2097 2098 2099 /** 2100 * Initializes the thread module. This function must be called by the 2101 * garbage collector on startup and before any other thread routines 2102 * are called. 2103 */ 2104 extern (C) void thread_init() @nogc 2105 { 2106 // NOTE: If thread_init itself performs any allocations then the thread 2107 // routines reserved for garbage collector use may be called while 2108 // thread_init is being processed. However, since no memory should 2109 // exist to be scanned at this point, it is sufficient for these 2110 // functions to detect the condition and return immediately. 2111 2112 initLowlevelThreads(); 2113 Thread.initLocks(); 2114 2115 // The Android VM runtime intercepts SIGUSR1 and apparently doesn't allow 2116 // its signal handler to run, so swap the two signals on Android, since 2117 // thread_resumeHandler does nothing. 2118 version (Android) thread_setGCSignals(SIGUSR2, SIGUSR1); 2119 2120 version (Darwin) 2121 { 2122 // thread id different in forked child process 2123 static extern(C) void initChildAfterFork() 2124 { 2125 auto thisThread = Thread.getThis(); 2126 thisThread.m_addr = pthread_self(); 2127 assert( thisThread.m_addr != thisThread.m_addr.init ); 2128 thisThread.m_tmach = pthread_mach_thread_np( thisThread.m_addr ); 2129 assert( thisThread.m_tmach != thisThread.m_tmach.init ); 2130 } 2131 pthread_atfork(null, null, &initChildAfterFork); 2132 } 2133 else version (Posix) 2134 { 2135 int status; 2136 sigaction_t suspend = void; 2137 sigaction_t resume = void; 2138 2139 // This is a quick way to zero-initialize the structs without using 2140 // memset or creating a link dependency on their static initializer. 2141 (cast(byte*) &suspend)[0 .. sigaction_t.sizeof] = 0; 2142 (cast(byte*) &resume)[0 .. sigaction_t.sizeof] = 0; 2143 2144 // NOTE: SA_RESTART indicates that system calls should restart if they 2145 // are interrupted by a signal, but this is not available on all 2146 // Posix systems, even those that support multithreading. 2147 static if ( __traits( compiles, SA_RESTART ) ) 2148 suspend.sa_flags = SA_RESTART; 2149 2150 suspend.sa_handler = &thread_suspendHandler; 2151 // NOTE: We want to ignore all signals while in this handler, so fill 2152 // sa_mask to indicate this. 2153 status = sigfillset( &suspend.sa_mask ); 2154 assert( status == 0 ); 2155 2156 // NOTE: Since resumeSignalNumber should only be issued for threads within the 2157 // suspend handler, we don't want this signal to trigger a 2158 // restart. 2159 resume.sa_flags = 0; 2160 resume.sa_handler = &thread_resumeHandler; 2161 // NOTE: We want to ignore all signals while in this handler, so fill 2162 // sa_mask to indicate this. 2163 status = sigfillset( &resume.sa_mask ); 2164 assert( status == 0 ); 2165 2166 status = sigaction( suspendSignalNumber, &suspend, null ); 2167 assert( status == 0 ); 2168 2169 status = sigaction( resumeSignalNumber, &resume, null ); 2170 assert( status == 0 ); 2171 2172 status = sem_init( &suspendCount, 0, 0 ); 2173 assert( status == 0 ); 2174 } 2175 _mainThreadStore[] = __traits(initSymbol, Thread)[]; 2176 Thread.sm_main = attachThread((cast(Thread)_mainThreadStore.ptr).__ctor()); 2177 } 2178 2179 private alias MainThreadStore = void[__traits(classInstanceSize, Thread)]; 2180 package __gshared align(Thread.alignof) MainThreadStore _mainThreadStore; 2181 2182 /** 2183 * Terminates the thread module. No other thread routine may be called 2184 * afterwards. 2185 */ 2186 extern (C) void thread_term() @nogc 2187 { 2188 thread_term_tpl!(Thread)(_mainThreadStore); 2189 } 2190 2191 2192 /////////////////////////////////////////////////////////////////////////////// 2193 // Thread Entry Point and Signal Handlers 2194 /////////////////////////////////////////////////////////////////////////////// 2195 2196 2197 version (Windows) 2198 { 2199 private 2200 { 2201 // 2202 // Entry point for Windows threads 2203 // 2204 extern (Windows) uint thread_entryPoint( void* arg ) nothrow 2205 { 2206 Thread obj = cast(Thread) arg; 2207 assert( obj ); 2208 2209 obj.initDataStorage(); 2210 2211 Thread.setThis(obj); 2212 Thread.add(obj); 2213 scope (exit) 2214 { 2215 Thread.remove(obj); 2216 obj.destroyDataStorage(); 2217 } 2218 Thread.add(&obj.m_main); 2219 2220 // NOTE: No GC allocations may occur until the stack pointers have 2221 // been set and Thread.getThis returns a valid reference to 2222 // this thread object (this latter condition is not strictly 2223 // necessary on Windows but it should be followed for the 2224 // sake of consistency). 2225 2226 // TODO: Consider putting an auto exception object here (using 2227 // alloca) forOutOfMemoryError plus something to track 2228 // whether an exception is in-flight? 2229 2230 void append( Throwable t ) 2231 { 2232 obj.m_unhandled = Throwable.chainTogether(obj.m_unhandled, t); 2233 } 2234 2235 version (D_InlineAsm_X86) 2236 { 2237 asm nothrow @nogc { fninit; } 2238 } 2239 2240 try 2241 { 2242 rt_moduleTlsCtor(); 2243 try 2244 { 2245 obj.run(); 2246 } 2247 catch ( Throwable t ) 2248 { 2249 append( t ); 2250 } 2251 rt_moduleTlsDtor(); 2252 } 2253 catch ( Throwable t ) 2254 { 2255 append( t ); 2256 } 2257 return 0; 2258 } 2259 2260 2261 HANDLE GetCurrentThreadHandle() nothrow @nogc 2262 { 2263 const uint DUPLICATE_SAME_ACCESS = 0x00000002; 2264 2265 HANDLE curr = GetCurrentThread(), 2266 proc = GetCurrentProcess(), 2267 hndl; 2268 2269 DuplicateHandle( proc, curr, proc, &hndl, 0, TRUE, DUPLICATE_SAME_ACCESS ); 2270 return hndl; 2271 } 2272 } 2273 } 2274 else version (Posix) 2275 { 2276 private 2277 { 2278 import core.stdc.errno; 2279 import core.sys.posix.semaphore; 2280 import core.sys.posix.stdlib; // for malloc, valloc, free, atexit 2281 import core.sys.posix.pthread; 2282 import core.sys.posix.signal; 2283 import core.sys.posix.time; 2284 2285 version (Darwin) 2286 { 2287 import core.sys.darwin.mach.thread_act; 2288 import core.sys.darwin.pthread : pthread_mach_thread_np; 2289 } 2290 2291 // 2292 // Entry point for POSIX threads 2293 // 2294 extern (C) void* thread_entryPoint( void* arg ) nothrow 2295 { 2296 version (Shared) 2297 { 2298 Thread obj = cast(Thread)(cast(void**)arg)[0]; 2299 auto loadedLibraries = (cast(void**)arg)[1]; 2300 .free(arg); 2301 } 2302 else 2303 { 2304 Thread obj = cast(Thread)arg; 2305 } 2306 assert( obj ); 2307 2308 // loadedLibraries need to be inherited from parent thread 2309 // before initilizing GC for TLS (rt_tlsgc_init) 2310 version (GNUShared) 2311 { 2312 externDFunc!("gcc.sections.inheritLoadedLibraries", 2313 void function(void*) @nogc nothrow)(loadedLibraries); 2314 } 2315 else version (Shared) 2316 { 2317 externDFunc!("rt.sections_elf_shared.inheritLoadedLibraries", 2318 void function(void*) @nogc nothrow)(loadedLibraries); 2319 } 2320 2321 obj.initDataStorage(); 2322 2323 atomicStore!(MemoryOrder.raw)(obj.m_isRunning, true); 2324 Thread.setThis(obj); // allocates lazy TLS (see Issue 11981) 2325 Thread.add(obj); // can only receive signals from here on 2326 scope (exit) 2327 { 2328 Thread.remove(obj); 2329 atomicStore!(MemoryOrder.raw)(obj.m_isRunning, false); 2330 obj.destroyDataStorage(); 2331 } 2332 Thread.add(&obj.m_main); 2333 2334 static extern (C) void thread_cleanupHandler( void* arg ) nothrow @nogc 2335 { 2336 Thread obj = cast(Thread) arg; 2337 assert( obj ); 2338 2339 // NOTE: If the thread terminated abnormally, just set it as 2340 // not running and let thread_suspendAll remove it from 2341 // the thread list. This is safer and is consistent 2342 // with the Windows thread code. 2343 atomicStore!(MemoryOrder.raw)(obj.m_isRunning,false); 2344 } 2345 2346 // NOTE: Using void to skip the initialization here relies on 2347 // knowledge of how pthread_cleanup is implemented. It may 2348 // not be appropriate for all platforms. However, it does 2349 // avoid the need to link the pthread module. If any 2350 // implementation actually requires default initialization 2351 // then pthread_cleanup should be restructured to maintain 2352 // the current lack of a link dependency. 2353 static if ( __traits( compiles, pthread_cleanup ) ) 2354 { 2355 pthread_cleanup cleanup = void; 2356 cleanup.push( &thread_cleanupHandler, cast(void*) obj ); 2357 } 2358 else static if ( __traits( compiles, pthread_cleanup_push ) ) 2359 { 2360 pthread_cleanup_push( &thread_cleanupHandler, cast(void*) obj ); 2361 } 2362 else 2363 { 2364 static assert( false, "Platform not supported." ); 2365 } 2366 2367 // NOTE: No GC allocations may occur until the stack pointers have 2368 // been set and Thread.getThis returns a valid reference to 2369 // this thread object (this latter condition is not strictly 2370 // necessary on Windows but it should be followed for the 2371 // sake of consistency). 2372 2373 // TODO: Consider putting an auto exception object here (using 2374 // alloca) forOutOfMemoryError plus something to track 2375 // whether an exception is in-flight? 2376 2377 void append( Throwable t ) 2378 { 2379 obj.m_unhandled = Throwable.chainTogether(obj.m_unhandled, t); 2380 } 2381 try 2382 { 2383 rt_moduleTlsCtor(); 2384 try 2385 { 2386 obj.run(); 2387 } 2388 catch ( Throwable t ) 2389 { 2390 append( t ); 2391 } 2392 rt_moduleTlsDtor(); 2393 version (GNUShared) 2394 { 2395 externDFunc!("gcc.sections.cleanupLoadedLibraries", 2396 void function() @nogc nothrow)(); 2397 } 2398 else version (Shared) 2399 { 2400 externDFunc!("rt.sections_elf_shared.cleanupLoadedLibraries", 2401 void function() @nogc nothrow)(); 2402 } 2403 } 2404 catch ( Throwable t ) 2405 { 2406 append( t ); 2407 } 2408 2409 // NOTE: Normal cleanup is handled by scope(exit). 2410 2411 static if ( __traits( compiles, pthread_cleanup ) ) 2412 { 2413 cleanup.pop( 0 ); 2414 } 2415 else static if ( __traits( compiles, pthread_cleanup_push ) ) 2416 { 2417 pthread_cleanup_pop( 0 ); 2418 } 2419 2420 return null; 2421 } 2422 2423 2424 // 2425 // Used to track the number of suspended threads 2426 // 2427 __gshared sem_t suspendCount; 2428 2429 2430 extern (C) void thread_suspendHandler( int sig ) nothrow 2431 in 2432 { 2433 assert( sig == suspendSignalNumber ); 2434 } 2435 do 2436 { 2437 void op(void* sp) nothrow 2438 { 2439 // NOTE: Since registers are being pushed and popped from the 2440 // stack, any other stack data used by this function should 2441 // be gone before the stack cleanup code is called below. 2442 Thread obj = Thread.getThis(); 2443 assert(obj !is null); 2444 2445 if ( !obj.m_lock ) 2446 { 2447 obj.m_curr.tstack = getStackTop(); 2448 } 2449 2450 sigset_t sigres = void; 2451 int status; 2452 2453 status = sigfillset( &sigres ); 2454 assert( status == 0 ); 2455 2456 status = sigdelset( &sigres, resumeSignalNumber ); 2457 assert( status == 0 ); 2458 2459 status = sem_post( &suspendCount ); 2460 assert( status == 0 ); 2461 2462 sigsuspend( &sigres ); 2463 2464 if ( !obj.m_lock ) 2465 { 2466 obj.m_curr.tstack = obj.m_curr.bstack; 2467 } 2468 } 2469 callWithStackShell(&op); 2470 } 2471 2472 2473 extern (C) void thread_resumeHandler( int sig ) nothrow 2474 in 2475 { 2476 assert( sig == resumeSignalNumber ); 2477 } 2478 do 2479 { 2480 2481 } 2482 } 2483 } 2484 else 2485 { 2486 // NOTE: This is the only place threading versions are checked. If a new 2487 // version is added, the module code will need to be searched for 2488 // places where version-specific code may be required. This can be 2489 // easily accomlished by searching for 'Windows' or 'Posix'. 2490 static assert( false, "Unknown threading implementation." ); 2491 } 2492 2493 // 2494 // exposed by compiler runtime 2495 // 2496 extern (C) void rt_moduleTlsCtor(); 2497 extern (C) void rt_moduleTlsDtor(); 2498 2499 2500 // regression test for Issue 13416 2501 version (FreeBSD) unittest 2502 { 2503 static void loop() 2504 { 2505 pthread_attr_t attr; 2506 pthread_attr_init(&attr); 2507 auto thr = pthread_self(); 2508 foreach (i; 0 .. 50) 2509 pthread_attr_get_np(thr, &attr); 2510 pthread_attr_destroy(&attr); 2511 } 2512 2513 auto thr = new Thread(&loop).start(); 2514 foreach (i; 0 .. 50) 2515 { 2516 thread_suspendAll(); 2517 thread_resumeAll(); 2518 } 2519 thr.join(); 2520 } 2521 2522 version (DragonFlyBSD) unittest 2523 { 2524 static void loop() 2525 { 2526 pthread_attr_t attr; 2527 pthread_attr_init(&attr); 2528 auto thr = pthread_self(); 2529 foreach (i; 0 .. 50) 2530 pthread_attr_get_np(thr, &attr); 2531 pthread_attr_destroy(&attr); 2532 } 2533 2534 auto thr = new Thread(&loop).start(); 2535 foreach (i; 0 .. 50) 2536 { 2537 thread_suspendAll(); 2538 thread_resumeAll(); 2539 } 2540 thr.join(); 2541 } 2542 2543 2544 /////////////////////////////////////////////////////////////////////////////// 2545 // lowlovel threading support 2546 /////////////////////////////////////////////////////////////////////////////// 2547 2548 private 2549 { 2550 version (Windows): 2551 // If the runtime is dynamically loaded as a DLL, there is a problem with 2552 // threads still running when the DLL is supposed to be unloaded: 2553 // 2554 // - with the VC runtime starting with VS2015 (i.e. using the Universal CRT) 2555 // a thread created with _beginthreadex increments the DLL reference count 2556 // and decrements it when done, so that the DLL is no longer unloaded unless 2557 // all the threads have terminated. With the DLL reference count held up 2558 // by a thread that is only stopped by a signal from a static destructor or 2559 // the termination of the runtime will cause the DLL to never be unloaded. 2560 // 2561 // - with the DigitalMars runtime and VC runtime up to VS2013, the thread 2562 // continues to run, but crashes once the DLL is unloaded from memory as 2563 // the code memory is no longer accessible. Stopping the threads is not possible 2564 // from within the runtime termination as it is invoked from 2565 // DllMain(DLL_PROCESS_DETACH) holding a lock that prevents threads from 2566 // terminating. 2567 // 2568 // Solution: start a watchdog thread that keeps the DLL reference count above 0 and 2569 // checks it periodically. If it is equal to 1 (plus the number of started threads), no 2570 // external references to the DLL exist anymore, threads can be stopped 2571 // and runtime termination and DLL unload can be invoked via FreeLibraryAndExitThread. 2572 // Note: runtime termination is then performed by a different thread than at startup. 2573 // 2574 // Note: if the DLL is never unloaded, process termination kills all threads 2575 // and signals their handles before unconditionally calling DllMain(DLL_PROCESS_DETACH). 2576 2577 import core.sys.windows.winbase : FreeLibraryAndExitThread, GetModuleHandleExW, 2578 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT; 2579 import core.sys.windows.windef : HMODULE; 2580 import core.sys.windows.dll : dll_getRefCount; 2581 2582 version (CRuntime_Microsoft) 2583 extern(C) extern __gshared ubyte msvcUsesUCRT; // from rt/msvc.d 2584 2585 /// set during termination of a DLL on Windows, i.e. while executing DllMain(DLL_PROCESS_DETACH) 2586 public __gshared bool thread_DLLProcessDetaching; 2587 2588 __gshared HMODULE ll_dllModule; 2589 __gshared ThreadID ll_dllMonitorThread; 2590 2591 int ll_countLowLevelThreadsWithDLLUnloadCallback() nothrow 2592 { 2593 lowlevelLock.lock_nothrow(); 2594 scope(exit) lowlevelLock.unlock_nothrow(); 2595 2596 int cnt = 0; 2597 foreach (i; 0 .. ll_nThreads) 2598 if (ll_pThreads[i].cbDllUnload) 2599 cnt++; 2600 return cnt; 2601 } 2602 2603 bool ll_dllHasExternalReferences() nothrow 2604 { 2605 version (CRuntime_DigitalMars) 2606 enum internalReferences = 1; // only the watchdog thread 2607 else 2608 int internalReferences = msvcUsesUCRT ? 1 + ll_countLowLevelThreadsWithDLLUnloadCallback() : 1; 2609 2610 int refcnt = dll_getRefCount(ll_dllModule); 2611 return refcnt > internalReferences; 2612 } 2613 2614 private void monitorDLLRefCnt() nothrow 2615 { 2616 // this thread keeps the DLL alive until all external references are gone 2617 while (ll_dllHasExternalReferences()) 2618 { 2619 Thread.sleep(100.msecs); 2620 } 2621 2622 // the current thread will be terminated below 2623 ll_removeThread(GetCurrentThreadId()); 2624 2625 for (;;) 2626 { 2627 ThreadID tid; 2628 void delegate() nothrow cbDllUnload; 2629 { 2630 lowlevelLock.lock_nothrow(); 2631 scope(exit) lowlevelLock.unlock_nothrow(); 2632 2633 foreach (i; 0 .. ll_nThreads) 2634 if (ll_pThreads[i].cbDllUnload) 2635 { 2636 cbDllUnload = ll_pThreads[i].cbDllUnload; 2637 tid = ll_pThreads[0].tid; 2638 } 2639 } 2640 if (!cbDllUnload) 2641 break; 2642 cbDllUnload(); 2643 assert(!findLowLevelThread(tid)); 2644 } 2645 2646 FreeLibraryAndExitThread(ll_dllModule, 0); 2647 } 2648 2649 int ll_getDLLRefCount() nothrow @nogc 2650 { 2651 if (!ll_dllModule && 2652 !GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, 2653 cast(const(wchar)*) &ll_getDLLRefCount, &ll_dllModule)) 2654 return -1; 2655 return dll_getRefCount(ll_dllModule); 2656 } 2657 2658 bool ll_startDLLUnloadThread() nothrow @nogc 2659 { 2660 int refcnt = ll_getDLLRefCount(); 2661 if (refcnt < 0) 2662 return false; // not a dynamically loaded DLL 2663 2664 if (ll_dllMonitorThread !is ThreadID.init) 2665 return true; 2666 2667 // if a thread is created from a DLL, the MS runtime (starting with VC2015) increments the DLL reference count 2668 // to avoid the DLL being unloaded while the thread is still running. Mimick this behavior here for all 2669 // runtimes not doing this 2670 version (CRuntime_DigitalMars) 2671 enum needRef = true; 2672 else 2673 bool needRef = !msvcUsesUCRT; 2674 2675 if (needRef) 2676 { 2677 HMODULE hmod; 2678 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, cast(const(wchar)*) &ll_getDLLRefCount, &hmod); 2679 } 2680 2681 ll_dllMonitorThread = createLowLevelThread(() { monitorDLLRefCnt(); }); 2682 return ll_dllMonitorThread != ThreadID.init; 2683 } 2684 } 2685 2686 /** 2687 * Create a thread not under control of the runtime, i.e. TLS module constructors are 2688 * not run and the GC does not suspend it during a collection. 2689 * 2690 * Params: 2691 * dg = delegate to execute in the created thread. 2692 * stacksize = size of the stack of the created thread. The default of 0 will select the 2693 * platform-specific default size. 2694 * cbDllUnload = Windows only: if running in a dynamically loaded DLL, this delegate will be called 2695 * if the DLL is supposed to be unloaded, but the thread is still running. 2696 * The thread must be terminated via `joinLowLevelThread` by the callback. 2697 * 2698 * Returns: the platform specific thread ID of the new thread. If an error occurs, `ThreadID.init` 2699 * is returned. 2700 */ 2701 ThreadID createLowLevelThread(void delegate() nothrow dg, uint stacksize = 0, 2702 void delegate() nothrow cbDllUnload = null) nothrow @nogc 2703 { 2704 void delegate() nothrow* context = cast(void delegate() nothrow*)malloc(dg.sizeof); 2705 *context = dg; 2706 2707 ThreadID tid; 2708 version (Windows) 2709 { 2710 // the thread won't start until after the DLL is unloaded 2711 if (thread_DLLProcessDetaching) 2712 return ThreadID.init; 2713 2714 static extern (Windows) uint thread_lowlevelEntry(void* ctx) nothrow 2715 { 2716 auto dg = *cast(void delegate() nothrow*)ctx; 2717 free(ctx); 2718 2719 dg(); 2720 ll_removeThread(GetCurrentThreadId()); 2721 return 0; 2722 } 2723 2724 // see Thread.start() for why thread is created in suspended state 2725 HANDLE hThread = cast(HANDLE) _beginthreadex(null, stacksize, &thread_lowlevelEntry, 2726 context, CREATE_SUSPENDED, &tid); 2727 if (!hThread) 2728 return ThreadID.init; 2729 } 2730 2731 lowlevelLock.lock_nothrow(); 2732 scope(exit) lowlevelLock.unlock_nothrow(); 2733 2734 ll_nThreads++; 2735 ll_pThreads = cast(ll_ThreadData*)realloc(ll_pThreads, ll_ThreadData.sizeof * ll_nThreads); 2736 2737 version (Windows) 2738 { 2739 ll_pThreads[ll_nThreads - 1].tid = tid; 2740 ll_pThreads[ll_nThreads - 1].cbDllUnload = cbDllUnload; 2741 if (ResumeThread(hThread) == -1) 2742 onThreadError("Error resuming thread"); 2743 CloseHandle(hThread); 2744 2745 if (cbDllUnload) 2746 ll_startDLLUnloadThread(); 2747 } 2748 else version (Posix) 2749 { 2750 static extern (C) void* thread_lowlevelEntry(void* ctx) nothrow 2751 { 2752 auto dg = *cast(void delegate() nothrow*)ctx; 2753 free(ctx); 2754 2755 dg(); 2756 ll_removeThread(pthread_self()); 2757 return null; 2758 } 2759 2760 size_t stksz = adjustStackSize(stacksize); 2761 2762 pthread_attr_t attr; 2763 2764 int rc; 2765 if ((rc = pthread_attr_init(&attr)) != 0) 2766 return ThreadID.init; 2767 if (stksz && (rc = pthread_attr_setstacksize(&attr, stksz)) != 0) 2768 return ThreadID.init; 2769 if ((rc = pthread_create(&tid, &attr, &thread_lowlevelEntry, context)) != 0) 2770 return ThreadID.init; 2771 if ((rc = pthread_attr_destroy(&attr)) != 0) 2772 return ThreadID.init; 2773 2774 ll_pThreads[ll_nThreads - 1].tid = tid; 2775 } 2776 return tid; 2777 } 2778 2779 /** 2780 * Wait for a thread created with `createLowLevelThread` to terminate. 2781 * 2782 * Note: In a Windows DLL, if this function is called via DllMain with 2783 * argument DLL_PROCESS_DETACH, the thread is terminated forcefully 2784 * without proper cleanup as a deadlock would happen otherwise. 2785 * 2786 * Params: 2787 * tid = the thread ID returned by `createLowLevelThread`. 2788 */ 2789 void joinLowLevelThread(ThreadID tid) nothrow @nogc 2790 { 2791 version (Windows) 2792 { 2793 HANDLE handle = OpenThreadHandle(tid); 2794 if (!handle) 2795 return; 2796 2797 if (thread_DLLProcessDetaching) 2798 { 2799 // When being called from DllMain/DLL_DETACH_PROCESS, threads cannot stop 2800 // due to the loader lock being held by the current thread. 2801 // On the other hand, the thread must not continue to run as it will crash 2802 // if the DLL is unloaded. The best guess is to terminate it immediately. 2803 TerminateThread(handle, 1); 2804 WaitForSingleObject(handle, 10); // give it some time to terminate, but don't wait indefinitely 2805 } 2806 else 2807 WaitForSingleObject(handle, INFINITE); 2808 CloseHandle(handle); 2809 } 2810 else version (Posix) 2811 { 2812 if (pthread_join(tid, null) != 0) 2813 onThreadError("Unable to join thread"); 2814 } 2815 } 2816 2817 nothrow @nogc unittest 2818 { 2819 struct TaskWithContect 2820 { 2821 shared int n = 0; 2822 void run() nothrow 2823 { 2824 n.atomicOp!"+="(1); 2825 } 2826 } 2827 TaskWithContect task; 2828 2829 ThreadID[8] tids; 2830 for (int i = 0; i < tids.length; i++) 2831 { 2832 tids[i] = createLowLevelThread(&task.run); 2833 assert(tids[i] != ThreadID.init); 2834 } 2835 2836 for (int i = 0; i < tids.length; i++) 2837 joinLowLevelThread(tids[i]); 2838 2839 assert(task.n == tids.length); 2840 } 2841 2842 version (Posix) 2843 private size_t adjustStackSize(size_t sz) nothrow @nogc 2844 { 2845 if (sz == 0) 2846 return 0; 2847 2848 // stack size must be at least PTHREAD_STACK_MIN for most platforms. 2849 if (PTHREAD_STACK_MIN > sz) 2850 sz = PTHREAD_STACK_MIN; 2851 2852 version (CRuntime_Glibc) 2853 { 2854 // On glibc, TLS uses the top of the stack, so add its size to the requested size 2855 version (GNU) 2856 { 2857 sz += externDFunc!("gcc.sections.elf.sizeOfTLS", 2858 size_t function() @nogc nothrow)(); 2859 } 2860 else 2861 { 2862 sz += externDFunc!("rt.sections_elf_shared.sizeOfTLS", 2863 size_t function() @nogc nothrow)(); 2864 } 2865 } 2866 2867 // stack size must be a multiple of PAGESIZE 2868 sz = ((sz + PAGESIZE - 1) & ~(PAGESIZE - 1)); 2869 2870 return sz; 2871 } 2872