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