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

Code before:
}

JL_DLLEXPORT int jl_repl_raise_sigtstp(void)
{
    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;

Review comment (suggestion):
```suggestion
#         define membarrier(...) (errno = ENOSYS; -1)
```

Code after:
}

JL_DLLEXPORT int jl_repl_raise_sigtstp(void)
{
    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);