From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Tyler Veness Date: Thu, 13 Jul 2023 22:13:47 -0700 Subject: [PATCH 6/9] Use C++ atomics --- src/unix/async.c | 25 +++++++++++++------------ src/unix/core.c | 3 ++- src/unix/fs.c | 33 +++++++++++++++++---------------- src/unix/kqueue.c | 10 ++++++---- src/unix/linux.c | 45 +++++++++++++++++++++++---------------------- src/unix/tty.c | 5 +++-- src/uv-common.c | 2 +- src/uv-common.h | 8 +++----- 8 files changed, 68 insertions(+), 63 deletions(-) diff --git a/src/unix/async.c b/src/unix/async.c index 0ff2669e30a628dbb2df9e28ba14b38cf14114e5..fef4ae93343edc0341179a1c4739dcd831ef6e26 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -26,7 +26,6 @@ #include "internal.h" #include -#include #include /* snprintf() */ #include #include @@ -38,6 +37,8 @@ #include #endif +#include + static void uv__async_send(uv_loop_t* loop); static int uv__async_start(uv_loop_t* loop); static void uv__cpu_relax(void); @@ -63,14 +64,14 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { int uv_async_send(uv_async_t* handle) { - _Atomic int* pending; - _Atomic int* busy; + std::atomic* pending; + std::atomic* busy; - pending = (_Atomic int*) &handle->pending; - busy = (_Atomic int*) &handle->u.fd; + pending = (std::atomic*) &handle->pending; + busy = (std::atomic*) &handle->u.fd; /* Do a cheap read first. */ - if (atomic_load_explicit(pending, memory_order_relaxed) != 0) + if (atomic_load_explicit(pending, std::memory_order_relaxed) != 0) return 0; /* Set the loop to busy. */ @@ -90,12 +91,12 @@ int uv_async_send(uv_async_t* handle) { /* Wait for the busy flag to clear before closing. * Only call this from the event loop thread. */ static void uv__async_spin(uv_async_t* handle) { - _Atomic int* pending; - _Atomic int* busy; + std::atomic* pending; + std::atomic* busy; int i; - pending = (_Atomic int*) &handle->pending; - busy = (_Atomic int*) &handle->u.fd; + pending = (std::atomic*) &handle->pending; + busy = (std::atomic*) &handle->u.fd; /* Set the pending flag first, so no new events will be added by other * threads after this function returns. */ @@ -135,7 +136,7 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { struct uv__queue queue; struct uv__queue* q; uv_async_t* h; - _Atomic int *pending; + std::atomic *pending; assert(w == &loop->async_io_watcher); @@ -166,7 +167,7 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { uv__queue_insert_tail(&loop->async_handles, q); /* Atomically fetch and clear pending flag */ - pending = (_Atomic int*) &h->pending; + pending = (std::atomic*) &h->pending; if (atomic_exchange(pending, 0) == 0) continue; diff --git a/src/unix/core.c b/src/unix/core.c index 18f0ce06336e4b3690f84d95b4be954a4466cdf6..c1cc4691439580160cfdda35a01b8e940e4d270b 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -45,6 +45,7 @@ #include #include #include /* clock_gettime */ +#include #ifdef __sun # include @@ -274,7 +275,7 @@ int uv__getiovmax(void) { #if defined(IOV_MAX) return IOV_MAX; #elif defined(_SC_IOV_MAX) - static _Atomic int iovmax_cached = -1; + static std::atomic iovmax_cached = -1; int iovmax; iovmax = atomic_load_explicit(&iovmax_cached, memory_order_relaxed); diff --git a/src/unix/fs.c b/src/unix/fs.c index efd37d78d9216de6ad46633a953f6b292b4af735..6a2e64cb33f004350bee89f28345667d095e1bb5 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include @@ -46,6 +45,8 @@ #include #include +#include + #if defined(__linux__) # include #endif @@ -299,7 +300,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) { static uv_once_t once = UV_ONCE_INIT; int r; #ifdef O_CLOEXEC - static _Atomic int no_cloexec_support; + static std::atomic no_cloexec_support; #endif static const char pattern[] = "XXXXXX"; static const size_t pattern_size = sizeof(pattern) - 1; @@ -324,7 +325,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) { uv_once(&once, uv__mkostemp_initonce); #ifdef O_CLOEXEC - if (atomic_load_explicit(&no_cloexec_support, memory_order_relaxed) == 0 && + if (atomic_load_explicit(&no_cloexec_support, std::memory_order_relaxed) == 0 && uv__mkostemp != NULL) { r = uv__mkostemp(path, O_CLOEXEC); @@ -338,7 +339,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. */ - atomic_store_explicit(&no_cloexec_support, 1, memory_order_relaxed); + atomic_store_explicit(&no_cloexec_support, 1, std::memory_order_relaxed); } #endif /* O_CLOEXEC */ @@ -459,7 +460,7 @@ static ssize_t uv__pwritev_emul(int fd, } -/* The function pointer cache is an uintptr_t because _Atomic void* +/* The function pointer cache is an uintptr_t because std::atomic* * doesn't work on macos/ios/etc... * Disable optimization on armv7 to work around the bug described in * https://github.com/libuv/libuv/issues/4532 @@ -471,12 +472,12 @@ static ssize_t uv__preadv_or_pwritev(int fd, const struct iovec* bufs, size_t nbufs, off_t off, - _Atomic uintptr_t* cache, + std::atomic* cache, int is_pread) { ssize_t (*f)(int, const struct iovec*, uv__iovcnt, off_t); void* p; - p = (void*) atomic_load_explicit(cache, memory_order_relaxed); + p = (void*) atomic_load_explicit(cache, std::memory_order_relaxed); if (p == NULL) { #ifdef RTLD_DEFAULT p = dlsym(RTLD_DEFAULT, is_pread ? "preadv" : "pwritev"); @@ -484,7 +485,7 @@ static ssize_t uv__preadv_or_pwritev(int fd, #endif /* RTLD_DEFAULT */ if (p == NULL) p = (void*)(is_pread ? uv__preadv_emul : uv__pwritev_emul); - atomic_store_explicit(cache, (uintptr_t) p, memory_order_relaxed); + atomic_store_explicit(cache, (uintptr_t) p, std::memory_order_relaxed); } /* Use memcpy instead of `f = p` to work around a compiler bug, @@ -499,7 +500,7 @@ static ssize_t uv__preadv(int fd, const struct iovec* bufs, size_t nbufs, off_t off) { - static _Atomic uintptr_t cache; + static std::atomic cache; return uv__preadv_or_pwritev(fd, bufs, nbufs, off, &cache, /*is_pread*/1); } @@ -508,7 +509,7 @@ static ssize_t uv__pwritev(int fd, const struct iovec* bufs, size_t nbufs, off_t off) { - static _Atomic uintptr_t cache; + static std::atomic cache; return uv__preadv_or_pwritev(fd, bufs, nbufs, off, &cache, /*is_pread*/0); } @@ -985,10 +986,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 _Atomic int no_copy_file_range_support; + static std::atomic no_copy_file_range_support; ssize_t r; - if (atomic_load_explicit(&no_copy_file_range_support, memory_order_relaxed)) { + if (atomic_load_explicit(&no_copy_file_range_support, std::memory_order_relaxed)) { errno = ENOSYS; return -1; } @@ -1007,7 +1008,7 @@ static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off, errno = ENOSYS; /* Use fallback. */ break; case ENOSYS: - atomic_store_explicit(&no_copy_file_range_support, 1, memory_order_relaxed); + atomic_store_explicit(&no_copy_file_range_support, 1, std::memory_order_relaxed); break; case EPERM: /* It's been reported that CIFS spuriously fails. @@ -1531,14 +1532,14 @@ static int uv__fs_statx(int fd, uv_stat_t* buf) { STATIC_ASSERT(UV_ENOSYS != -1); #ifdef __linux__ - static _Atomic int no_statx; + static std::atomic no_statx; struct uv__statx statxbuf; int dirfd; int flags; int mode; int rc; - if (atomic_load_explicit(&no_statx, memory_order_relaxed)) + if (atomic_load_explicit(&no_statx, std::memory_order_relaxed)) return UV_ENOSYS; dirfd = AT_FDCWD; @@ -1572,7 +1573,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. */ - atomic_store_explicit(&no_statx, 1, memory_order_relaxed); + atomic_store_explicit(&no_statx, 1, std::memory_order_relaxed); return UV_ENOSYS; } diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index b7bd00ea0c45964d8e26d7596d9ad3734fe67237..8676a6340d7047585e230138ac130b591c164e4e 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -37,6 +37,8 @@ #include #include +#include + /* * Required on * - Until at least FreeBSD 11.0 @@ -63,7 +65,7 @@ int uv__kqueue_init(uv_loop_t* loop) { #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 -static _Atomic int uv__has_forked_with_cfrunloop; +static std::atomic uv__has_forked_with_cfrunloop; #endif int uv__io_fork(uv_loop_t* loop) { @@ -87,7 +89,7 @@ int uv__io_fork(uv_loop_t* loop) { */ atomic_store_explicit(&uv__has_forked_with_cfrunloop, 1, - memory_order_relaxed); + std::memory_order_relaxed); uv__free(loop->cf_state); loop->cf_state = NULL; } @@ -598,7 +600,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, goto fallback; if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop, - memory_order_relaxed)) { + std::memory_order_relaxed)) { int r; /* The fallback fd is no longer needed */ uv__close_nocheckstdio(fd); @@ -634,7 +636,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop, - memory_order_relaxed)) + std::memory_order_relaxed)) if (handle->cf_cb != NULL) r = uv__fsevents_close(handle); #endif diff --git a/src/unix/linux.c b/src/unix/linux.c index b8063cc8900d4cf255a46a9620d01815c65c6d21..25b93ba43b98874d658d58e3faab12049f6e4edf 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -27,7 +27,6 @@ #include "internal.h" #include -#include #include /* offsetof */ #include #include @@ -124,6 +123,8 @@ # endif #endif /* __NR_getrandom */ +#include + enum { UV__IORING_SETUP_SQPOLL = 2u, UV__IORING_SETUP_NO_SQARRAY = 0x10000u, @@ -300,7 +301,7 @@ static struct watcher_root* uv__inotify_watchers(uv_loop_t* loop) { unsigned uv__kernel_version(void) { - static _Atomic unsigned cached_version; + static std::atomic cached_version; struct utsname u; unsigned version; unsigned major; @@ -309,7 +310,7 @@ unsigned uv__kernel_version(void) { char v_sig[256]; char* needle; - version = atomic_load_explicit(&cached_version, memory_order_relaxed); + version = std::atomic_load_explicit(&cached_version, std::memory_order_relaxed); if (version != 0) return version; @@ -365,7 +366,7 @@ unsigned uv__kernel_version(void) { calculate_version: version = major * 65536 + minor * 256 + patch; - atomic_store_explicit(&cached_version, version, memory_order_relaxed); + std::atomic_store_explicit(&cached_version, version, std::memory_order_relaxed); return version; } @@ -466,11 +467,11 @@ static int uv__use_io_uring(void) { return 0; /* Random SIGSEGV in signal handler. */ #else /* Ternary: unknown=0, yes=1, no=-1 */ - static _Atomic int use_io_uring; + static std::atomic use_io_uring; char* val; int use; - use = atomic_load_explicit(&use_io_uring, memory_order_relaxed); + use = std::atomic_load_explicit(&use_io_uring, std::memory_order_relaxed); if (use == 0) { use = uv__kernel_version() >= @@ -489,7 +490,7 @@ static int uv__use_io_uring(void) { if (val != NULL) use = atoi(val) ? 1 : -1; - atomic_store_explicit(&use_io_uring, use, memory_order_relaxed); + std::atomic_store_explicit(&use_io_uring, use, std::memory_order_relaxed); } return use > 0; @@ -781,8 +782,8 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou, if (iou->ringfd == -1) return NULL; - head = atomic_load_explicit((_Atomic uint32_t*) iou->sqhead, - memory_order_acquire); + head = std::atomic_load_explicit((std::atomic*) iou->sqhead, + std::memory_order_acquire); tail = *iou->sqtail; mask = iou->sqmask; @@ -811,12 +812,12 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou, static void uv__iou_submit(struct uv__iou* iou) { uint32_t flags; - atomic_store_explicit((_Atomic uint32_t*) iou->sqtail, + std::atomic_store_explicit((std::atomic*) iou->sqtail, *iou->sqtail + 1, - memory_order_release); + std::memory_order_release); - flags = atomic_load_explicit((_Atomic uint32_t*) iou->sqflags, - memory_order_acquire); + flags = std::atomic_load_explicit((std::atomic*) iou->sqflags, + std::memory_order_acquire); if (flags & UV__IORING_SQ_NEED_WAKEUP) if (uv__io_uring_enter(iou->ringfd, 0, 0, UV__IORING_ENTER_SQ_WAKEUP)) @@ -1174,8 +1175,8 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) { int rc; head = *iou->cqhead; - tail = atomic_load_explicit((_Atomic uint32_t*) iou->cqtail, - memory_order_acquire); + tail = std::atomic_load_explicit((std::atomic*) iou->cqtail, + std::memory_order_acquire); mask = iou->cqmask; cqe = (uv__io_uring_cqe*)iou->cqe; nevents = 0; @@ -1213,15 +1214,15 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) { nevents++; } - atomic_store_explicit((_Atomic uint32_t*) iou->cqhead, + std::atomic_store_explicit((std::atomic*) iou->cqhead, tail, - memory_order_release); + std::memory_order_release); /* Check whether CQE's overflowed, if so enter the kernel to make them * available. Don't grab them immediately but in the next loop iteration to * avoid loop starvation. */ - flags = atomic_load_explicit((_Atomic uint32_t*) iou->sqflags, - memory_order_acquire); + flags = std::atomic_load_explicit((std::atomic*) iou->sqflags, + std::memory_order_acquire); if (flags & UV__IORING_SQ_CQ_OVERFLOW) { do @@ -1619,7 +1620,7 @@ update_timeout: } uint64_t uv__hrtime(uv_clocktype_t type) { - static _Atomic clock_t fast_clock_id = -1; + static std::atomic fast_clock_id = -1; struct timespec t; clock_t clock_id; @@ -1635,7 +1636,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) { if (type != UV_CLOCK_FAST) goto done; - clock_id = atomic_load_explicit(&fast_clock_id, memory_order_relaxed); + clock_id = std::atomic_load_explicit(&fast_clock_id, std::memory_order_relaxed); if (clock_id != -1) goto done; @@ -1644,7 +1645,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) { if (t.tv_nsec <= 1 * 1000 * 1000) clock_id = CLOCK_MONOTONIC_COARSE; - atomic_store_explicit(&fast_clock_id, clock_id, memory_order_relaxed); + std::atomic_store_explicit(&fast_clock_id, clock_id, std::memory_order_relaxed); done: diff --git a/src/unix/tty.c b/src/unix/tty.c index 699a092da2dea77277557211065f6594bcad4e0b..5ca2105848fc07d312455c336ac7303e61679213 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -22,7 +22,6 @@ #include "uv.h" #include "internal.h" -#include #include #include #include @@ -30,6 +29,8 @@ #include #include +#include + #if defined(__MVS__) && !defined(IMAXBEL) #define IMAXBEL 0 #endif @@ -64,7 +65,7 @@ static int isreallyatty(int file) { static int orig_termios_fd = -1; static struct termios orig_termios; -static _Atomic int termios_spinlock; +static std::atomic termios_spinlock; int uv__tcsetattr(int fd, int how, const struct termios *term) { int rc; diff --git a/src/uv-common.c b/src/uv-common.c index 49126e50f07bac16d198775454b731f40630d1d1..1ce25c24d6c046f7aaeaa52dcfc4fafa5a738650 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -953,7 +953,7 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { __attribute__((destructor)) #endif void uv_library_shutdown(void) { - static int was_shutdown; + static std::atomic was_shutdown; if (uv__exchange_int_relaxed(&was_shutdown, 1)) return; diff --git a/src/uv-common.h b/src/uv-common.h index 4baede2e506ee1787d554a0ec75bc9eb346fc8f2..4978cf0633c2de5fa96bf600a59dfb539cab8201 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -32,15 +32,13 @@ #include #include +#include + #include "uv.h" #include "uv/tree.h" #include "queue.h" #include "strscpy.h" -#ifndef _MSC_VER -# include -#endif - #if EDOM > 0 # define UV__ERR(x) (-(x)) #else @@ -70,7 +68,7 @@ extern int snprintf(char*, size_t, const char*, ...); InterlockedExchangeNoFence((LONG volatile*)(p), v) #else #define uv__exchange_int_relaxed(p, v) \ - atomic_exchange_explicit((_Atomic int*)(p), v, memory_order_relaxed) + std::atomic_exchange_explicit((std::atomic*)(p), v, std::memory_order_relaxed) #endif #define UV__UDP_DGRAM_MAXSIZE (64 * 1024)