Skip to content

Commit f407ee7

Browse files
authored
druntime: Move unblockGCSignals to core.internal.gc.os (#21847)
Limit the number of platforms that this is done on. A inspection of some libc implementations of fork has identified the main culprits, don't need to apply this to any others. MacOS testsuite also regressed as a result on calling this code, it's not clear why, but the backtrace is: ``` * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) * frame #0: 0x00007ff81abe6ee3 libsystem_platform.dylib`_os_unfair_lock_recursive_abort + 23 frame #1: 0x00007ff81abe12da libsystem_platform.dylib`_os_unfair_lock_lock_slow + 247 frame #2: 0x00007ff81abccd44 libsystem_pthread.dylib`_pthread_atfork_prepare_handlers + 48 frame #3: 0x00007ff825dc2705 libSystem.B.dylib`libSystem_atfork_prepare + 25 frame #4: 0x00007ff81aac17e1 libsystem_c.dylib`fork + 24 frame #5: 0x0000000101f730ee test_runner`core.internal.backtrace.dwarf.resolveAddressesWithAtos(Location[]) + 210 ```
1 parent c81714b commit f407ee7

File tree

2 files changed

+36
-22
lines changed
  • druntime/src/core/internal/gc

2 files changed

+36
-22
lines changed

druntime/src/core/internal/gc/impl/conservative/gc.d

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3495,30 +3495,10 @@ Lmark:
34953495

34963496
__gshared bool fork_needs_lock = true; // racing condition with cocurrent calls of fork?
34973497

3498-
// The GC signals might be blocked by `fork` when the atfork prepare
3499-
// handler is invoked. This guards us from the scenario where we are
3500-
// waiting for a GC action in another thread to complete, and that thread
3501-
// decides to call thread_suspendAll, then we must be able to response to
3502-
// that request, otherwise we end up in a deadlock situation.
3503-
private static void unblockGCSignals() nothrow @nogc
3504-
{
3505-
import core.sys.posix.signal : pthread_sigmask, sigaddset, sigemptyset, sigset_t, SIG_UNBLOCK;
3506-
3507-
int suspendSignal = void, resumeSignal = void;
3508-
thread_getGCSignals(suspendSignal, resumeSignal);
3509-
3510-
sigset_t set;
3511-
sigemptyset(&set);
3512-
sigaddset(&set, suspendSignal);
3513-
sigaddset(&set, resumeSignal);
3514-
3515-
auto sigmask = pthread_sigmask(SIG_UNBLOCK, &set, null);
3516-
assert(sigmask == 0, "failed to unblock GC signals");
3517-
}
3518-
35193498
extern(C) static void _d_gcx_atfork_prepare()
35203499
{
3521-
unblockGCSignals();
3500+
static if (__traits(compiles, os_unblock_gc_signals))
3501+
os_unblock_gc_signals();
35223502

35233503
if (instance && fork_needs_lock)
35243504
ConservativeGC.lockNR();

druntime/src/core/internal/gc/os.d

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@ else version (Posix)
8585
return ChildStatus.done;
8686
}
8787

88+
version (DragonFlyBSD)
89+
version = GCSignalsUnblock;
90+
version (FreeBSD)
91+
version = GCSignalsUnblock;
92+
version (Solaris)
93+
version = GCSignalsUnblock;
94+
8895
//version = GC_Use_Alloc_MMap;
8996
}
9097
else
@@ -315,3 +322,30 @@ else version (Posix)
315322
return pageSize * pages;
316323
}
317324
}
325+
326+
/**
327+
The GC signals might be blocked by `fork` when the atfork prepare
328+
handler is invoked. This guards us from the scenario where we are
329+
waiting for a GC action in another thread to complete, and that thread
330+
decides to call thread_suspendAll, then we must be able to response to
331+
that request, otherwise we end up in a deadlock situation.
332+
*/
333+
version (GCSignalsUnblock)
334+
{
335+
void os_unblock_gc_signals() nothrow @nogc
336+
{
337+
import core.sys.posix.signal : pthread_sigmask, sigaddset, sigemptyset, sigset_t, SIG_UNBLOCK;
338+
import core.thread : thread_getGCSignals;
339+
340+
int suspendSignal = void, resumeSignal = void;
341+
thread_getGCSignals(suspendSignal, resumeSignal);
342+
343+
sigset_t set;
344+
sigemptyset(&set);
345+
sigaddset(&set, suspendSignal);
346+
sigaddset(&set, resumeSignal);
347+
348+
auto sigmask = pthread_sigmask(SIG_UNBLOCK, &set, null);
349+
assert(sigmask == 0, "failed to unblock GC signals");
350+
}
351+
}

0 commit comments

Comments
 (0)