Repository: JuliaLang/julia
File: src/signals-unix.c (C)

Code before:
    return raise(SIGTSTP);
}

// Linux and FreeBSD have compatible membarrier support
#if defined(_OS_LINUX_) || defined(_OS_FREEBSD_)
#if defined(_OS_LINUX_)
# include <sys/syscall.h>
# if defined(__has_include)
#   if __has_include(<linux/membarrier.h>)
#       include <linux/membarrier.h>
#       define membarrier(...) syscall(__NR_membarrier, __VA_ARGS__)
#   else
#     if defined(__NR_membarrier)
enum membarrier_cmd {
    MEMBARRIER_CMD_QUERY                        = 0,
    MEMBARRIER_CMD_PRIVATE_EXPEDITED            = (1 << 3),
    MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED   = (1 << 4),
};
#         define membarrier(...) syscall(__NR_membarrier, __VA_ARGS__)
#     else
#         warning "Missing linux kernel headers for membarrier syscall, support disabled"
#         define membarrier(...) -ENOSYS
#     endif
#  endif
# else
#   include <linux/membarrier.h>
# endif
#elif defined(_OS_FREEBSD_)
# include <sys/param.h>
# if __FreeBSD_version >= 1401500
#   include <sys/membarrier.h>
# else
#   define MEMBARRIER_CMD_QUERY                         0x00
#   define MEMBARRIER_CMD_PRIVATE_EXPEDITED             0x08
#   define MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED    0x10
#   define membarrier(...) -ENOSYS
# endif
#endif

// Implementation of the `mprotect` based membarrier fallback.
// This is a common fallback based on the observation that `mprotect` happens to
// issue the necessary memory barriers. However, there is no spec that
// guarantees this behavior, and indeed AArch64 macos does not. However, we
// only use it as a fallback here for older versions of Linux and FreeBSD where
// we know that it happens to work.
static pthread_mutex_t mprotect_barrier_lock = PTHREAD_MUTEX_INITIALIZER;
static _Atomic(uint64_t) *mprotect_barrier_page = NULL;
static void jl_init_mprotect_membarrier(void)
{
    int result = pthread_mutex_lock(&mprotect_barrier_lock);
    assert(result == 0);

Review comment (refactor):
Should we simplify this to always take the `if defined(__NR_membarrier)` path? It looks slightly odd that if `__has_include` isn't defined, then we just assume the header is available instead of defining it always in this file

For the most part (similar to libuv policy), we should try to limit how often we do compile time checks, instead of defining the values such that we can do runtime checks

Code after:
    return raise(SIGTSTP);
}

#if !defined(_OS_DARWIN_)
// Thread suspension based membarrier fallback.
// This is a sound but slow implementation that suspends and resumes each thread
// to force them to execute memory barriers via the signal handling mechanism.
// This is used as a fallback when neither the membarrier syscall nor the mprotect
// hack are available or working.
static void jl_thread_suspend_membarrier(void)
{
    bt_context_t ctx;
    // Suspend each thread and immediately resume it.
    // The act of suspending/resuming forces a memory barrier via
    // the signal handler mechanism.
    // jl_thread_suspend tries to interrupt the thread for up to 1 second,
    // so we retry in a loop until it succeeds or we determine the thread
    // is no longer alive.
    for (int tid = 0; tid < jl_atomic_load_acquire(&jl_n_threads); tid++) {
        while (!jl_thread_suspend(tid, &ctx)) {
            jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid];
            jl_task_t *ct2 = ptls2 ? jl_atomic_load_relaxed(&ptls2->current_task) : NULL;
            if (ct2 == NULL) {
                // this thread is not alive or already dead, move to next
                goto next_thread;
            }
            // thread is alive but suspend failed, retry
        }
        jl_thread_resume(tid);
next_thread:;
    }
}

// Implementation of the `mprotect` based membarrier fallback.
// This is a common fallback based on the observation that `mprotect` happens to
// issue the necessary memory barriers. However, there is no spec that
// guarantees this behavior. On AArch64, it is known not to work on either
// Linux or FreeBSD, so we don't use it there. However, we use it as a fallback
// here for older versions of Linux and FreeBSD on x86 where we know that it
// happens to work.
#if !defined(_CPU_AARCH64_) && !defined(_CPU_ARM_)
static pthread_mutex_t mprotect_barrier_lock = PTHREAD_MUTEX_INITIALIZER;
static _Atomic(uint64_t) *mprotect_barrier_page = NULL;
// Returns 1 on success, 0 on failure (e.g. mlock fails)
static int jl_init_mprotect_membarrier(void)
{
    int result = pthread_mutex_lock(&mprotect_barrier_lock);
    assert(result == 0);
    if (mprotect_barrier_page == NULL) {
        size_t pagesize = jl_getpagesize();