src: switch to use C11 atomics where available (#3950)

Switch all code in unix/ to use C11 atomics directly.

Change uv_library_shutdown() to use an exchange instead of load/store.

Unfortunately MSVC only started supporting C11 atomics in VS2022 version
17.5 Preview 2 as experimental. So resort to using the Interlocked API.

Ref: https://devblogs.microsoft.com/cppblog/c11-atomics-in-visual-studio-2022-version-17-5-preview-2/
Fixes: https://github.com/libuv/libuv/issues/3948
This commit is contained in:
Trevor Norris 2023-04-12 13:54:22 -06:00 committed by GitHub
parent e189c31375
commit 2f33980a91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 40 additions and 32 deletions

View File

@ -233,10 +233,10 @@ int uv__getiovmax(void) {
#if defined(IOV_MAX)
return IOV_MAX;
#elif defined(_SC_IOV_MAX)
static int iovmax_cached = -1;
static _Atomic int iovmax_cached = -1;
int iovmax;
iovmax = uv__load_relaxed(&iovmax_cached);
iovmax = atomic_load_explicit(&iovmax_cached, memory_order_relaxed);
if (iovmax != -1)
return iovmax;
@ -248,7 +248,7 @@ int uv__getiovmax(void) {
if (iovmax == -1)
iovmax = 1;
uv__store_relaxed(&iovmax_cached, iovmax);
atomic_store_explicit(&iovmax_cached, iovmax, memory_order_relaxed);
return iovmax;
#else

View File

@ -309,7 +309,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
static uv_once_t once = UV_ONCE_INIT;
int r;
#ifdef O_CLOEXEC
static int no_cloexec_support;
static _Atomic int no_cloexec_support;
#endif
static const char pattern[] = "XXXXXX";
static const size_t pattern_size = sizeof(pattern) - 1;
@ -334,7 +334,8 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
uv_once(&once, uv__mkostemp_initonce);
#ifdef O_CLOEXEC
if (uv__load_relaxed(&no_cloexec_support) == 0 && uv__mkostemp != NULL) {
if (atomic_load_explicit(&no_cloexec_support, memory_order_relaxed) == 0 &&
uv__mkostemp != NULL) {
r = uv__mkostemp(path, O_CLOEXEC);
if (r >= 0)
@ -347,7 +348,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
/* We set the static variable so that next calls don't even
try to use mkostemp. */
uv__store_relaxed(&no_cloexec_support, 1);
atomic_store_explicit(&no_cloexec_support, 1, memory_order_relaxed);
}
#endif /* O_CLOEXEC */
@ -457,7 +458,7 @@ static ssize_t uv__fs_preadv(uv_file fd,
static ssize_t uv__fs_read(uv_fs_t* req) {
#if defined(__linux__)
static int no_preadv;
static _Atomic int no_preadv;
#endif
unsigned int iovmax;
ssize_t result;
@ -481,7 +482,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
#else
# if defined(__linux__)
if (uv__load_relaxed(&no_preadv)) retry:
if (atomic_load_explicit(&no_preadv, memory_order_relaxed)) retry:
# endif
{
result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off);
@ -493,7 +494,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
req->nbufs,
req->off);
if (result == -1 && errno == ENOSYS) {
uv__store_relaxed(&no_preadv, 1);
atomic_store_explicit(&no_preadv, 1, memory_order_relaxed);
goto retry;
}
}
@ -899,14 +900,14 @@ out:
#ifdef __linux__
static unsigned uv__kernel_version(void) {
static unsigned cached_version;
static _Atomic unsigned cached_version;
struct utsname u;
unsigned version;
unsigned major;
unsigned minor;
unsigned patch;
version = uv__load_relaxed(&cached_version);
version = atomic_load_explicit(&cached_version, memory_order_relaxed);
if (version != 0)
return version;
@ -917,7 +918,7 @@ static unsigned uv__kernel_version(void) {
return 0;
version = major * 65536 + minor * 256 + patch;
uv__store_relaxed(&cached_version, version);
atomic_store_explicit(&cached_version, version, memory_order_relaxed);
return version;
}
@ -959,10 +960,10 @@ static int uv__is_cifs_or_smb(int fd) {
static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off,
int out_fd, size_t len) {
static int no_copy_file_range_support;
static _Atomic int no_copy_file_range_support;
ssize_t r;
if (uv__load_relaxed(&no_copy_file_range_support)) {
if (atomic_load_explicit(&no_copy_file_range_support, memory_order_relaxed)) {
errno = ENOSYS;
return -1;
}
@ -981,7 +982,7 @@ static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off,
errno = ENOSYS; /* Use fallback. */
break;
case ENOSYS:
uv__store_relaxed(&no_copy_file_range_support, 1);
atomic_store_explicit(&no_copy_file_range_support, 1, memory_order_relaxed);
break;
case EPERM:
/* It's been reported that CIFS spuriously fails.
@ -1530,14 +1531,14 @@ static int uv__fs_statx(int fd,
uv_stat_t* buf) {
STATIC_ASSERT(UV_ENOSYS != -1);
#ifdef __linux__
static int no_statx;
static _Atomic int no_statx;
struct uv__statx statxbuf;
int dirfd;
int flags;
int mode;
int rc;
if (uv__load_relaxed(&no_statx))
if (atomic_load_explicit(&no_statx, memory_order_relaxed))
return UV_ENOSYS;
dirfd = AT_FDCWD;
@ -1571,7 +1572,7 @@ static int uv__fs_statx(int fd,
* implemented, rc might return 1 with 0 set as the error code in which
* case we return ENOSYS.
*/
uv__store_relaxed(&no_statx, 1);
atomic_store_explicit(&no_statx, 1, memory_order_relaxed);
return UV_ENOSYS;
}

View File

@ -60,7 +60,7 @@ int uv__kqueue_init(uv_loop_t* loop) {
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
static int uv__has_forked_with_cfrunloop;
static _Atomic int uv__has_forked_with_cfrunloop;
#endif
int uv__io_fork(uv_loop_t* loop) {
@ -82,7 +82,9 @@ int uv__io_fork(uv_loop_t* loop) {
process. So we sidestep the issue by pretending like we never
started it in the first place.
*/
uv__store_relaxed(&uv__has_forked_with_cfrunloop, 1);
atomic_store_explicit(&uv__has_forked_with_cfrunloop,
1,
memory_order_relaxed);
uv__free(loop->cf_state);
loop->cf_state = NULL;
}
@ -530,7 +532,8 @@ int uv_fs_event_start(uv_fs_event_t* handle,
if (!(statbuf.st_mode & S_IFDIR))
goto fallback;
if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop)) {
if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop,
memory_order_relaxed)) {
int r;
/* The fallback fd is no longer needed */
uv__close_nocheckstdio(fd);
@ -565,7 +568,8 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
uv__handle_stop(handle);
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop))
if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop,
memory_order_relaxed))
if (handle->cf_cb != NULL)
r = uv__fsevents_close(handle);
#endif

View File

@ -579,7 +579,7 @@ update_timeout:
}
uint64_t uv__hrtime(uv_clocktype_t type) {
static clock_t fast_clock_id = -1;
static _Atomic clock_t fast_clock_id = -1;
struct timespec t;
clock_t clock_id;
@ -595,7 +595,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
if (type != UV_CLOCK_FAST)
goto done;
clock_id = uv__load_relaxed(&fast_clock_id);
clock_id = atomic_load_explicit(&fast_clock_id, memory_order_relaxed);
if (clock_id != -1)
goto done;
@ -604,7 +604,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
if (t.tv_nsec <= 1 * 1000 * 1000)
clock_id = CLOCK_MONOTONIC_COARSE;
uv__store_relaxed(&fast_clock_id, clock_id);
atomic_store_explicit(&fast_clock_id, clock_id, memory_order_relaxed);
done:

View File

@ -944,7 +944,7 @@ __attribute__((destructor))
void uv_library_shutdown(void) {
static int was_shutdown;
if (uv__load_relaxed(&was_shutdown))
if (uv__exchange_int_relaxed(&was_shutdown, 1))
return;
uv__process_title_cleanup();
@ -955,7 +955,6 @@ void uv_library_shutdown(void) {
#else
uv__threadpool_cleanup();
#endif
uv__store_relaxed(&was_shutdown, 1);
}

View File

@ -37,6 +37,10 @@
#include "queue.h"
#include "strscpy.h"
#ifndef _MSC_VER
# include <stdatomic.h>
#endif
#if EDOM > 0
# define UV__ERR(x) (-(x))
#else
@ -61,12 +65,12 @@ extern int snprintf(char*, size_t, const char*, ...);
void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)])
#endif
#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 7)
#define uv__load_relaxed(p) __atomic_load_n(p, __ATOMIC_RELAXED)
#define uv__store_relaxed(p, v) __atomic_store_n(p, v, __ATOMIC_RELAXED)
#ifdef _MSC_VER
#define uv__exchange_int_relaxed(p, v) \
InterlockedExchangeNoFence((LONG volatile*)(p), v)
#else
#define uv__load_relaxed(p) (*p)
#define uv__store_relaxed(p, v) do *p = v; while (0)
#define uv__exchange_int_relaxed(p, v) \
atomic_exchange_explicit((_Atomic int*)(p), v, memory_order_relaxed)
#endif
#define UV__UDP_DGRAM_MAXSIZE (64 * 1024)