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