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