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

Code before:
        if (membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0) == 0) {
            // working
            jl_atomic_store_relaxed(&membarrier_impl, MEMBARRIER_IMPLEMENTATION_SYS_MEMBARRIER);
            return MEMBARRIER_IMPLEMENTATION_SYS_MEMBARRIER;
        }
    }
    jl_init_mprotect_membarrier();
    jl_atomic_store_relaxed(&membarrier_impl, MEMBARRIER_IMPLEMENTATION_MPROTECT);
    return MEMBARRIER_IMPLEMENTATION_MPROTECT;
}

JL_DLLEXPORT void jl_membarrier(void) {
    enum membarrier_implementation impl = jl_atomic_load_relaxed(&membarrier_impl);
    if (impl == MEMBARRIER_IMPLEMENTATION_UNKNOWN) {
        impl = jl_init_membarrier();
    }
    if (impl == MEMBARRIER_IMPLEMENTATION_SYS_MEMBARRIER) {
        int ret = membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED, 0);
        assert(ret);
        (void)ret;
    } else {
        assert(impl == MEMBARRIER_IMPLEMENTATION_MPROTECT);
        jl_mprotect_membarrier();
    }
}
#endif


Review comment (performance):
Claude: 
  2. Missing jl_membarrier for non-Linux/FreeBSD Unix (signals-unix.c)
  The jl_membarrier function is only defined inside the `#if defined(_OS_LINUX_) || defined(_OS_FREEBSD_)` block. Other Unix systems (like OpenBSD, NetBSD, Solaris) will have a
   missing symbol at link time.

```suggestion
#else
JL_DLLEXPORT void jl_membarrier(void) {
    jl_mprotect_membarrier();
}
#endif
```
(and move `jl_mprotect_membarrier` implementation)

Alternatively, we could use our existing default-sound implementation instead of the default-unsound one:
```
JL_DLLEXPORT void jl_membarrier(void)
{
    bt_context_t signal_context;
    for (int tid = 0; tid < jl_atomic_load_acquire(&jl_n_threads); tid++) {
        while (!jl_thread_suspend(tid, &signal_context)) { // work to try to interrupt for up to 1 second each iteration
            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
                if (++tid >= jl_atomic_load_acquire(&jl_n_threads))
                    return;
            }
        }
        jl_thread_resume(tid, &signal_context));
    }
}
```

(we could even have fun and optimize that similar to the kernel implementation, since we might not care about threads in certain `gc_state` (as they have already done a barrier) or threads with `sleep_check_state != not_sleeping`, but there isn't all that much point to that)

Code after:

// Linux and FreeBSD have compatible membarrier syscall support
#if defined(_OS_LINUX_)
#   include <sys/syscall.h>
#   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__)
#    define HAVE_MEMBARRIER_SYSCALL
#  else
#    warning "Missing linux kernel headers for membarrier syscall, support disabled"
#  endif
#elif defined(_OS_FREEBSD_)
#  include <sys/param.h>
#  if __FreeBSD_version >= 1401500
#    include <sys/membarrier.h>
#    define HAVE_MEMBARRIER_SYSCALL
#  endif
#endif

static enum membarrier_implementation jl_init_membarrier(void) {
#ifdef HAVE_MEMBARRIER_SYSCALL
    int ret = membarrier(MEMBARRIER_CMD_QUERY, 0);
    int needed = MEMBARRIER_CMD_PRIVATE_EXPEDITED | MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED;
    if (ret > 0 && ((ret & needed) == needed)) {
        // supported
        if (membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0) == 0) {
            // working
            jl_atomic_store_relaxed(&membarrier_impl, MEMBARRIER_IMPLEMENTATION_SYS_MEMBARRIER);
            return MEMBARRIER_IMPLEMENTATION_SYS_MEMBARRIER;
        }
    }
#endif
    // The mprotect fallback is known not to work on AArch64, so skip it there
#if !defined(_CPU_AARCH64_) && !defined(_CPU_ARM_)
    if (jl_init_mprotect_membarrier()) {
        jl_atomic_store_relaxed(&membarrier_impl, MEMBARRIER_IMPLEMENTATION_MPROTECT);
        return MEMBARRIER_IMPLEMENTATION_MPROTECT;
    }
#endif
    // Fall back to thread suspension (sound but slow)
    jl_atomic_store_relaxed(&membarrier_impl, MEMBARRIER_IMPLEMENTATION_THREAD_SUSPEND);
    return MEMBARRIER_IMPLEMENTATION_THREAD_SUSPEND;
}

JL_DLLEXPORT void jl_membarrier(void) {
    enum membarrier_implementation impl = jl_atomic_load_relaxed(&membarrier_impl);
    if (impl == MEMBARRIER_IMPLEMENTATION_UNKNOWN) {