d: Merge dmd. druntime e770945277, phobos 6d6e0b9b9
[official-gcc.git] / libphobos / libdruntime / core / thread / osthread.d
blob93902439fbfd60479002e399c2d52d1a8957a415
1 /**
2 * The osthread module provides low-level, OS-dependent code
3 * for thread creation and management.
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)
13 /* NOTE: This file has been patched from the original DMD distribution to
14 * work with the GDC compiler.
16 module core.thread.osthread;
18 import core.thread.threadbase;
19 import core.thread.context;
20 import core.thread.types;
21 import core.atomic;
22 import core.memory : GC, pageSize;
23 import core.time;
24 import core.exception : onOutOfMemoryError;
25 import core.internal.traits : externDFunc;
28 ///////////////////////////////////////////////////////////////////////////////
29 // Platform Detection and Memory Allocation
30 ///////////////////////////////////////////////////////////////////////////////
32 version (OSX)
33 version = Darwin;
34 else version (iOS)
35 version = Darwin;
36 else version (TVOS)
37 version = Darwin;
38 else version (WatchOS)
39 version = Darwin;
41 version (Shared)
42 version (GNU)
43 version = GNUShared;
45 version (D_InlineAsm_X86)
47 version (Windows)
48 version = AsmX86_Windows;
49 else version (Posix)
50 version = AsmX86_Posix;
52 else version (D_InlineAsm_X86_64)
54 version (Windows)
56 version = AsmX86_64_Windows;
58 else version (Posix)
60 version = AsmX86_64_Posix;
63 else version (X86)
65 version (CET) {} else
67 version = AsmExternal;
70 else version (X86_64)
72 version (CET) {} else
73 version (D_X32) {} else
75 version = AsmExternal;
78 else version (PPC)
80 version (Posix)
82 version = AsmExternal;
85 else version (MIPS_O32)
87 version (Posix)
89 version = AsmExternal;
92 else version (AArch64)
94 version (Posix)
96 version = AsmExternal;
99 else version (ARM)
101 version (Posix)
103 version = AsmExternal;
107 version (Posix)
109 version (AsmX86_Windows) {} else
110 version (AsmX86_Posix) {} else
111 version (AsmX86_64_Windows) {} else
112 version (AsmX86_64_Posix) {} else
113 version (AsmExternal) {} else
115 // NOTE: The ucontext implementation requires architecture specific
116 // data definitions to operate so testing for it must be done
117 // by checking for the existence of ucontext_t rather than by
118 // a version identifier. Please note that this is considered
119 // an obsolescent feature according to the POSIX spec, so a
120 // custom solution is still preferred.
121 import core.sys.posix.ucontext;
125 version (Windows)
127 import core.stdc.stdint : uintptr_t; // for _beginthreadex decl below
128 import core.stdc.stdlib; // for malloc, atexit
129 import core.sys.windows.basetsd /+: HANDLE+/;
130 import core.sys.windows.threadaux /+: getThreadStackBottom, impersonate_thread, OpenThreadHandle+/;
131 import core.sys.windows.winbase /+: CloseHandle, CREATE_SUSPENDED, DuplicateHandle, GetCurrentThread,
132 GetCurrentThreadId, GetCurrentProcess, GetExitCodeThread, GetSystemInfo, GetThreadContext,
133 GetThreadPriority, INFINITE, ResumeThread, SetThreadPriority, Sleep, STILL_ACTIVE,
134 SuspendThread, SwitchToThread, SYSTEM_INFO, THREAD_PRIORITY_IDLE, THREAD_PRIORITY_NORMAL,
135 THREAD_PRIORITY_TIME_CRITICAL, WAIT_OBJECT_0, WaitForSingleObject+/;
136 import core.sys.windows.windef /+: TRUE+/;
137 import core.sys.windows.winnt /+: CONTEXT, CONTEXT_CONTROL, CONTEXT_INTEGER+/;
139 private extern (Windows) alias btex_fptr = uint function(void*);
140 private extern (C) uintptr_t _beginthreadex(void*, uint, btex_fptr, void*, uint, uint*) nothrow @nogc;
142 else version (Posix)
144 import core.stdc.errno;
145 import core.sys.posix.semaphore;
146 import core.sys.posix.stdlib; // for malloc, valloc, free, atexit
147 import core.sys.posix.pthread;
148 import core.sys.posix.signal;
149 import core.sys.posix.time;
151 version (Darwin)
153 import core.sys.darwin.mach.thread_act;
154 import core.sys.darwin.pthread : pthread_mach_thread_np;
158 version (Solaris)
160 import core.sys.solaris.sys.priocntl;
161 import core.sys.solaris.sys.types;
162 import core.sys.posix.sys.wait : idtype_t;
165 version (GNU)
167 import gcc.builtins;
171 * Hook for whatever EH implementation is used to save/restore some data
172 * per stack.
174 * Params:
175 * newContext = The return value of the prior call to this function
176 * where the stack was last swapped out, or null when a fiber stack
177 * is switched in for the first time.
179 private extern(C) void* _d_eh_swapContext(void* newContext) nothrow @nogc;
181 version (DigitalMars)
183 version (Windows)
185 extern(D) void* swapContext(void* newContext) nothrow @nogc
187 return _d_eh_swapContext(newContext);
190 else
192 extern(C) void* _d_eh_swapContextDwarf(void* newContext) nothrow @nogc;
194 extern(D) void* swapContext(void* newContext) nothrow @nogc
196 /* Detect at runtime which scheme is being used.
197 * Eventually, determine it statically.
199 static int which = 0;
200 final switch (which)
202 case 0:
204 assert(newContext == null);
205 auto p = _d_eh_swapContext(newContext);
206 auto pdwarf = _d_eh_swapContextDwarf(newContext);
207 if (p)
209 which = 1;
210 return p;
212 else if (pdwarf)
214 which = 2;
215 return pdwarf;
217 return null;
219 case 1:
220 return _d_eh_swapContext(newContext);
221 case 2:
222 return _d_eh_swapContextDwarf(newContext);
227 else
229 extern(D) void* swapContext(void* newContext) nothrow @nogc
231 return _d_eh_swapContext(newContext);
235 ///////////////////////////////////////////////////////////////////////////////
236 // Thread
237 ///////////////////////////////////////////////////////////////////////////////
240 * This class encapsulates all threading functionality for the D
241 * programming language. As thread manipulation is a required facility
242 * for garbage collection, all user threads should derive from this
243 * class, and instances of this class should never be explicitly deleted.
244 * A new thread may be created using either derivation or composition, as
245 * in the following example.
247 class Thread : ThreadBase
250 // Standard thread data
252 version (Windows)
254 private HANDLE m_hndl;
257 version (Posix)
259 private shared bool m_isRunning;
262 version (Darwin)
264 private mach_port_t m_tmach;
267 version (Solaris)
269 private __gshared bool m_isRTClass;
273 // Standard types
275 version (Windows)
277 alias TLSKey = uint;
279 else version (Posix)
281 alias TLSKey = pthread_key_t;
284 ///////////////////////////////////////////////////////////////////////////
285 // Initialization
286 ///////////////////////////////////////////////////////////////////////////
290 * Initializes a thread object which is associated with a static
291 * D function.
293 * Params:
294 * fn = The thread function.
295 * sz = The stack size for this thread.
297 * In:
298 * fn must not be null.
300 this( void function() fn, size_t sz = 0 ) @safe pure nothrow @nogc
302 super(fn, sz);
307 * Initializes a thread object which is associated with a dynamic
308 * D function.
310 * Params:
311 * dg = The thread function.
312 * sz = The stack size for this thread.
314 * In:
315 * dg must not be null.
317 this( void delegate() dg, size_t sz = 0 ) @safe pure nothrow @nogc
319 super(dg, sz);
322 package this( size_t sz = 0 ) @safe pure nothrow @nogc
324 super(sz);
328 * Cleans up any remaining resources used by this object.
330 ~this() nothrow @nogc
332 if (super.destructBeforeDtor())
333 return;
335 version (Windows)
337 m_addr = m_addr.init;
338 CloseHandle( m_hndl );
339 m_hndl = m_hndl.init;
341 else version (Posix)
343 if (m_addr != m_addr.init)
344 pthread_detach( m_addr );
345 m_addr = m_addr.init;
347 version (Darwin)
349 m_tmach = m_tmach.init;
354 // Thread entry point. Invokes the function or delegate passed on
355 // construction (if any).
357 private final void run()
359 super.run();
363 * Provides a reference to the calling thread.
365 * Returns:
366 * The thread object representing the calling thread. The result of
367 * deleting this object is undefined. If the current thread is not
368 * attached to the runtime, a null reference is returned.
370 static Thread getThis() @safe nothrow @nogc
372 return ThreadBase.getThis().toThread;
375 ///////////////////////////////////////////////////////////////////////////
376 // Thread Context and GC Scanning Support
377 ///////////////////////////////////////////////////////////////////////////
380 version (Windows)
382 version (X86)
384 uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
386 else version (X86_64)
388 ulong[16] m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax
389 // r8,r9,r10,r11,r12,r13,r14,r15
391 else
393 static assert(false, "Architecture not supported." );
396 else version (Darwin)
398 version (X86)
400 uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax
402 else version (X86_64)
404 ulong[16] m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax
405 // r8,r9,r10,r11,r12,r13,r14,r15
407 else version (AArch64)
409 ulong[33] m_reg; // x0-x31, pc
411 else version (ARM)
413 uint[16] m_reg; // r0-r15
415 else version (PPC)
417 // Make the assumption that we only care about non-fp and non-vr regs.
418 // ??? : it seems plausible that a valid address can be copied into a VR.
419 uint[32] m_reg; // r0-31
421 else version (PPC64)
423 // As above.
424 ulong[32] m_reg; // r0-31
426 else
428 static assert(false, "Architecture not supported." );
433 ///////////////////////////////////////////////////////////////////////////
434 // General Actions
435 ///////////////////////////////////////////////////////////////////////////
439 * Starts the thread and invokes the function or delegate passed upon
440 * construction.
442 * In:
443 * This routine may only be called once per thread instance.
445 * Throws:
446 * ThreadException if the thread fails to start.
448 final Thread start() nothrow
451 assert( !next && !prev );
455 auto wasThreaded = multiThreadedFlag;
456 multiThreadedFlag = true;
457 scope( failure )
459 if ( !wasThreaded )
460 multiThreadedFlag = false;
463 version (Windows) {} else
464 version (Posix)
466 size_t stksz = adjustStackSize( m_sz );
468 pthread_attr_t attr;
470 if ( pthread_attr_init( &attr ) )
471 onThreadError( "Error initializing thread attributes" );
472 if ( stksz && pthread_attr_setstacksize( &attr, stksz ) )
473 onThreadError( "Error initializing thread stack size" );
476 version (Windows)
478 // NOTE: If a thread is just executing DllMain()
479 // while another thread is started here, it holds an OS internal
480 // lock that serializes DllMain with CreateThread. As the code
481 // might request a synchronization on slock (e.g. in thread_findByAddr()),
482 // we cannot hold that lock while creating the thread without
483 // creating a deadlock
485 // Solution: Create the thread in suspended state and then
486 // add and resume it with slock acquired
487 assert(m_sz <= uint.max, "m_sz must be less than or equal to uint.max");
488 m_hndl = cast(HANDLE) _beginthreadex( null, cast(uint) m_sz, &thread_entryPoint, cast(void*) this, CREATE_SUSPENDED, &m_addr );
489 if ( cast(size_t) m_hndl == 0 )
490 onThreadError( "Error creating thread" );
493 slock.lock_nothrow();
494 scope(exit) slock.unlock_nothrow();
496 incrementAboutToStart(this);
498 version (Windows)
500 if ( ResumeThread( m_hndl ) == -1 )
501 onThreadError( "Error resuming thread" );
503 else version (Posix)
505 // NOTE: This is also set to true by thread_entryPoint, but set it
506 // here as well so the calling thread will see the isRunning
507 // state immediately.
508 atomicStore!(MemoryOrder.raw)(m_isRunning, true);
509 scope( failure ) atomicStore!(MemoryOrder.raw)(m_isRunning, false);
511 version (Shared)
513 version (GNU)
515 auto libs = externDFunc!("gcc.sections.pinLoadedLibraries",
516 void* function() @nogc nothrow)();
518 else
520 auto libs = externDFunc!("rt.sections_elf_shared.pinLoadedLibraries",
521 void* function() @nogc nothrow)();
524 auto ps = cast(void**).malloc(2 * size_t.sizeof);
525 if (ps is null) onOutOfMemoryError();
526 ps[0] = cast(void*)this;
527 ps[1] = cast(void*)libs;
528 if ( pthread_create( &m_addr, &attr, &thread_entryPoint, ps ) != 0 )
530 version (GNU)
532 externDFunc!("gcc.sections.unpinLoadedLibraries",
533 void function(void*) @nogc nothrow)(libs);
535 else
537 externDFunc!("rt.sections_elf_shared.unpinLoadedLibraries",
538 void function(void*) @nogc nothrow)(libs);
540 .free(ps);
541 onThreadError( "Error creating thread" );
544 else
546 if ( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 )
547 onThreadError( "Error creating thread" );
549 if ( pthread_attr_destroy( &attr ) != 0 )
550 onThreadError( "Error destroying thread attributes" );
552 version (Darwin)
554 m_tmach = pthread_mach_thread_np( m_addr );
555 if ( m_tmach == m_tmach.init )
556 onThreadError( "Error creating thread" );
559 return this;
564 * Waits for this thread to complete. If the thread terminated as the
565 * result of an unhandled exception, this exception will be rethrown.
567 * Params:
568 * rethrow = Rethrow any unhandled exception which may have caused this
569 * thread to terminate.
571 * Throws:
572 * ThreadException if the operation fails.
573 * Any exception not handled by the joined thread.
575 * Returns:
576 * Any exception not handled by this thread if rethrow = false, null
577 * otherwise.
579 override final Throwable join( bool rethrow = true )
581 version (Windows)
583 if ( m_addr != m_addr.init && WaitForSingleObject( m_hndl, INFINITE ) != WAIT_OBJECT_0 )
584 throw new ThreadException( "Unable to join thread" );
585 // NOTE: m_addr must be cleared before m_hndl is closed to avoid
586 // a race condition with isRunning. The operation is done
587 // with atomicStore to prevent compiler reordering.
588 atomicStore!(MemoryOrder.raw)(*cast(shared)&m_addr, m_addr.init);
589 CloseHandle( m_hndl );
590 m_hndl = m_hndl.init;
592 else version (Posix)
594 if ( m_addr != m_addr.init && pthread_join( m_addr, null ) != 0 )
595 throw new ThreadException( "Unable to join thread" );
596 // NOTE: pthread_join acts as a substitute for pthread_detach,
597 // which is normally called by the dtor. Setting m_addr
598 // to zero ensures that pthread_detach will not be called
599 // on object destruction.
600 m_addr = m_addr.init;
602 if ( m_unhandled )
604 if ( rethrow )
605 throw m_unhandled;
606 return m_unhandled;
608 return null;
612 ///////////////////////////////////////////////////////////////////////////
613 // Thread Priority Actions
614 ///////////////////////////////////////////////////////////////////////////
616 version (Windows)
618 @property static int PRIORITY_MIN() @nogc nothrow pure @safe
620 return THREAD_PRIORITY_IDLE;
623 @property static const(int) PRIORITY_MAX() @nogc nothrow pure @safe
625 return THREAD_PRIORITY_TIME_CRITICAL;
628 @property static int PRIORITY_DEFAULT() @nogc nothrow pure @safe
630 return THREAD_PRIORITY_NORMAL;
633 else
635 private struct Priority
637 int PRIORITY_MIN = int.min;
638 int PRIORITY_DEFAULT = int.min;
639 int PRIORITY_MAX = int.min;
643 Lazily loads one of the members stored in a hidden global variable of
644 type `Priority`. Upon the first access of either member, the entire
645 `Priority` structure is initialized. Multiple initializations from
646 different threads calling this function are tolerated.
648 `which` must be one of `PRIORITY_MIN`, `PRIORITY_DEFAULT`,
649 `PRIORITY_MAX`.
651 private static shared Priority cache;
652 private static int loadGlobal(string which)()
654 auto local = atomicLoad(mixin("cache." ~ which));
655 if (local != local.min) return local;
656 // There will be benign races
657 cache = loadPriorities;
658 return atomicLoad(mixin("cache." ~ which));
662 Loads all priorities and returns them as a `Priority` structure. This
663 function is thread-neutral.
665 private static Priority loadPriorities() @nogc nothrow @trusted
667 Priority result;
668 version (Solaris)
670 pcparms_t pcParms;
671 pcinfo_t pcInfo;
673 pcParms.pc_cid = PC_CLNULL;
674 if (priocntl(idtype_t.P_PID, P_MYID, PC_GETPARMS, &pcParms) == -1)
675 assert( 0, "Unable to get scheduling class" );
677 pcInfo.pc_cid = pcParms.pc_cid;
678 // PC_GETCLINFO ignores the first two args, use dummy values
679 if (priocntl(idtype_t.P_PID, 0, PC_GETCLINFO, &pcInfo) == -1)
680 assert( 0, "Unable to get scheduling class info" );
682 pri_t* clparms = cast(pri_t*)&pcParms.pc_clparms;
683 pri_t* clinfo = cast(pri_t*)&pcInfo.pc_clinfo;
685 result.PRIORITY_MAX = clparms[0];
687 if (pcInfo.pc_clname == "RT")
689 m_isRTClass = true;
691 // For RT class, just assume it can't be changed
692 result.PRIORITY_MIN = clparms[0];
693 result.PRIORITY_DEFAULT = clparms[0];
695 else
697 m_isRTClass = false;
699 // For all other scheduling classes, there are
700 // two key values -- uprilim and maxupri.
701 // maxupri is the maximum possible priority defined
702 // for the scheduling class, and valid priorities
703 // range are in [-maxupri, maxupri].
705 // However, uprilim is an upper limit that the
706 // current thread can set for the current scheduling
707 // class, which can be less than maxupri. As such,
708 // use this value for priorityMax since this is
709 // the effective maximum.
711 // maxupri
712 result.PRIORITY_MIN = -cast(int)(clinfo[0]);
713 // by definition
714 result.PRIORITY_DEFAULT = 0;
717 else version (Posix)
719 int policy;
720 sched_param param;
721 pthread_getschedparam( pthread_self(), &policy, &param ) == 0
722 || assert(0, "Internal error in pthread_getschedparam");
724 result.PRIORITY_MIN = sched_get_priority_min( policy );
725 result.PRIORITY_MIN != -1
726 || assert(0, "Internal error in sched_get_priority_min");
727 result.PRIORITY_DEFAULT = param.sched_priority;
728 result.PRIORITY_MAX = sched_get_priority_max( policy );
729 result.PRIORITY_MAX != -1 ||
730 assert(0, "Internal error in sched_get_priority_max");
732 else
734 static assert(0, "Your code here.");
736 return result;
740 * The minimum scheduling priority that may be set for a thread. On
741 * systems where multiple scheduling policies are defined, this value
742 * represents the minimum valid priority for the scheduling policy of
743 * the process.
745 @property static int PRIORITY_MIN() @nogc nothrow pure @trusted
747 return (cast(int function() @nogc nothrow pure @safe)
748 &loadGlobal!"PRIORITY_MIN")();
752 * The maximum scheduling priority that may be set for a thread. On
753 * systems where multiple scheduling policies are defined, this value
754 * represents the maximum valid priority for the scheduling policy of
755 * the process.
757 @property static const(int) PRIORITY_MAX() @nogc nothrow pure @trusted
759 return (cast(int function() @nogc nothrow pure @safe)
760 &loadGlobal!"PRIORITY_MAX")();
764 * The default scheduling priority that is set for a thread. On
765 * systems where multiple scheduling policies are defined, this value
766 * represents the default priority for the scheduling policy of
767 * the process.
769 @property static int PRIORITY_DEFAULT() @nogc nothrow pure @trusted
771 return (cast(int function() @nogc nothrow pure @safe)
772 &loadGlobal!"PRIORITY_DEFAULT")();
776 version (NetBSD)
778 //NetBSD does not support priority for default policy
779 // and it is not possible change policy without root access
780 int fakePriority = int.max;
784 * Gets the scheduling priority for the associated thread.
786 * Note: Getting the priority of a thread that already terminated
787 * might return the default priority.
789 * Returns:
790 * The scheduling priority of this thread.
792 final @property int priority()
794 version (Windows)
796 return GetThreadPriority( m_hndl );
798 else version (NetBSD)
800 return fakePriority==int.max? PRIORITY_DEFAULT : fakePriority;
802 else version (Posix)
804 int policy;
805 sched_param param;
807 if (auto err = pthread_getschedparam(m_addr, &policy, &param))
809 // ignore error if thread is not running => Bugzilla 8960
810 if (!atomicLoad(m_isRunning)) return PRIORITY_DEFAULT;
811 throw new ThreadException("Unable to get thread priority");
813 return param.sched_priority;
819 * Sets the scheduling priority for the associated thread.
821 * Note: Setting the priority of a thread that already terminated
822 * might have no effect.
824 * Params:
825 * val = The new scheduling priority of this thread.
827 final @property void priority( int val )
830 assert(val >= PRIORITY_MIN);
831 assert(val <= PRIORITY_MAX);
835 version (Windows)
837 if ( !SetThreadPriority( m_hndl, val ) )
838 throw new ThreadException( "Unable to set thread priority" );
840 else version (Solaris)
842 // the pthread_setschedprio(3c) and pthread_setschedparam functions
843 // are broken for the default (TS / time sharing) scheduling class.
844 // instead, we use priocntl(2) which gives us the desired behavior.
846 // We hardcode the min and max priorities to the current value
847 // so this is a no-op for RT threads.
848 if (m_isRTClass)
849 return;
851 pcparms_t pcparm;
853 pcparm.pc_cid = PC_CLNULL;
854 if (priocntl(idtype_t.P_LWPID, P_MYID, PC_GETPARMS, &pcparm) == -1)
855 throw new ThreadException( "Unable to get scheduling class" );
857 pri_t* clparms = cast(pri_t*)&pcparm.pc_clparms;
859 // clparms is filled in by the PC_GETPARMS call, only necessary
860 // to adjust the element that contains the thread priority
861 clparms[1] = cast(pri_t) val;
863 if (priocntl(idtype_t.P_LWPID, P_MYID, PC_SETPARMS, &pcparm) == -1)
864 throw new ThreadException( "Unable to set scheduling class" );
866 else version (NetBSD)
868 fakePriority = val;
870 else version (Posix)
872 static if (__traits(compiles, pthread_setschedprio))
874 if (auto err = pthread_setschedprio(m_addr, val))
876 // ignore error if thread is not running => Bugzilla 8960
877 if (!atomicLoad(m_isRunning)) return;
878 throw new ThreadException("Unable to set thread priority");
881 else
883 // NOTE: pthread_setschedprio is not implemented on Darwin, FreeBSD, OpenBSD,
884 // or DragonFlyBSD, so use the more complicated get/set sequence below.
885 int policy;
886 sched_param param;
888 if (auto err = pthread_getschedparam(m_addr, &policy, &param))
890 // ignore error if thread is not running => Bugzilla 8960
891 if (!atomicLoad(m_isRunning)) return;
892 throw new ThreadException("Unable to set thread priority");
894 param.sched_priority = val;
895 if (auto err = pthread_setschedparam(m_addr, policy, &param))
897 // ignore error if thread is not running => Bugzilla 8960
898 if (!atomicLoad(m_isRunning)) return;
899 throw new ThreadException("Unable to set thread priority");
906 unittest
908 auto thr = Thread.getThis();
909 immutable prio = thr.priority;
910 scope (exit) thr.priority = prio;
912 assert(prio == PRIORITY_DEFAULT);
913 assert(prio >= PRIORITY_MIN && prio <= PRIORITY_MAX);
914 thr.priority = PRIORITY_MIN;
915 assert(thr.priority == PRIORITY_MIN);
916 thr.priority = PRIORITY_MAX;
917 assert(thr.priority == PRIORITY_MAX);
920 unittest // Bugzilla 8960
922 import core.sync.semaphore;
924 auto thr = new Thread({});
925 thr.start();
926 Thread.sleep(1.msecs); // wait a little so the thread likely has finished
927 thr.priority = PRIORITY_MAX; // setting priority doesn't cause error
928 auto prio = thr.priority; // getting priority doesn't cause error
929 assert(prio >= PRIORITY_MIN && prio <= PRIORITY_MAX);
933 * Tests whether this thread is running.
935 * Returns:
936 * true if the thread is running, false if not.
938 override final @property bool isRunning() nothrow @nogc
940 if (!super.isRunning())
941 return false;
943 version (Windows)
945 uint ecode = 0;
946 GetExitCodeThread( m_hndl, &ecode );
947 return ecode == STILL_ACTIVE;
949 else version (Posix)
951 return atomicLoad(m_isRunning);
956 ///////////////////////////////////////////////////////////////////////////
957 // Actions on Calling Thread
958 ///////////////////////////////////////////////////////////////////////////
962 * Suspends the calling thread for at least the supplied period. This may
963 * result in multiple OS calls if period is greater than the maximum sleep
964 * duration supported by the operating system.
966 * Params:
967 * val = The minimum duration the calling thread should be suspended.
969 * In:
970 * period must be non-negative.
972 * Example:
973 * ------------------------------------------------------------------------
975 * Thread.sleep( dur!("msecs")( 50 ) ); // sleep for 50 milliseconds
976 * Thread.sleep( dur!("seconds")( 5 ) ); // sleep for 5 seconds
978 * ------------------------------------------------------------------------
980 static void sleep( Duration val ) @nogc nothrow
983 assert( !val.isNegative );
987 version (Windows)
989 auto maxSleepMillis = dur!("msecs")( uint.max - 1 );
991 // avoid a non-zero time to be round down to 0
992 if ( val > dur!"msecs"( 0 ) && val < dur!"msecs"( 1 ) )
993 val = dur!"msecs"( 1 );
995 // NOTE: In instances where all other threads in the process have a
996 // lower priority than the current thread, the current thread
997 // will not yield with a sleep time of zero. However, unlike
998 // yield(), the user is not asking for a yield to occur but
999 // only for execution to suspend for the requested interval.
1000 // Therefore, expected performance may not be met if a yield
1001 // is forced upon the user.
1002 while ( val > maxSleepMillis )
1004 Sleep( cast(uint)
1005 maxSleepMillis.total!"msecs" );
1006 val -= maxSleepMillis;
1008 Sleep( cast(uint) val.total!"msecs" );
1010 else version (Posix)
1012 timespec tin = void;
1013 timespec tout = void;
1015 val.split!("seconds", "nsecs")(tin.tv_sec, tin.tv_nsec);
1016 if ( val.total!"seconds" > tin.tv_sec.max )
1017 tin.tv_sec = tin.tv_sec.max;
1018 while ( true )
1020 if ( !nanosleep( &tin, &tout ) )
1021 return;
1022 if ( errno != EINTR )
1023 assert(0, "Unable to sleep for the specified duration");
1024 tin = tout;
1031 * Forces a context switch to occur away from the calling thread.
1033 static void yield() @nogc nothrow
1035 version (Windows)
1036 SwitchToThread();
1037 else version (Posix)
1038 sched_yield();
1042 private Thread toThread(return scope ThreadBase t) @trusted nothrow @nogc pure
1044 return cast(Thread) cast(void*) t;
1047 private extern(D) static void thread_yield() @nogc nothrow
1049 Thread.yield();
1053 unittest
1055 class DerivedThread : Thread
1057 this()
1059 super(&run);
1062 private:
1063 void run()
1065 // Derived thread running.
1069 void threadFunc()
1071 // Composed thread running.
1074 // create and start instances of each type
1075 auto derived = new DerivedThread().start();
1076 auto composed = new Thread(&threadFunc).start();
1077 new Thread({
1078 // Codes to run in the newly created thread.
1079 }).start();
1082 unittest
1084 int x = 0;
1086 new Thread(
1088 x++;
1089 }).start().join();
1090 assert( x == 1 );
1094 unittest
1096 enum MSG = "Test message.";
1097 string caughtMsg;
1101 new Thread(
1102 function()
1104 throw new Exception( MSG );
1105 }).start().join();
1106 assert( false, "Expected rethrown exception." );
1108 catch ( Throwable t )
1110 assert( t.msg == MSG );
1115 unittest
1117 // use >pageSize to avoid stack overflow (e.g. in an syscall)
1118 auto thr = new Thread(function{}, 4096 + 1).start();
1119 thr.join();
1123 unittest
1125 import core.memory : GC;
1127 auto t1 = new Thread({
1128 foreach (_; 0 .. 20)
1129 ThreadBase.getAll;
1130 }).start;
1131 auto t2 = new Thread({
1132 foreach (_; 0 .. 20)
1133 GC.collect;
1134 }).start;
1135 t1.join();
1136 t2.join();
1139 unittest
1141 import core.sync.semaphore;
1142 auto sem = new Semaphore();
1144 auto t = new Thread(
1146 sem.notify();
1147 Thread.sleep(100.msecs);
1148 }).start();
1150 sem.wait(); // thread cannot be detached while being started
1151 thread_detachInstance(t);
1152 foreach (t2; Thread)
1153 assert(t !is t2);
1154 t.join();
1157 unittest
1159 // NOTE: This entire test is based on the assumption that no
1160 // memory is allocated after the child thread is
1161 // started. If an allocation happens, a collection could
1162 // trigger, which would cause the synchronization below
1163 // to cause a deadlock.
1164 // NOTE: DO NOT USE LOCKS IN CRITICAL REGIONS IN NORMAL CODE.
1166 import core.sync.semaphore;
1168 auto sema = new Semaphore(),
1169 semb = new Semaphore();
1171 auto thr = new Thread(
1173 thread_enterCriticalRegion();
1174 assert(thread_inCriticalRegion());
1175 sema.notify();
1177 semb.wait();
1178 assert(thread_inCriticalRegion());
1180 thread_exitCriticalRegion();
1181 assert(!thread_inCriticalRegion());
1182 sema.notify();
1184 semb.wait();
1185 assert(!thread_inCriticalRegion());
1188 thr.start();
1190 sema.wait();
1191 synchronized (ThreadBase.criticalRegionLock)
1192 assert(thr.m_isInCriticalRegion);
1193 semb.notify();
1195 sema.wait();
1196 synchronized (ThreadBase.criticalRegionLock)
1197 assert(!thr.m_isInCriticalRegion);
1198 semb.notify();
1200 thr.join();
1203 // https://issues.dlang.org/show_bug.cgi?id=22124
1204 unittest
1206 Thread thread = new Thread({});
1207 auto fun(Thread t, int x)
1209 t.__ctor({x = 3;});
1210 return t;
1212 static assert(!__traits(compiles, () @nogc => fun(thread, 3) ));
1215 unittest
1217 import core.sync.semaphore;
1219 shared bool inCriticalRegion;
1220 auto sema = new Semaphore(),
1221 semb = new Semaphore();
1223 auto thr = new Thread(
1225 thread_enterCriticalRegion();
1226 inCriticalRegion = true;
1227 sema.notify();
1228 semb.wait();
1230 Thread.sleep(dur!"msecs"(1));
1231 inCriticalRegion = false;
1232 thread_exitCriticalRegion();
1234 thr.start();
1236 sema.wait();
1237 assert(inCriticalRegion);
1238 semb.notify();
1240 thread_suspendAll();
1241 assert(!inCriticalRegion);
1242 thread_resumeAll();
1245 ///////////////////////////////////////////////////////////////////////////////
1246 // GC Support Routines
1247 ///////////////////////////////////////////////////////////////////////////////
1249 version (CoreDdoc)
1252 * Instruct the thread module, when initialized, to use a different set of
1253 * signals besides SIGRTMIN and SIGRTMIN + 1 for suspension and resumption of threads.
1254 * This function should be called at most once, prior to thread_init().
1255 * This function is Posix-only.
1257 extern (C) void thread_setGCSignals(int suspendSignalNo, int resumeSignalNo) nothrow @nogc
1261 else version (Posix)
1263 extern (C) void thread_setGCSignals(int suspendSignalNo, int resumeSignalNo) nothrow @nogc
1266 assert(suspendSignalNo != 0);
1267 assert(resumeSignalNo != 0);
1271 assert(suspendSignalNumber != 0);
1272 assert(resumeSignalNumber != 0);
1276 suspendSignalNumber = suspendSignalNo;
1277 resumeSignalNumber = resumeSignalNo;
1281 version (Posix)
1283 private __gshared int suspendSignalNumber;
1284 private __gshared int resumeSignalNumber;
1287 private extern (D) ThreadBase attachThread(ThreadBase _thisThread) @nogc nothrow
1289 Thread thisThread = _thisThread.toThread();
1291 StackContext* thisContext = &thisThread.m_main;
1292 assert( thisContext == thisThread.m_curr );
1294 version (Windows)
1296 thisThread.m_addr = GetCurrentThreadId();
1297 thisThread.m_hndl = GetCurrentThreadHandle();
1298 thisContext.bstack = getStackBottom();
1299 thisContext.tstack = thisContext.bstack;
1301 else version (Posix)
1303 thisThread.m_addr = pthread_self();
1304 thisContext.bstack = getStackBottom();
1305 thisContext.tstack = thisContext.bstack;
1307 atomicStore!(MemoryOrder.raw)(thisThread.toThread.m_isRunning, true);
1309 thisThread.m_isDaemon = true;
1310 thisThread.tlsGCdataInit();
1311 Thread.setThis( thisThread );
1313 version (Darwin)
1315 thisThread.m_tmach = pthread_mach_thread_np( thisThread.m_addr );
1316 assert( thisThread.m_tmach != thisThread.m_tmach.init );
1319 Thread.add( thisThread, false );
1320 Thread.add( thisContext );
1321 if ( Thread.sm_main !is null )
1322 multiThreadedFlag = true;
1323 return thisThread;
1327 * Registers the calling thread for use with the D Runtime. If this routine
1328 * is called for a thread which is already registered, no action is performed.
1330 * NOTE: This routine does not run thread-local static constructors when called.
1331 * If full functionality as a D thread is desired, the following function
1332 * must be called after thread_attachThis:
1334 * extern (C) void rt_moduleTlsCtor();
1336 * See_Also:
1337 * $(REF thread_detachThis, core,thread,threadbase)
1339 extern(C) Thread thread_attachThis()
1341 return thread_attachThis_tpl!Thread();
1345 version (Windows)
1347 // NOTE: These calls are not safe on Posix systems that use signals to
1348 // perform garbage collection. The suspendHandler uses getThis()
1349 // to get the thread handle so getThis() must be a simple call.
1350 // Mutexes can't safely be acquired inside signal handlers, and
1351 // even if they could, the mutex needed (Thread.slock) is held by
1352 // thread_suspendAll(). So in short, these routines will remain
1353 // Windows-specific. If they are truly needed elsewhere, the
1354 // suspendHandler will need a way to call a version of getThis()
1355 // that only does the TLS lookup without the fancy fallback stuff.
1357 /// ditto
1358 extern (C) Thread thread_attachByAddr( ThreadID addr )
1360 return thread_attachByAddrB( addr, getThreadStackBottom( addr ) );
1364 /// ditto
1365 extern (C) Thread thread_attachByAddrB( ThreadID addr, void* bstack )
1367 GC.disable(); scope(exit) GC.enable();
1369 if (auto t = thread_findByAddr(addr).toThread)
1370 return t;
1372 Thread thisThread = new Thread();
1373 StackContext* thisContext = &thisThread.m_main;
1374 assert( thisContext == thisThread.m_curr );
1376 thisThread.m_addr = addr;
1377 thisContext.bstack = bstack;
1378 thisContext.tstack = thisContext.bstack;
1380 thisThread.m_isDaemon = true;
1382 if ( addr == GetCurrentThreadId() )
1384 thisThread.m_hndl = GetCurrentThreadHandle();
1385 thisThread.tlsGCdataInit();
1386 Thread.setThis( thisThread );
1388 else
1390 thisThread.m_hndl = OpenThreadHandle( addr );
1391 impersonate_thread(addr,
1393 thisThread.tlsGCdataInit();
1394 Thread.setThis( thisThread );
1398 Thread.add( thisThread, false );
1399 Thread.add( thisContext );
1400 if ( Thread.sm_main !is null )
1401 multiThreadedFlag = true;
1402 return thisThread;
1407 // Calls the given delegate, passing the current thread's stack pointer to it.
1408 package extern(D) void callWithStackShell(scope callWithStackShellDg fn) nothrow
1409 in (fn)
1411 // The purpose of the 'shell' is to ensure all the registers get
1412 // put on the stack so they'll be scanned. We only need to push
1413 // the callee-save registers.
1414 void *sp = void;
1415 version (GNU)
1417 // The generic solution below using a call to __builtin_unwind_init ()
1418 // followed by an assignment to sp has two issues:
1419 // 1) On some archs it stores a huge amount of FP and Vector state which
1420 // is not the subject of the scan - and, indeed might produce false
1421 // hits.
1422 // 2) Even on archs like X86, where there are no callee-saved FPRs/VRs there
1423 // tend to be 'holes' in the frame allocations (to deal with alignment) which
1424 // also will contain random data which could produce false positives.
1425 // This solution stores only the integer callee-saved registers.
1426 version (X86)
1428 void*[3] regs = void;
1429 asm pure nothrow @nogc
1431 "movl %%ebx, %0" : "=m" (regs[0]);
1432 "movl %%esi, %0" : "=m" (regs[1]);
1433 "movl %%edi, %0" : "=m" (regs[2]);
1435 sp = cast(void*)&regs[0];
1437 else version (X86_64)
1439 void*[5] regs = void;
1440 asm pure nothrow @nogc
1442 "movq %%rbx, %0" : "=m" (regs[0]);
1443 "movq %%r12, %0" : "=m" (regs[1]);
1444 "movq %%r13, %0" : "=m" (regs[2]);
1445 "movq %%r14, %0" : "=m" (regs[3]);
1446 "movq %%r15, %0" : "=m" (regs[4]);
1448 sp = cast(void*)&regs[0];
1450 else version (PPC)
1452 void*[19] regs = void;
1453 version (Darwin)
1454 enum regname = "r";
1455 else
1456 enum regname = "";
1457 static foreach (i; 0 .. regs.length)
1459 enum int j = 13 + i; // source register
1460 asm pure nothrow @nogc
1462 "stw "~regname~j.stringof~", %0" : "=m" (regs[i]);
1465 sp = cast(void*)&regs[0];
1467 else version (PPC64)
1469 void*[19] regs = void;
1470 version (Darwin)
1471 enum regname = "r";
1472 else
1473 enum regname = "";
1474 static foreach (i; 0 .. regs.length)
1476 enum int j = 13 + i; // source register
1477 asm pure nothrow @nogc
1479 "std "~regname~j.stringof~", %0" : "=m" (regs[i]);
1482 sp = cast(void*)&regs[0];
1484 else version (AArch64)
1486 // Callee-save registers, x19-x28 according to AAPCS64, section
1487 // 5.1.1. Include x29 fp because it optionally can be a callee
1488 // saved reg
1489 size_t[11] regs = void;
1490 // store the registers in pairs
1491 asm pure nothrow @nogc
1493 "stp x19, x20, %0" : "=m" (regs[ 0]), "=m" (regs[1]);
1494 "stp x21, x22, %0" : "=m" (regs[ 2]), "=m" (regs[3]);
1495 "stp x23, x24, %0" : "=m" (regs[ 4]), "=m" (regs[5]);
1496 "stp x25, x26, %0" : "=m" (regs[ 6]), "=m" (regs[7]);
1497 "stp x27, x28, %0" : "=m" (regs[ 8]), "=m" (regs[9]);
1498 "str x29, %0" : "=m" (regs[10]);
1499 "mov %0, sp" : "=r" (sp);
1502 else version (ARM)
1504 // Callee-save registers, according to AAPCS, section 5.1.1.
1505 // arm and thumb2 instructions
1506 size_t[8] regs = void;
1507 asm pure nothrow @nogc
1509 "stm %0, {r4-r11}" : : "r" (regs.ptr) : "memory";
1510 "mov %0, sp" : "=r" (sp);
1513 else
1515 __builtin_unwind_init();
1516 sp = &sp;
1519 else version (AsmX86_Posix)
1521 size_t[3] regs = void;
1522 asm pure nothrow @nogc
1524 mov [regs + 0 * 4], EBX;
1525 mov [regs + 1 * 4], ESI;
1526 mov [regs + 2 * 4], EDI;
1528 mov sp[EBP], ESP;
1531 else version (AsmX86_Windows)
1533 size_t[3] regs = void;
1534 asm pure nothrow @nogc
1536 mov [regs + 0 * 4], EBX;
1537 mov [regs + 1 * 4], ESI;
1538 mov [regs + 2 * 4], EDI;
1540 mov sp[EBP], ESP;
1543 else version (AsmX86_64_Posix)
1545 size_t[5] regs = void;
1546 asm pure nothrow @nogc
1548 mov [regs + 0 * 8], RBX;
1549 mov [regs + 1 * 8], R12;
1550 mov [regs + 2 * 8], R13;
1551 mov [regs + 3 * 8], R14;
1552 mov [regs + 4 * 8], R15;
1554 mov sp[RBP], RSP;
1557 else version (AsmX86_64_Windows)
1559 size_t[7] regs = void;
1560 asm pure nothrow @nogc
1562 mov [regs + 0 * 8], RBX;
1563 mov [regs + 1 * 8], RSI;
1564 mov [regs + 2 * 8], RDI;
1565 mov [regs + 3 * 8], R12;
1566 mov [regs + 4 * 8], R13;
1567 mov [regs + 5 * 8], R14;
1568 mov [regs + 6 * 8], R15;
1570 mov sp[RBP], RSP;
1573 else
1575 static assert(false, "Architecture not supported.");
1578 fn(sp);
1581 version (Windows)
1582 private extern (D) void scanWindowsOnly(scope ScanAllThreadsTypeFn scan, ThreadBase _t) nothrow
1584 auto t = _t.toThread;
1586 scan( ScanType.stack, t.m_reg.ptr, t.m_reg.ptr + t.m_reg.length );
1591 * Returns the process ID of the calling process, which is guaranteed to be
1592 * unique on the system. This call is always successful.
1594 * Example:
1595 * ---
1596 * writefln("Current process id: %s", getpid());
1597 * ---
1599 version (Posix)
1601 import core.sys.posix.unistd;
1603 alias getpid = core.sys.posix.unistd.getpid;
1605 else version (Windows)
1607 alias getpid = core.sys.windows.winbase.GetCurrentProcessId;
1610 extern (C) @nogc nothrow
1612 version (CRuntime_Glibc) version = PThread_Getattr_NP;
1613 version (CRuntime_Bionic) version = PThread_Getattr_NP;
1614 version (CRuntime_Musl) version = PThread_Getattr_NP;
1615 version (CRuntime_UClibc) version = PThread_Getattr_NP;
1617 version (FreeBSD) version = PThread_Attr_Get_NP;
1618 version (NetBSD) version = PThread_Attr_Get_NP;
1619 version (DragonFlyBSD) version = PThread_Attr_Get_NP;
1621 version (PThread_Getattr_NP) int pthread_getattr_np(pthread_t thread, pthread_attr_t* attr);
1622 version (PThread_Attr_Get_NP) int pthread_attr_get_np(pthread_t thread, pthread_attr_t* attr);
1623 version (Solaris) int thr_stksegment(stack_t* stk);
1624 version (OpenBSD) int pthread_stackseg_np(pthread_t thread, stack_t* sinfo);
1628 package extern(D) void* getStackTop() nothrow @nogc
1630 version (D_InlineAsm_X86)
1631 asm pure nothrow @nogc { naked; mov EAX, ESP; ret; }
1632 else version (D_InlineAsm_X86_64)
1633 asm pure nothrow @nogc { naked; mov RAX, RSP; ret; }
1634 else version (GNU)
1635 return __builtin_frame_address(0);
1636 else
1637 static assert(false, "Architecture not supported.");
1641 package extern(D) void* getStackBottom() nothrow @nogc
1643 version (Windows)
1645 version (D_InlineAsm_X86)
1646 asm pure nothrow @nogc { naked; mov EAX, FS:4; ret; }
1647 else version (D_InlineAsm_X86_64)
1648 asm pure nothrow @nogc
1649 { naked;
1650 mov RAX, 8;
1651 mov RAX, GS:[RAX];
1652 ret;
1654 else version (GNU_InlineAsm)
1656 void *bottom;
1658 version (X86)
1659 asm pure nothrow @nogc { "movl %%fs:4, %0;" : "=r" (bottom); }
1660 else version (X86_64)
1661 asm pure nothrow @nogc { "movq %%gs:8, %0;" : "=r" (bottom); }
1662 else
1663 static assert(false, "Platform not supported.");
1665 return bottom;
1667 else
1668 static assert(false, "Architecture not supported.");
1670 else version (Darwin)
1672 import core.sys.darwin.pthread;
1673 return pthread_get_stackaddr_np(pthread_self());
1675 else version (PThread_Getattr_NP)
1677 pthread_attr_t attr;
1678 void* addr; size_t size;
1680 pthread_attr_init(&attr);
1681 pthread_getattr_np(pthread_self(), &attr);
1682 pthread_attr_getstack(&attr, &addr, &size);
1683 pthread_attr_destroy(&attr);
1684 static if (isStackGrowingDown)
1685 addr += size;
1686 return addr;
1688 else version (PThread_Attr_Get_NP)
1690 pthread_attr_t attr;
1691 void* addr; size_t size;
1693 pthread_attr_init(&attr);
1694 pthread_attr_get_np(pthread_self(), &attr);
1695 pthread_attr_getstack(&attr, &addr, &size);
1696 pthread_attr_destroy(&attr);
1697 static if (isStackGrowingDown)
1698 addr += size;
1699 return addr;
1701 else version (OpenBSD)
1703 stack_t stk;
1705 pthread_stackseg_np(pthread_self(), &stk);
1706 return stk.ss_sp;
1708 else version (Solaris)
1710 stack_t stk;
1712 thr_stksegment(&stk);
1713 return stk.ss_sp;
1715 else
1716 static assert(false, "Platform not supported.");
1720 * Suspend the specified thread and load stack and register information for
1721 * use by thread_scanAll. If the supplied thread is the calling thread,
1722 * stack and register information will be loaded but the thread will not
1723 * be suspended. If the suspend operation fails and the thread is not
1724 * running then it will be removed from the global thread list, otherwise
1725 * an exception will be thrown.
1727 * Params:
1728 * t = The thread to suspend.
1730 * Throws:
1731 * ThreadError if the suspend operation fails for a running thread.
1732 * Returns:
1733 * Whether the thread is now suspended (true) or terminated (false).
1735 private extern (D) bool suspend( Thread t ) nothrow @nogc
1737 Duration waittime = dur!"usecs"(10);
1738 Lagain:
1739 if (!t.isRunning)
1741 Thread.remove(t);
1742 return false;
1744 else if (t.m_isInCriticalRegion)
1746 Thread.criticalRegionLock.unlock_nothrow();
1747 Thread.sleep(waittime);
1748 if (waittime < dur!"msecs"(10)) waittime *= 2;
1749 Thread.criticalRegionLock.lock_nothrow();
1750 goto Lagain;
1753 version (Windows)
1755 if ( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF )
1757 if ( !t.isRunning )
1759 Thread.remove( t );
1760 return false;
1762 onThreadError( "Unable to suspend thread" );
1765 CONTEXT context = void;
1766 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
1768 if ( !GetThreadContext( t.m_hndl, &context ) )
1769 onThreadError( "Unable to load thread context" );
1770 version (X86)
1772 if ( !t.m_lock )
1773 t.m_curr.tstack = cast(void*) context.Esp;
1774 // eax,ebx,ecx,edx,edi,esi,ebp,esp
1775 t.m_reg[0] = context.Eax;
1776 t.m_reg[1] = context.Ebx;
1777 t.m_reg[2] = context.Ecx;
1778 t.m_reg[3] = context.Edx;
1779 t.m_reg[4] = context.Edi;
1780 t.m_reg[5] = context.Esi;
1781 t.m_reg[6] = context.Ebp;
1782 t.m_reg[7] = context.Esp;
1784 else version (X86_64)
1786 if ( !t.m_lock )
1787 t.m_curr.tstack = cast(void*) context.Rsp;
1788 // rax,rbx,rcx,rdx,rdi,rsi,rbp,rsp
1789 t.m_reg[0] = context.Rax;
1790 t.m_reg[1] = context.Rbx;
1791 t.m_reg[2] = context.Rcx;
1792 t.m_reg[3] = context.Rdx;
1793 t.m_reg[4] = context.Rdi;
1794 t.m_reg[5] = context.Rsi;
1795 t.m_reg[6] = context.Rbp;
1796 t.m_reg[7] = context.Rsp;
1797 // r8,r9,r10,r11,r12,r13,r14,r15
1798 t.m_reg[8] = context.R8;
1799 t.m_reg[9] = context.R9;
1800 t.m_reg[10] = context.R10;
1801 t.m_reg[11] = context.R11;
1802 t.m_reg[12] = context.R12;
1803 t.m_reg[13] = context.R13;
1804 t.m_reg[14] = context.R14;
1805 t.m_reg[15] = context.R15;
1807 else
1809 static assert(false, "Architecture not supported." );
1812 else version (Darwin)
1814 if ( t.m_addr != pthread_self() && thread_suspend( t.m_tmach ) != KERN_SUCCESS )
1816 if ( !t.isRunning )
1818 Thread.remove( t );
1819 return false;
1821 onThreadError( "Unable to suspend thread" );
1824 version (X86)
1826 x86_thread_state32_t state = void;
1827 mach_msg_type_number_t count = x86_THREAD_STATE32_COUNT;
1829 if ( thread_get_state( t.m_tmach, x86_THREAD_STATE32, &state, &count ) != KERN_SUCCESS )
1830 onThreadError( "Unable to load thread state" );
1831 if ( !t.m_lock )
1832 t.m_curr.tstack = cast(void*) state.esp;
1833 // eax,ebx,ecx,edx,edi,esi,ebp,esp
1834 t.m_reg[0] = state.eax;
1835 t.m_reg[1] = state.ebx;
1836 t.m_reg[2] = state.ecx;
1837 t.m_reg[3] = state.edx;
1838 t.m_reg[4] = state.edi;
1839 t.m_reg[5] = state.esi;
1840 t.m_reg[6] = state.ebp;
1841 t.m_reg[7] = state.esp;
1843 else version (X86_64)
1845 x86_thread_state64_t state = void;
1846 mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
1848 if ( thread_get_state( t.m_tmach, x86_THREAD_STATE64, &state, &count ) != KERN_SUCCESS )
1849 onThreadError( "Unable to load thread state" );
1850 if ( !t.m_lock )
1851 t.m_curr.tstack = cast(void*) state.rsp;
1852 // rax,rbx,rcx,rdx,rdi,rsi,rbp,rsp
1853 t.m_reg[0] = state.rax;
1854 t.m_reg[1] = state.rbx;
1855 t.m_reg[2] = state.rcx;
1856 t.m_reg[3] = state.rdx;
1857 t.m_reg[4] = state.rdi;
1858 t.m_reg[5] = state.rsi;
1859 t.m_reg[6] = state.rbp;
1860 t.m_reg[7] = state.rsp;
1861 // r8,r9,r10,r11,r12,r13,r14,r15
1862 t.m_reg[8] = state.r8;
1863 t.m_reg[9] = state.r9;
1864 t.m_reg[10] = state.r10;
1865 t.m_reg[11] = state.r11;
1866 t.m_reg[12] = state.r12;
1867 t.m_reg[13] = state.r13;
1868 t.m_reg[14] = state.r14;
1869 t.m_reg[15] = state.r15;
1871 else version (AArch64)
1873 arm_thread_state64_t state = void;
1874 mach_msg_type_number_t count = ARM_THREAD_STATE64_COUNT;
1876 if (thread_get_state(t.m_tmach, ARM_THREAD_STATE64, &state, &count) != KERN_SUCCESS)
1877 onThreadError("Unable to load thread state");
1878 // TODO: ThreadException here recurses forever! Does it
1879 //still using onThreadError?
1880 //printf("state count %d (expect %d)\n", count ,ARM_THREAD_STATE64_COUNT);
1881 if (!t.m_lock)
1882 t.m_curr.tstack = cast(void*) state.sp;
1884 t.m_reg[0..29] = state.x; // x0-x28
1885 t.m_reg[29] = state.fp; // x29
1886 t.m_reg[30] = state.lr; // x30
1887 t.m_reg[31] = state.sp; // x31
1888 t.m_reg[32] = state.pc;
1890 else version (ARM)
1892 arm_thread_state32_t state = void;
1893 mach_msg_type_number_t count = ARM_THREAD_STATE32_COUNT;
1895 // Thought this would be ARM_THREAD_STATE32, but that fails.
1896 // Mystery
1897 if (thread_get_state(t.m_tmach, ARM_THREAD_STATE, &state, &count) != KERN_SUCCESS)
1898 onThreadError("Unable to load thread state");
1899 // TODO: in past, ThreadException here recurses forever! Does it
1900 //still using onThreadError?
1901 //printf("state count %d (expect %d)\n", count ,ARM_THREAD_STATE32_COUNT);
1902 if (!t.m_lock)
1903 t.m_curr.tstack = cast(void*) state.sp;
1905 t.m_reg[0..13] = state.r; // r0 - r13
1906 t.m_reg[13] = state.sp;
1907 t.m_reg[14] = state.lr;
1908 t.m_reg[15] = state.pc;
1910 else version (PPC)
1912 ppc_thread_state_t state = void;
1913 mach_msg_type_number_t count = PPC_THREAD_STATE_COUNT;
1915 if (thread_get_state(t.m_tmach, PPC_THREAD_STATE, &state, &count) != KERN_SUCCESS)
1916 onThreadError("Unable to load thread state");
1917 if (!t.m_lock)
1918 t.m_curr.tstack = cast(void*) state.r[1];
1919 t.m_reg[] = state.r[];
1921 else version (PPC64)
1923 ppc_thread_state64_t state = void;
1924 mach_msg_type_number_t count = PPC_THREAD_STATE64_COUNT;
1926 if (thread_get_state(t.m_tmach, PPC_THREAD_STATE64, &state, &count) != KERN_SUCCESS)
1927 onThreadError("Unable to load thread state");
1928 if (!t.m_lock)
1929 t.m_curr.tstack = cast(void*) state.r[1];
1930 t.m_reg[] = state.r[];
1932 else
1934 static assert(false, "Architecture not supported." );
1937 else version (Posix)
1939 if ( t.m_addr != pthread_self() )
1941 if ( pthread_kill( t.m_addr, suspendSignalNumber ) != 0 )
1943 if ( !t.isRunning )
1945 Thread.remove( t );
1946 return false;
1948 onThreadError( "Unable to suspend thread" );
1951 else if ( !t.m_lock )
1953 t.m_curr.tstack = getStackTop();
1956 return true;
1960 * Suspend all threads but the calling thread for "stop the world" garbage
1961 * collection runs. This function may be called multiple times, and must
1962 * be followed by a matching number of calls to thread_resumeAll before
1963 * processing is resumed.
1965 * Throws:
1966 * ThreadError if the suspend operation fails for a running thread.
1968 extern (C) void thread_suspendAll() nothrow
1970 // NOTE: We've got an odd chicken & egg problem here, because while the GC
1971 // is required to call thread_init before calling any other thread
1972 // routines, thread_init may allocate memory which could in turn
1973 // trigger a collection. Thus, thread_suspendAll, thread_scanAll,
1974 // and thread_resumeAll must be callable before thread_init
1975 // completes, with the assumption that no other GC memory has yet
1976 // been allocated by the system, and thus there is no risk of losing
1977 // data if the global thread list is empty. The check of
1978 // Thread.sm_tbeg below is done to ensure thread_init has completed,
1979 // and therefore that calling Thread.getThis will not result in an
1980 // error. For the short time when Thread.sm_tbeg is null, there is
1981 // no reason not to simply call the multithreaded code below, with
1982 // the expectation that the foreach loop will never be entered.
1983 if ( !multiThreadedFlag && Thread.sm_tbeg )
1985 if ( ++suspendDepth == 1 )
1986 suspend( Thread.getThis() );
1988 return;
1991 Thread.slock.lock_nothrow();
1993 if ( ++suspendDepth > 1 )
1994 return;
1996 Thread.criticalRegionLock.lock_nothrow();
1997 scope (exit) Thread.criticalRegionLock.unlock_nothrow();
1998 size_t cnt;
1999 bool suspendedSelf;
2000 Thread t = ThreadBase.sm_tbeg.toThread;
2001 while (t)
2003 auto tn = t.next.toThread;
2004 if (suspend(t))
2006 if (t is ThreadBase.getThis())
2007 suspendedSelf = true;
2008 ++cnt;
2010 t = tn;
2013 version (Darwin)
2015 else version (Posix)
2017 // Subtract own thread if we called suspend() on ourselves.
2018 // For example, suspendedSelf would be false if the current
2019 // thread ran thread_detachThis().
2020 assert(cnt >= 1);
2021 if (suspendedSelf)
2022 --cnt;
2023 // wait for semaphore notifications
2024 for (; cnt; --cnt)
2026 while (sem_wait(&suspendCount) != 0)
2028 if (errno != EINTR)
2029 onThreadError("Unable to wait for semaphore");
2030 errno = 0;
2038 * Resume the specified thread and unload stack and register information.
2039 * If the supplied thread is the calling thread, stack and register
2040 * information will be unloaded but the thread will not be resumed. If
2041 * the resume operation fails and the thread is not running then it will
2042 * be removed from the global thread list, otherwise an exception will be
2043 * thrown.
2045 * Params:
2046 * t = The thread to resume.
2048 * Throws:
2049 * ThreadError if the resume fails for a running thread.
2051 private extern (D) void resume(ThreadBase _t) nothrow @nogc
2053 Thread t = _t.toThread;
2055 version (Windows)
2057 if ( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF )
2059 if ( !t.isRunning )
2061 Thread.remove( t );
2062 return;
2064 onThreadError( "Unable to resume thread" );
2067 if ( !t.m_lock )
2068 t.m_curr.tstack = t.m_curr.bstack;
2069 t.m_reg[0 .. $] = 0;
2071 else version (Darwin)
2073 if ( t.m_addr != pthread_self() && thread_resume( t.m_tmach ) != KERN_SUCCESS )
2075 if ( !t.isRunning )
2077 Thread.remove( t );
2078 return;
2080 onThreadError( "Unable to resume thread" );
2083 if ( !t.m_lock )
2084 t.m_curr.tstack = t.m_curr.bstack;
2085 t.m_reg[0 .. $] = 0;
2087 else version (Posix)
2089 if ( t.m_addr != pthread_self() )
2091 if ( pthread_kill( t.m_addr, resumeSignalNumber ) != 0 )
2093 if ( !t.isRunning )
2095 Thread.remove( t );
2096 return;
2098 onThreadError( "Unable to resume thread" );
2101 else if ( !t.m_lock )
2103 t.m_curr.tstack = t.m_curr.bstack;
2110 * Initializes the thread module. This function must be called by the
2111 * garbage collector on startup and before any other thread routines
2112 * are called.
2114 extern (C) void thread_init() @nogc nothrow
2116 // NOTE: If thread_init itself performs any allocations then the thread
2117 // routines reserved for garbage collector use may be called while
2118 // thread_init is being processed. However, since no memory should
2119 // exist to be scanned at this point, it is sufficient for these
2120 // functions to detect the condition and return immediately.
2122 initLowlevelThreads();
2123 Thread.initLocks();
2125 version (Darwin)
2127 // thread id different in forked child process
2128 static extern(C) void initChildAfterFork()
2130 auto thisThread = Thread.getThis();
2131 if (!thisThread)
2133 // It is possible that runtime was not properly initialized in the current process or thread -
2134 // it may happen after `fork` call when using a dynamically loaded shared library written in D from a multithreaded non-D program.
2135 // In such case getThis will return null.
2136 return;
2138 thisThread.m_addr = pthread_self();
2139 assert( thisThread.m_addr != thisThread.m_addr.init );
2140 thisThread.m_tmach = pthread_mach_thread_np( thisThread.m_addr );
2141 assert( thisThread.m_tmach != thisThread.m_tmach.init );
2143 pthread_atfork(null, null, &initChildAfterFork);
2145 else version (Posix)
2147 version (OpenBSD)
2149 // OpenBSD does not support SIGRTMIN or SIGRTMAX
2150 // Use SIGUSR1 for SIGRTMIN, SIGUSR2 for SIGRTMIN + 1
2151 // And use 32 for SIGRTMAX (32 is the max signal number on OpenBSD)
2152 enum SIGRTMIN = SIGUSR1;
2153 enum SIGRTMAX = 32;
2156 if ( suspendSignalNumber == 0 )
2158 suspendSignalNumber = SIGRTMIN;
2161 if ( resumeSignalNumber == 0 )
2163 resumeSignalNumber = SIGRTMIN + 1;
2164 assert(resumeSignalNumber <= SIGRTMAX);
2166 int status;
2167 sigaction_t suspend = void;
2168 sigaction_t resume = void;
2170 // This is a quick way to zero-initialize the structs without using
2171 // memset or creating a link dependency on their static initializer.
2172 (cast(byte*) &suspend)[0 .. sigaction_t.sizeof] = 0;
2173 (cast(byte*) &resume)[0 .. sigaction_t.sizeof] = 0;
2175 // NOTE: SA_RESTART indicates that system calls should restart if they
2176 // are interrupted by a signal, but this is not available on all
2177 // Posix systems, even those that support multithreading.
2178 static if ( __traits( compiles, SA_RESTART ) )
2179 suspend.sa_flags = SA_RESTART;
2181 suspend.sa_handler = &thread_suspendHandler;
2182 // NOTE: We want to ignore all signals while in this handler, so fill
2183 // sa_mask to indicate this.
2184 status = sigfillset( &suspend.sa_mask );
2185 assert( status == 0 );
2187 // NOTE: Since resumeSignalNumber should only be issued for threads within the
2188 // suspend handler, we don't want this signal to trigger a
2189 // restart.
2190 resume.sa_flags = 0;
2191 resume.sa_handler = &thread_resumeHandler;
2192 // NOTE: We want to ignore all signals while in this handler, so fill
2193 // sa_mask to indicate this.
2194 status = sigfillset( &resume.sa_mask );
2195 assert( status == 0 );
2197 status = sigaction( suspendSignalNumber, &suspend, null );
2198 assert( status == 0 );
2200 status = sigaction( resumeSignalNumber, &resume, null );
2201 assert( status == 0 );
2203 status = sem_init( &suspendCount, 0, 0 );
2204 assert( status == 0 );
2206 _mainThreadStore[] = __traits(initSymbol, Thread)[];
2207 Thread.sm_main = attachThread((cast(Thread)_mainThreadStore.ptr).__ctor());
2210 private alias MainThreadStore = void[__traits(classInstanceSize, Thread)];
2211 package __gshared align(__traits(classInstanceAlignment, Thread)) MainThreadStore _mainThreadStore;
2214 * Terminates the thread module. No other thread routine may be called
2215 * afterwards.
2217 extern (C) void thread_term() @nogc nothrow
2219 thread_term_tpl!(Thread)(_mainThreadStore);
2223 ///////////////////////////////////////////////////////////////////////////////
2224 // Thread Entry Point and Signal Handlers
2225 ///////////////////////////////////////////////////////////////////////////////
2228 version (Windows)
2230 private
2233 // Entry point for Windows threads
2235 extern (Windows) uint thread_entryPoint( void* arg ) nothrow
2237 Thread obj = cast(Thread) arg;
2238 assert( obj );
2240 obj.initDataStorage();
2242 Thread.setThis(obj);
2243 Thread.add(obj);
2244 scope (exit)
2246 Thread.remove(obj);
2247 obj.destroyDataStorage();
2249 Thread.add(&obj.m_main);
2251 // NOTE: No GC allocations may occur until the stack pointers have
2252 // been set and Thread.getThis returns a valid reference to
2253 // this thread object (this latter condition is not strictly
2254 // necessary on Windows but it should be followed for the
2255 // sake of consistency).
2257 // TODO: Consider putting an auto exception object here (using
2258 // alloca) forOutOfMemoryError plus something to track
2259 // whether an exception is in-flight?
2261 void append( Throwable t )
2263 obj.m_unhandled = Throwable.chainTogether(obj.m_unhandled, t);
2266 version (D_InlineAsm_X86)
2268 asm nothrow @nogc { fninit; }
2273 rt_moduleTlsCtor();
2276 obj.run();
2278 catch ( Throwable t )
2280 append( t );
2282 rt_moduleTlsDtor();
2284 catch ( Throwable t )
2286 append( t );
2288 return 0;
2292 HANDLE GetCurrentThreadHandle() nothrow @nogc
2294 const uint DUPLICATE_SAME_ACCESS = 0x00000002;
2296 HANDLE curr = GetCurrentThread(),
2297 proc = GetCurrentProcess(),
2298 hndl;
2300 DuplicateHandle( proc, curr, proc, &hndl, 0, TRUE, DUPLICATE_SAME_ACCESS );
2301 return hndl;
2305 else version (Posix)
2307 private
2309 import core.stdc.errno;
2310 import core.sys.posix.semaphore;
2311 import core.sys.posix.stdlib; // for malloc, valloc, free, atexit
2312 import core.sys.posix.pthread;
2313 import core.sys.posix.signal;
2314 import core.sys.posix.time;
2316 version (Darwin)
2318 import core.sys.darwin.mach.thread_act;
2319 import core.sys.darwin.pthread : pthread_mach_thread_np;
2323 // Entry point for POSIX threads
2325 extern (C) void* thread_entryPoint( void* arg ) nothrow
2327 version (Shared)
2329 Thread obj = cast(Thread)(cast(void**)arg)[0];
2330 auto loadedLibraries = (cast(void**)arg)[1];
2331 .free(arg);
2333 else
2335 Thread obj = cast(Thread)arg;
2337 assert( obj );
2339 // loadedLibraries need to be inherited from parent thread
2340 // before initilizing GC for TLS (rt_tlsgc_init)
2341 version (GNUShared)
2343 externDFunc!("gcc.sections.inheritLoadedLibraries",
2344 void function(void*) @nogc nothrow)(loadedLibraries);
2346 else version (Shared)
2348 externDFunc!("rt.sections_elf_shared.inheritLoadedLibraries",
2349 void function(void*) @nogc nothrow)(loadedLibraries);
2352 obj.initDataStorage();
2354 atomicStore!(MemoryOrder.raw)(obj.m_isRunning, true);
2355 Thread.setThis(obj); // allocates lazy TLS (see Issue 11981)
2356 Thread.add(obj); // can only receive signals from here on
2357 scope (exit)
2359 Thread.remove(obj);
2360 atomicStore!(MemoryOrder.raw)(obj.m_isRunning, false);
2361 obj.destroyDataStorage();
2363 Thread.add(&obj.m_main);
2365 static extern (C) void thread_cleanupHandler( void* arg ) nothrow @nogc
2367 Thread obj = cast(Thread) arg;
2368 assert( obj );
2370 // NOTE: If the thread terminated abnormally, just set it as
2371 // not running and let thread_suspendAll remove it from
2372 // the thread list. This is safer and is consistent
2373 // with the Windows thread code.
2374 atomicStore!(MemoryOrder.raw)(obj.m_isRunning,false);
2377 // NOTE: Using void to skip the initialization here relies on
2378 // knowledge of how pthread_cleanup is implemented. It may
2379 // not be appropriate for all platforms. However, it does
2380 // avoid the need to link the pthread module. If any
2381 // implementation actually requires default initialization
2382 // then pthread_cleanup should be restructured to maintain
2383 // the current lack of a link dependency.
2384 static if ( __traits( compiles, pthread_cleanup ) )
2386 pthread_cleanup cleanup = void;
2387 cleanup.push( &thread_cleanupHandler, cast(void*) obj );
2389 else static if ( __traits( compiles, pthread_cleanup_push ) )
2391 pthread_cleanup_push( &thread_cleanupHandler, cast(void*) obj );
2393 else
2395 static assert( false, "Platform not supported." );
2398 // NOTE: No GC allocations may occur until the stack pointers have
2399 // been set and Thread.getThis returns a valid reference to
2400 // this thread object (this latter condition is not strictly
2401 // necessary on Windows but it should be followed for the
2402 // sake of consistency).
2404 // TODO: Consider putting an auto exception object here (using
2405 // alloca) forOutOfMemoryError plus something to track
2406 // whether an exception is in-flight?
2408 void append( Throwable t )
2410 obj.m_unhandled = Throwable.chainTogether(obj.m_unhandled, t);
2414 rt_moduleTlsCtor();
2417 obj.run();
2419 catch ( Throwable t )
2421 append( t );
2423 rt_moduleTlsDtor();
2424 version (GNUShared)
2426 externDFunc!("gcc.sections.cleanupLoadedLibraries",
2427 void function() @nogc nothrow)();
2429 else version (Shared)
2431 externDFunc!("rt.sections_elf_shared.cleanupLoadedLibraries",
2432 void function() @nogc nothrow)();
2435 catch ( Throwable t )
2437 append( t );
2440 // NOTE: Normal cleanup is handled by scope(exit).
2442 static if ( __traits( compiles, pthread_cleanup ) )
2444 cleanup.pop( 0 );
2446 else static if ( __traits( compiles, pthread_cleanup_push ) )
2448 pthread_cleanup_pop( 0 );
2451 return null;
2456 // Used to track the number of suspended threads
2458 __gshared sem_t suspendCount;
2461 extern (C) void thread_suspendHandler( int sig ) nothrow
2464 assert( sig == suspendSignalNumber );
2468 void op(void* sp) nothrow
2470 // NOTE: Since registers are being pushed and popped from the
2471 // stack, any other stack data used by this function should
2472 // be gone before the stack cleanup code is called below.
2473 Thread obj = Thread.getThis();
2474 assert(obj !is null);
2476 if ( !obj.m_lock )
2478 obj.m_curr.tstack = getStackTop();
2481 sigset_t sigres = void;
2482 int status;
2484 status = sigfillset( &sigres );
2485 assert( status == 0 );
2487 status = sigdelset( &sigres, resumeSignalNumber );
2488 assert( status == 0 );
2490 status = sem_post( &suspendCount );
2491 assert( status == 0 );
2493 sigsuspend( &sigres );
2495 if ( !obj.m_lock )
2497 obj.m_curr.tstack = obj.m_curr.bstack;
2500 callWithStackShell(&op);
2504 extern (C) void thread_resumeHandler( int sig ) nothrow
2507 assert( sig == resumeSignalNumber );
2515 else
2517 // NOTE: This is the only place threading versions are checked. If a new
2518 // version is added, the module code will need to be searched for
2519 // places where version-specific code may be required. This can be
2520 // easily accomlished by searching for 'Windows' or 'Posix'.
2521 static assert( false, "Unknown threading implementation." );
2525 // exposed by compiler runtime
2527 extern (C) void rt_moduleTlsCtor();
2528 extern (C) void rt_moduleTlsDtor();
2531 // regression test for Issue 13416
2532 version (FreeBSD) unittest
2534 static void loop()
2536 pthread_attr_t attr;
2537 pthread_attr_init(&attr);
2538 auto thr = pthread_self();
2539 foreach (i; 0 .. 50)
2540 pthread_attr_get_np(thr, &attr);
2541 pthread_attr_destroy(&attr);
2544 auto thr = new Thread(&loop).start();
2545 foreach (i; 0 .. 50)
2547 thread_suspendAll();
2548 thread_resumeAll();
2550 thr.join();
2553 version (DragonFlyBSD) unittest
2555 static void loop()
2557 pthread_attr_t attr;
2558 pthread_attr_init(&attr);
2559 auto thr = pthread_self();
2560 foreach (i; 0 .. 50)
2561 pthread_attr_get_np(thr, &attr);
2562 pthread_attr_destroy(&attr);
2565 auto thr = new Thread(&loop).start();
2566 foreach (i; 0 .. 50)
2568 thread_suspendAll();
2569 thread_resumeAll();
2571 thr.join();
2575 ///////////////////////////////////////////////////////////////////////////////
2576 // lowlovel threading support
2577 ///////////////////////////////////////////////////////////////////////////////
2579 private
2581 version (Windows):
2582 // If the runtime is dynamically loaded as a DLL, there is a problem with
2583 // threads still running when the DLL is supposed to be unloaded:
2585 // - with the VC runtime starting with VS2015 (i.e. using the Universal CRT)
2586 // a thread created with _beginthreadex increments the DLL reference count
2587 // and decrements it when done, so that the DLL is no longer unloaded unless
2588 // all the threads have terminated. With the DLL reference count held up
2589 // by a thread that is only stopped by a signal from a static destructor or
2590 // the termination of the runtime will cause the DLL to never be unloaded.
2592 // - with the DigitalMars runtime and VC runtime up to VS2013, the thread
2593 // continues to run, but crashes once the DLL is unloaded from memory as
2594 // the code memory is no longer accessible. Stopping the threads is not possible
2595 // from within the runtime termination as it is invoked from
2596 // DllMain(DLL_PROCESS_DETACH) holding a lock that prevents threads from
2597 // terminating.
2599 // Solution: start a watchdog thread that keeps the DLL reference count above 0 and
2600 // checks it periodically. If it is equal to 1 (plus the number of started threads), no
2601 // external references to the DLL exist anymore, threads can be stopped
2602 // and runtime termination and DLL unload can be invoked via FreeLibraryAndExitThread.
2603 // Note: runtime termination is then performed by a different thread than at startup.
2605 // Note: if the DLL is never unloaded, process termination kills all threads
2606 // and signals their handles before unconditionally calling DllMain(DLL_PROCESS_DETACH).
2608 import core.sys.windows.winbase : FreeLibraryAndExitThread, GetModuleHandleExW,
2609 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
2610 import core.sys.windows.windef : HMODULE;
2611 import core.sys.windows.dll : dll_getRefCount;
2613 version (CRuntime_Microsoft)
2614 extern(C) extern __gshared ubyte msvcUsesUCRT; // from rt/msvc.d
2616 /// set during termination of a DLL on Windows, i.e. while executing DllMain(DLL_PROCESS_DETACH)
2617 public __gshared bool thread_DLLProcessDetaching;
2619 __gshared HMODULE ll_dllModule;
2620 __gshared ThreadID ll_dllMonitorThread;
2622 int ll_countLowLevelThreadsWithDLLUnloadCallback() nothrow
2624 lowlevelLock.lock_nothrow();
2625 scope(exit) lowlevelLock.unlock_nothrow();
2627 int cnt = 0;
2628 foreach (i; 0 .. ll_nThreads)
2629 if (ll_pThreads[i].cbDllUnload)
2630 cnt++;
2631 return cnt;
2634 bool ll_dllHasExternalReferences() nothrow
2636 version (CRuntime_DigitalMars)
2637 enum internalReferences = 1; // only the watchdog thread
2638 else
2639 int internalReferences = msvcUsesUCRT ? 1 + ll_countLowLevelThreadsWithDLLUnloadCallback() : 1;
2641 int refcnt = dll_getRefCount(ll_dllModule);
2642 return refcnt > internalReferences;
2645 private void monitorDLLRefCnt() nothrow
2647 // this thread keeps the DLL alive until all external references are gone
2648 while (ll_dllHasExternalReferences())
2650 Thread.sleep(100.msecs);
2653 // the current thread will be terminated below
2654 ll_removeThread(GetCurrentThreadId());
2656 for (;;)
2658 ThreadID tid;
2659 void delegate() nothrow cbDllUnload;
2661 lowlevelLock.lock_nothrow();
2662 scope(exit) lowlevelLock.unlock_nothrow();
2664 foreach (i; 0 .. ll_nThreads)
2665 if (ll_pThreads[i].cbDllUnload)
2667 cbDllUnload = ll_pThreads[i].cbDllUnload;
2668 tid = ll_pThreads[0].tid;
2671 if (!cbDllUnload)
2672 break;
2673 cbDllUnload();
2674 assert(!findLowLevelThread(tid));
2677 FreeLibraryAndExitThread(ll_dllModule, 0);
2680 int ll_getDLLRefCount() nothrow @nogc
2682 if (!ll_dllModule &&
2683 !GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
2684 cast(const(wchar)*) &ll_getDLLRefCount, &ll_dllModule))
2685 return -1;
2686 return dll_getRefCount(ll_dllModule);
2689 bool ll_startDLLUnloadThread() nothrow @nogc
2691 int refcnt = ll_getDLLRefCount();
2692 if (refcnt < 0)
2693 return false; // not a dynamically loaded DLL
2695 if (ll_dllMonitorThread !is ThreadID.init)
2696 return true;
2698 // if a thread is created from a DLL, the MS runtime (starting with VC2015) increments the DLL reference count
2699 // to avoid the DLL being unloaded while the thread is still running. Mimick this behavior here for all
2700 // runtimes not doing this
2701 version (CRuntime_DigitalMars)
2702 enum needRef = true;
2703 else
2704 bool needRef = !msvcUsesUCRT;
2706 if (needRef)
2708 HMODULE hmod;
2709 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, cast(const(wchar)*) &ll_getDLLRefCount, &hmod);
2712 ll_dllMonitorThread = createLowLevelThread(() { monitorDLLRefCnt(); });
2713 return ll_dllMonitorThread != ThreadID.init;
2718 * Create a thread not under control of the runtime, i.e. TLS module constructors are
2719 * not run and the GC does not suspend it during a collection.
2721 * Params:
2722 * dg = delegate to execute in the created thread.
2723 * stacksize = size of the stack of the created thread. The default of 0 will select the
2724 * platform-specific default size.
2725 * cbDllUnload = Windows only: if running in a dynamically loaded DLL, this delegate will be called
2726 * if the DLL is supposed to be unloaded, but the thread is still running.
2727 * The thread must be terminated via `joinLowLevelThread` by the callback.
2729 * Returns: the platform specific thread ID of the new thread. If an error occurs, `ThreadID.init`
2730 * is returned.
2732 ThreadID createLowLevelThread(void delegate() nothrow dg, uint stacksize = 0,
2733 void delegate() nothrow cbDllUnload = null) nothrow @nogc
2735 void delegate() nothrow* context = cast(void delegate() nothrow*)malloc(dg.sizeof);
2736 *context = dg;
2738 ThreadID tid;
2739 version (Windows)
2741 // the thread won't start until after the DLL is unloaded
2742 if (thread_DLLProcessDetaching)
2743 return ThreadID.init;
2745 static extern (Windows) uint thread_lowlevelEntry(void* ctx) nothrow
2747 auto dg = *cast(void delegate() nothrow*)ctx;
2748 free(ctx);
2750 dg();
2751 ll_removeThread(GetCurrentThreadId());
2752 return 0;
2755 // see Thread.start() for why thread is created in suspended state
2756 HANDLE hThread = cast(HANDLE) _beginthreadex(null, stacksize, &thread_lowlevelEntry,
2757 context, CREATE_SUSPENDED, &tid);
2758 if (!hThread)
2759 return ThreadID.init;
2762 lowlevelLock.lock_nothrow();
2763 scope(exit) lowlevelLock.unlock_nothrow();
2765 ll_nThreads++;
2766 ll_pThreads = cast(ll_ThreadData*)realloc(ll_pThreads, ll_ThreadData.sizeof * ll_nThreads);
2768 version (Windows)
2770 ll_pThreads[ll_nThreads - 1].tid = tid;
2771 ll_pThreads[ll_nThreads - 1].cbDllUnload = cbDllUnload;
2772 if (ResumeThread(hThread) == -1)
2773 onThreadError("Error resuming thread");
2774 CloseHandle(hThread);
2776 if (cbDllUnload)
2777 ll_startDLLUnloadThread();
2779 else version (Posix)
2781 static extern (C) void* thread_lowlevelEntry(void* ctx) nothrow
2783 auto dg = *cast(void delegate() nothrow*)ctx;
2784 free(ctx);
2786 dg();
2787 ll_removeThread(pthread_self());
2788 return null;
2791 size_t stksz = adjustStackSize(stacksize);
2793 pthread_attr_t attr;
2795 int rc;
2796 if ((rc = pthread_attr_init(&attr)) != 0)
2797 return ThreadID.init;
2798 if (stksz && (rc = pthread_attr_setstacksize(&attr, stksz)) != 0)
2799 return ThreadID.init;
2800 if ((rc = pthread_create(&tid, &attr, &thread_lowlevelEntry, context)) != 0)
2801 return ThreadID.init;
2802 if ((rc = pthread_attr_destroy(&attr)) != 0)
2803 return ThreadID.init;
2805 ll_pThreads[ll_nThreads - 1].tid = tid;
2807 return tid;
2811 * Wait for a thread created with `createLowLevelThread` to terminate.
2813 * Note: In a Windows DLL, if this function is called via DllMain with
2814 * argument DLL_PROCESS_DETACH, the thread is terminated forcefully
2815 * without proper cleanup as a deadlock would happen otherwise.
2817 * Params:
2818 * tid = the thread ID returned by `createLowLevelThread`.
2820 void joinLowLevelThread(ThreadID tid) nothrow @nogc
2822 version (Windows)
2824 HANDLE handle = OpenThreadHandle(tid);
2825 if (!handle)
2826 return;
2828 if (thread_DLLProcessDetaching)
2830 // When being called from DllMain/DLL_DETACH_PROCESS, threads cannot stop
2831 // due to the loader lock being held by the current thread.
2832 // On the other hand, the thread must not continue to run as it will crash
2833 // if the DLL is unloaded. The best guess is to terminate it immediately.
2834 TerminateThread(handle, 1);
2835 WaitForSingleObject(handle, 10); // give it some time to terminate, but don't wait indefinitely
2837 else
2838 WaitForSingleObject(handle, INFINITE);
2839 CloseHandle(handle);
2841 else version (Posix)
2843 if (pthread_join(tid, null) != 0)
2844 onThreadError("Unable to join thread");
2848 nothrow @nogc unittest
2850 struct TaskWithContect
2852 shared int n = 0;
2853 void run() nothrow
2855 n.atomicOp!"+="(1);
2858 TaskWithContect task;
2860 ThreadID[8] tids;
2861 for (int i = 0; i < tids.length; i++)
2863 tids[i] = createLowLevelThread(&task.run);
2864 assert(tids[i] != ThreadID.init);
2867 for (int i = 0; i < tids.length; i++)
2868 joinLowLevelThread(tids[i]);
2870 assert(task.n == tids.length);
2873 version (Posix)
2874 private size_t adjustStackSize(size_t sz) nothrow @nogc
2876 if (sz == 0)
2877 return 0;
2879 // stack size must be at least PTHREAD_STACK_MIN for most platforms.
2880 if (PTHREAD_STACK_MIN > sz)
2881 sz = PTHREAD_STACK_MIN;
2883 version (CRuntime_Glibc)
2885 // On glibc, TLS uses the top of the stack, so add its size to the requested size
2886 version (GNU)
2888 sz += externDFunc!("gcc.sections.elf.sizeOfTLS",
2889 size_t function() @nogc nothrow)();
2891 else
2893 sz += externDFunc!("rt.sections_elf_shared.sizeOfTLS",
2894 size_t function() @nogc nothrow)();
2898 // stack size must be a multiple of pageSize
2899 sz = ((sz + pageSize - 1) & ~(pageSize - 1));
2901 return sz;