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

Code before:

// 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);
    if (mprotect_barrier_page == NULL) {
        size_t pagesize = jl_getpagesize();

        mprotect_barrier_page = (_Atomic(uint64_t) *)
                                     mmap(NULL, pagesize, PROT_NONE,
                                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        if (mprotect_barrier_page == MAP_FAILED) {
            jl_safe_printf("fatal: failed to allocate barrier page.\n");
            abort();
        }
        result = mlock(mprotect_barrier_page, pagesize);
        if (result != 0) {
            jl_safe_printf("fatal: failed to mlock barrier page.\n");
            abort();
        }
    }
    result = pthread_mutex_unlock(&mprotect_barrier_lock);
    assert(result == 0);
    (void)result;
}

static void jl_mprotect_membarrier(void)
{
    int result = pthread_mutex_lock(&mprotect_barrier_lock);
    assert(result == 0);
    size_t pagesize = jl_getpagesize();
    result = mprotect(mprotect_barrier_page, pagesize, PROT_NONE);
    jl_atomic_fetch_add_relaxed(mprotect_barrier_page, 1);
    assert(result == 0);
    result = mprotect(mprotect_barrier_page, pagesize, PROT_READ | PROT_WRITE);
    assert(result == 0);
    result = pthread_mutex_unlock(&mprotect_barrier_lock);
    assert(result == 0);
    (void)result;
}

// Implementation of `jl_membarrier`
enum membarrier_implementation {

Review comment (bug):
```suggestion
            jl_safe_printf("fatal: failed to mlock barrier page (try increasing RLIMIT_MEMLOCK with `ulimit -l`).\n");
```

Code after:
// 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();

        mprotect_barrier_page = (_Atomic(uint64_t) *)
                                     mmap(NULL, pagesize, PROT_READ | PROT_WRITE,
                                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        if (mprotect_barrier_page == MAP_FAILED) {
            mprotect_barrier_page = NULL;
            result = pthread_mutex_unlock(&mprotect_barrier_lock);
            assert(result == 0);
            return 0;
        }
        result = mlock(mprotect_barrier_page, pagesize);
        if (result != 0) {
            // mlock failed (e.g. RLIMIT_MEMLOCK too low), fall back to thread suspension
            munmap(mprotect_barrier_page, pagesize);
            mprotect_barrier_page = NULL;
            result = pthread_mutex_unlock(&mprotect_barrier_lock);
            assert(result == 0);
            return 0;
        }
    }
    result = pthread_mutex_unlock(&mprotect_barrier_lock);
    assert(result == 0);
    (void)result;
    return 1;
}

static void jl_mprotect_membarrier(void)
{
    int result = pthread_mutex_lock(&mprotect_barrier_lock);
    assert(result == 0);
    size_t pagesize = jl_getpagesize();
    result = mprotect(mprotect_barrier_page, pagesize, PROT_READ | PROT_WRITE);
    jl_atomic_fetch_add_relaxed(mprotect_barrier_page, 1);
    assert(result == 0);
    result = mprotect(mprotect_barrier_page, pagesize, PROT_NONE);
    assert(result == 0);
    result = pthread_mutex_unlock(&mprotect_barrier_lock);
    assert(result == 0);
    (void)result;