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