diff --git a/druntime/src/core/internal/gc/impl/conservative/gc.d b/druntime/src/core/internal/gc/impl/conservative/gc.d index 591e0dc9dc87..322486e2082b 100644 --- a/druntime/src/core/internal/gc/impl/conservative/gc.d +++ b/druntime/src/core/internal/gc/impl/conservative/gc.d @@ -3495,30 +3495,10 @@ Lmark: __gshared bool fork_needs_lock = true; // racing condition with cocurrent calls of fork? - // The GC signals might be blocked by `fork` when the atfork prepare - // handler is invoked. This guards us from the scenario where we are - // waiting for a GC action in another thread to complete, and that thread - // decides to call thread_suspendAll, then we must be able to response to - // that request, otherwise we end up in a deadlock situation. - private static void unblockGCSignals() nothrow @nogc - { - import core.sys.posix.signal : pthread_sigmask, sigaddset, sigemptyset, sigset_t, SIG_UNBLOCK; - - int suspendSignal = void, resumeSignal = void; - thread_getGCSignals(suspendSignal, resumeSignal); - - sigset_t set; - sigemptyset(&set); - sigaddset(&set, suspendSignal); - sigaddset(&set, resumeSignal); - - auto sigmask = pthread_sigmask(SIG_UNBLOCK, &set, null); - assert(sigmask == 0, "failed to unblock GC signals"); - } - extern(C) static void _d_gcx_atfork_prepare() { - unblockGCSignals(); + static if (__traits(compiles, os_unblock_gc_signals)) + os_unblock_gc_signals(); if (instance && fork_needs_lock) ConservativeGC.lockNR(); diff --git a/druntime/src/core/internal/gc/os.d b/druntime/src/core/internal/gc/os.d index 291aee535bc6..a301664d34be 100644 --- a/druntime/src/core/internal/gc/os.d +++ b/druntime/src/core/internal/gc/os.d @@ -85,6 +85,13 @@ else version (Posix) return ChildStatus.done; } + version (DragonFlyBSD) + version = GCSignalsUnblock; + version (FreeBSD) + version = GCSignalsUnblock; + version (Solaris) + version = GCSignalsUnblock; + //version = GC_Use_Alloc_MMap; } else @@ -315,3 +322,30 @@ else version (Posix) return pageSize * pages; } } + +/** + The GC signals might be blocked by `fork` when the atfork prepare + handler is invoked. This guards us from the scenario where we are + waiting for a GC action in another thread to complete, and that thread + decides to call thread_suspendAll, then we must be able to response to + that request, otherwise we end up in a deadlock situation. + */ +version (GCSignalsUnblock) +{ + void os_unblock_gc_signals() nothrow @nogc + { + import core.sys.posix.signal : pthread_sigmask, sigaddset, sigemptyset, sigset_t, SIG_UNBLOCK; + import core.thread : thread_getGCSignals; + + int suspendSignal = void, resumeSignal = void; + thread_getGCSignals(suspendSignal, resumeSignal); + + sigset_t set; + sigemptyset(&set); + sigaddset(&set, suspendSignal); + sigaddset(&set, resumeSignal); + + auto sigmask = pthread_sigmask(SIG_UNBLOCK, &set, null); + assert(sigmask == 0, "failed to unblock GC signals"); + } +}