blob: ffdc5887f5194372688be538534d6c04d7cab1e0 [file] [log] [blame]
James Kuszmaulb13e13f2023-11-22 20:44:04 -08001From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2From: Tyler Veness <calcmogul@gmail.com>
3Date: Thu, 13 Jul 2023 22:13:47 -0700
4Subject: [PATCH 08/10] Use C++ atomics
5
6---
7 src/unix/async.c | 25 +++++++++++++------------
8 src/unix/core.c | 3 ++-
9 src/unix/fs.c | 32 +++++++++++++++++---------------
10 src/unix/kqueue.c | 10 ++++++----
11 src/unix/linux.c | 45 +++++++++++++++++++++++----------------------
12 src/unix/tty.c | 5 +++--
13 src/uv-common.c | 2 +-
14 src/uv-common.h | 8 +++-----
15 8 files changed, 68 insertions(+), 62 deletions(-)
16
17diff --git a/src/unix/async.c b/src/unix/async.c
18index 0ff2669e30a628dbb2df9e28ba14b38cf14114e5..fef4ae93343edc0341179a1c4739dcd831ef6e26 100644
19--- a/src/unix/async.c
20+++ b/src/unix/async.c
21@@ -26,7 +26,6 @@
22 #include "internal.h"
23
24 #include <errno.h>
25-#include <stdatomic.h>
26 #include <stdio.h> /* snprintf() */
27 #include <assert.h>
28 #include <stdlib.h>
29@@ -38,6 +37,8 @@
30 #include <sys/eventfd.h>
31 #endif
32
33+#include <atomic>
34+
35 static void uv__async_send(uv_loop_t* loop);
36 static int uv__async_start(uv_loop_t* loop);
37 static void uv__cpu_relax(void);
38@@ -63,14 +64,14 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
39
40
41 int uv_async_send(uv_async_t* handle) {
42- _Atomic int* pending;
43- _Atomic int* busy;
44+ std::atomic<int>* pending;
45+ std::atomic<int>* busy;
46
47- pending = (_Atomic int*) &handle->pending;
48- busy = (_Atomic int*) &handle->u.fd;
49+ pending = (std::atomic<int>*) &handle->pending;
50+ busy = (std::atomic<int>*) &handle->u.fd;
51
52 /* Do a cheap read first. */
53- if (atomic_load_explicit(pending, memory_order_relaxed) != 0)
54+ if (atomic_load_explicit(pending, std::memory_order_relaxed) != 0)
55 return 0;
56
57 /* Set the loop to busy. */
58@@ -90,12 +91,12 @@ int uv_async_send(uv_async_t* handle) {
59 /* Wait for the busy flag to clear before closing.
60 * Only call this from the event loop thread. */
61 static void uv__async_spin(uv_async_t* handle) {
62- _Atomic int* pending;
63- _Atomic int* busy;
64+ std::atomic<int>* pending;
65+ std::atomic<int>* busy;
66 int i;
67
68- pending = (_Atomic int*) &handle->pending;
69- busy = (_Atomic int*) &handle->u.fd;
70+ pending = (std::atomic<int>*) &handle->pending;
71+ busy = (std::atomic<int>*) &handle->u.fd;
72
73 /* Set the pending flag first, so no new events will be added by other
74 * threads after this function returns. */
75@@ -135,7 +136,7 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
76 struct uv__queue queue;
77 struct uv__queue* q;
78 uv_async_t* h;
79- _Atomic int *pending;
80+ std::atomic<int> *pending;
81
82 assert(w == &loop->async_io_watcher);
83
84@@ -166,7 +167,7 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
85 uv__queue_insert_tail(&loop->async_handles, q);
86
87 /* Atomically fetch and clear pending flag */
88- pending = (_Atomic int*) &h->pending;
89+ pending = (std::atomic<int>*) &h->pending;
90 if (atomic_exchange(pending, 0) == 0)
91 continue;
92
93diff --git a/src/unix/core.c b/src/unix/core.c
94index f53adc156a7c454c492abaeac29d90be436785fc..ce7fd2cdfdd53410dc694450bd56dffc26ff4792 100644
95--- a/src/unix/core.c
96+++ b/src/unix/core.c
97@@ -45,6 +45,7 @@
98 #include <sys/utsname.h>
99 #include <sys/time.h>
100 #include <time.h> /* clock_gettime */
101+#include <atomic>
102
103 #ifdef __sun
104 # include <sys/filio.h>
105@@ -263,7 +264,7 @@ int uv__getiovmax(void) {
106 #if defined(IOV_MAX)
107 return IOV_MAX;
108 #elif defined(_SC_IOV_MAX)
109- static _Atomic int iovmax_cached = -1;
110+ static std::atomic<int> iovmax_cached = -1;
111 int iovmax;
112
113 iovmax = atomic_load_explicit(&iovmax_cached, memory_order_relaxed);
114diff --git a/src/unix/fs.c b/src/unix/fs.c
115index e25d02e54dbe93e4b9c22b0140108c99ae2cb4f7..aba190a9c0240fba0128fb7fbc5d92d7fa86214b 100644
116--- a/src/unix/fs.c
117+++ b/src/unix/fs.c
118@@ -46,6 +46,8 @@
119 #include <fcntl.h>
120 #include <poll.h>
121
122+#include <atomic>
123+
124 #if defined(__DragonFly__) || \
125 defined(__FreeBSD__) || \
126 defined(__OpenBSD__) || \
127@@ -313,7 +315,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
128 static uv_once_t once = UV_ONCE_INIT;
129 int r;
130 #ifdef O_CLOEXEC
131- static _Atomic int no_cloexec_support;
132+ static std::atomic<int> no_cloexec_support;
133 #endif
134 static const char pattern[] = "XXXXXX";
135 static const size_t pattern_size = sizeof(pattern) - 1;
136@@ -338,7 +340,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
137 uv_once(&once, uv__mkostemp_initonce);
138
139 #ifdef O_CLOEXEC
140- if (atomic_load_explicit(&no_cloexec_support, memory_order_relaxed) == 0 &&
141+ if (atomic_load_explicit(&no_cloexec_support, std::memory_order_relaxed) == 0 &&
142 uv__mkostemp != NULL) {
143 r = uv__mkostemp(path, O_CLOEXEC);
144
145@@ -352,7 +354,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
146
147 /* We set the static variable so that next calls don't even
148 try to use mkostemp. */
149- atomic_store_explicit(&no_cloexec_support, 1, memory_order_relaxed);
150+ atomic_store_explicit(&no_cloexec_support, 1, std::memory_order_relaxed);
151 }
152 #endif /* O_CLOEXEC */
153
154@@ -462,7 +464,7 @@ static ssize_t uv__fs_preadv(uv_file fd,
155
156 static ssize_t uv__fs_read(uv_fs_t* req) {
157 #if TRY_PREADV
158- static _Atomic int no_preadv;
159+ static std::atomic<int> no_preadv;
160 #endif
161 unsigned int iovmax;
162 ssize_t result;
163@@ -486,7 +488,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
164 result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
165 #else
166 # if TRY_PREADV
167- if (atomic_load_explicit(&no_preadv, memory_order_relaxed)) retry:
168+ if (atomic_load_explicit(&no_preadv, std::memory_order_relaxed)) retry:
169 # endif
170 {
171 result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off);
172@@ -498,7 +500,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
173 req->nbufs,
174 req->off);
175 if (result == -1 && errno == ENOSYS) {
176- atomic_store_explicit(&no_preadv, 1, memory_order_relaxed);
177+ atomic_store_explicit(&no_preadv, 1, std::memory_order_relaxed);
178 goto retry;
179 }
180 }
181@@ -939,10 +941,10 @@ static int uv__is_cifs_or_smb(int fd) {
182
183 static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off,
184 int out_fd, size_t len) {
185- static _Atomic int no_copy_file_range_support;
186+ static std::atomic<int> no_copy_file_range_support;
187 ssize_t r;
188
189- if (atomic_load_explicit(&no_copy_file_range_support, memory_order_relaxed)) {
190+ if (atomic_load_explicit(&no_copy_file_range_support, std::memory_order_relaxed)) {
191 errno = ENOSYS;
192 return -1;
193 }
194@@ -961,7 +963,7 @@ static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off,
195 errno = ENOSYS; /* Use fallback. */
196 break;
197 case ENOSYS:
198- atomic_store_explicit(&no_copy_file_range_support, 1, memory_order_relaxed);
199+ atomic_store_explicit(&no_copy_file_range_support, 1, std::memory_order_relaxed);
200 break;
201 case EPERM:
202 /* It's been reported that CIFS spuriously fails.
203@@ -1162,7 +1164,7 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) {
204
205 static ssize_t uv__fs_write(uv_fs_t* req) {
206 #if TRY_PREADV
207- static _Atomic int no_pwritev;
208+ static std::atomic<int> no_pwritev;
209 #endif
210 ssize_t r;
211
212@@ -1191,7 +1193,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
213 r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
214 #else
215 # if TRY_PREADV
216- if (atomic_load_explicit(&no_pwritev, memory_order_relaxed)) retry:
217+ if (atomic_load_explicit(&no_pwritev, std::memory_order_relaxed)) retry:
218 # endif
219 {
220 r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
221@@ -1203,7 +1205,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
222 req->nbufs,
223 req->off);
224 if (r == -1 && errno == ENOSYS) {
225- atomic_store_explicit(&no_pwritev, 1, memory_order_relaxed);
226+ atomic_store_explicit(&no_pwritev, 1, std::memory_order_relaxed);
227 goto retry;
228 }
229 }
230@@ -1483,14 +1485,14 @@ static int uv__fs_statx(int fd,
231 uv_stat_t* buf) {
232 STATIC_ASSERT(UV_ENOSYS != -1);
233 #ifdef __linux__
234- static _Atomic int no_statx;
235+ static std::atomic<int> no_statx;
236 struct uv__statx statxbuf;
237 int dirfd;
238 int flags;
239 int mode;
240 int rc;
241
242- if (atomic_load_explicit(&no_statx, memory_order_relaxed))
243+ if (atomic_load_explicit(&no_statx, std::memory_order_relaxed))
244 return UV_ENOSYS;
245
246 dirfd = AT_FDCWD;
247@@ -1524,7 +1526,7 @@ static int uv__fs_statx(int fd,
248 * implemented, rc might return 1 with 0 set as the error code in which
249 * case we return ENOSYS.
250 */
251- atomic_store_explicit(&no_statx, 1, memory_order_relaxed);
252+ atomic_store_explicit(&no_statx, 1, std::memory_order_relaxed);
253 return UV_ENOSYS;
254 }
255
256diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c
257index 28e55aae6c613576ede7024a5c73d746e134d865..ffe0f9191cc7b0c233447db358077d8814e0217e 100644
258--- a/src/unix/kqueue.c
259+++ b/src/unix/kqueue.c
260@@ -34,6 +34,8 @@
261 #include <fcntl.h>
262 #include <time.h>
263
264+#include <atomic>
265+
266 /*
267 * Required on
268 * - Until at least FreeBSD 11.0
269@@ -60,7 +62,7 @@ int uv__kqueue_init(uv_loop_t* loop) {
270
271
272 #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
273-static _Atomic int uv__has_forked_with_cfrunloop;
274+static std::atomic<int> uv__has_forked_with_cfrunloop;
275 #endif
276
277 int uv__io_fork(uv_loop_t* loop) {
278@@ -84,7 +86,7 @@ int uv__io_fork(uv_loop_t* loop) {
279 */
280 atomic_store_explicit(&uv__has_forked_with_cfrunloop,
281 1,
282- memory_order_relaxed);
283+ std::memory_order_relaxed);
284 uv__free(loop->cf_state);
285 loop->cf_state = NULL;
286 }
287@@ -541,7 +543,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
288 goto fallback;
289
290 if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop,
291- memory_order_relaxed)) {
292+ std::memory_order_relaxed)) {
293 int r;
294 /* The fallback fd is no longer needed */
295 uv__close_nocheckstdio(fd);
296@@ -577,7 +579,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
297
298 #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
299 if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop,
300- memory_order_relaxed))
301+ std::memory_order_relaxed))
302 if (handle->cf_cb != NULL)
303 r = uv__fsevents_close(handle);
304 #endif
305diff --git a/src/unix/linux.c b/src/unix/linux.c
306index 157443792f1216c83b4221c3810d17c81c5913c4..e3dfb186dc531e5c8197a81681c00d693e0913c6 100644
307--- a/src/unix/linux.c
308+++ b/src/unix/linux.c
309@@ -27,7 +27,6 @@
310 #include "internal.h"
311
312 #include <inttypes.h>
313-#include <stdatomic.h>
314 #include <stddef.h> /* offsetof */
315 #include <stdint.h>
316 #include <stdio.h>
317@@ -133,6 +132,8 @@
318 # include <netpacket/packet.h>
319 #endif /* HAVE_IFADDRS_H */
320
321+#include <atomic>
322+
323 enum {
324 UV__IORING_SETUP_SQPOLL = 2u,
325 };
326@@ -311,14 +312,14 @@ static struct watcher_root* uv__inotify_watchers(uv_loop_t* loop) {
327
328
329 unsigned uv__kernel_version(void) {
330- static _Atomic unsigned cached_version;
331+ static std::atomic<unsigned int> cached_version;
332 struct utsname u;
333 unsigned version;
334 unsigned major;
335 unsigned minor;
336 unsigned patch;
337
338- version = atomic_load_explicit(&cached_version, memory_order_relaxed);
339+ version = std::atomic_load_explicit(&cached_version, std::memory_order_relaxed);
340 if (version != 0)
341 return version;
342
343@@ -329,7 +330,7 @@ unsigned uv__kernel_version(void) {
344 return 0;
345
346 version = major * 65536 + minor * 256 + patch;
347- atomic_store_explicit(&cached_version, version, memory_order_relaxed);
348+ std::atomic_store_explicit(&cached_version, version, std::memory_order_relaxed);
349
350 return version;
351 }
352@@ -424,16 +425,16 @@ static int uv__use_io_uring(void) {
353 return 0; /* Possibly available but blocked by seccomp. */
354 #else
355 /* Ternary: unknown=0, yes=1, no=-1 */
356- static _Atomic int use_io_uring;
357+ static std::atomic<int> use_io_uring;
358 char* val;
359 int use;
360
361- use = atomic_load_explicit(&use_io_uring, memory_order_relaxed);
362+ use = std::atomic_load_explicit(&use_io_uring, std::memory_order_relaxed);
363
364 if (use == 0) {
365 val = getenv("UV_USE_IO_URING");
366 use = val == NULL || atoi(val) ? 1 : -1;
367- atomic_store_explicit(&use_io_uring, use, memory_order_relaxed);
368+ std::atomic_store_explicit(&use_io_uring, use, std::memory_order_relaxed);
369 }
370
371 return use > 0;
372@@ -709,8 +710,8 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou,
373 if (iou->ringfd == -1)
374 return NULL;
375
376- head = atomic_load_explicit((_Atomic uint32_t*) iou->sqhead,
377- memory_order_acquire);
378+ head = std::atomic_load_explicit((std::atomic<uint32_t>*) iou->sqhead,
379+ std::memory_order_acquire);
380 tail = *iou->sqtail;
381 mask = iou->sqmask;
382
383@@ -739,12 +740,12 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou,
384 static void uv__iou_submit(struct uv__iou* iou) {
385 uint32_t flags;
386
387- atomic_store_explicit((_Atomic uint32_t*) iou->sqtail,
388+ std::atomic_store_explicit((std::atomic<uint32_t>*) iou->sqtail,
389 *iou->sqtail + 1,
390- memory_order_release);
391+ std::memory_order_release);
392
393- flags = atomic_load_explicit((_Atomic uint32_t*) iou->sqflags,
394- memory_order_acquire);
395+ flags = std::atomic_load_explicit((std::atomic<uint32_t>*) iou->sqflags,
396+ std::memory_order_acquire);
397
398 if (flags & UV__IORING_SQ_NEED_WAKEUP)
399 if (uv__io_uring_enter(iou->ringfd, 0, 0, UV__IORING_ENTER_SQ_WAKEUP))
400@@ -1076,8 +1077,8 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) {
401 int rc;
402
403 head = *iou->cqhead;
404- tail = atomic_load_explicit((_Atomic uint32_t*) iou->cqtail,
405- memory_order_acquire);
406+ tail = std::atomic_load_explicit((std::atomic<uint32_t>*) iou->cqtail,
407+ std::memory_order_acquire);
408 mask = iou->cqmask;
409 cqe = (uv__io_uring_cqe*)iou->cqe;
410 nevents = 0;
411@@ -1109,15 +1110,15 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) {
412 nevents++;
413 }
414
415- atomic_store_explicit((_Atomic uint32_t*) iou->cqhead,
416+ std::atomic_store_explicit((std::atomic<uint32_t>*) iou->cqhead,
417 tail,
418- memory_order_release);
419+ std::memory_order_release);
420
421 /* Check whether CQE's overflowed, if so enter the kernel to make them
422 * available. Don't grab them immediately but in the next loop iteration to
423 * avoid loop starvation. */
424- flags = atomic_load_explicit((_Atomic uint32_t*) iou->sqflags,
425- memory_order_acquire);
426+ flags = std::atomic_load_explicit((std::atomic<uint32_t>*) iou->sqflags,
427+ std::memory_order_acquire);
428
429 if (flags & UV__IORING_SQ_CQ_OVERFLOW) {
430 do
431@@ -1531,7 +1532,7 @@ update_timeout:
432 }
433
434 uint64_t uv__hrtime(uv_clocktype_t type) {
435- static _Atomic clock_t fast_clock_id = -1;
436+ static std::atomic<clock_t> fast_clock_id = -1;
437 struct timespec t;
438 clock_t clock_id;
439
440@@ -1547,7 +1548,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
441 if (type != UV_CLOCK_FAST)
442 goto done;
443
444- clock_id = atomic_load_explicit(&fast_clock_id, memory_order_relaxed);
445+ clock_id = std::atomic_load_explicit(&fast_clock_id, std::memory_order_relaxed);
446 if (clock_id != -1)
447 goto done;
448
449@@ -1556,7 +1557,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
450 if (t.tv_nsec <= 1 * 1000 * 1000)
451 clock_id = CLOCK_MONOTONIC_COARSE;
452
453- atomic_store_explicit(&fast_clock_id, clock_id, memory_order_relaxed);
454+ std::atomic_store_explicit(&fast_clock_id, clock_id, std::memory_order_relaxed);
455
456 done:
457
458diff --git a/src/unix/tty.c b/src/unix/tty.c
459index 1bd217b5a15eed13a8349c479b53471dd36ca216..1304c6d8685cfd122cffea066dc668d1dfc9ae02 100644
460--- a/src/unix/tty.c
461+++ b/src/unix/tty.c
462@@ -22,7 +22,6 @@
463 #include "uv.h"
464 #include "internal.h"
465
466-#include <stdatomic.h>
467 #include <stdlib.h>
468 #include <assert.h>
469 #include <unistd.h>
470@@ -30,6 +29,8 @@
471 #include <errno.h>
472 #include <sys/ioctl.h>
473
474+#include <atomic>
475+
476 #if defined(__MVS__) && !defined(IMAXBEL)
477 #define IMAXBEL 0
478 #endif
479@@ -64,7 +65,7 @@ static int isreallyatty(int file) {
480
481 static int orig_termios_fd = -1;
482 static struct termios orig_termios;
483-static _Atomic int termios_spinlock;
484+static std::atomic<int> termios_spinlock;
485
486 int uv__tcsetattr(int fd, int how, const struct termios *term) {
487 int rc;
488diff --git a/src/uv-common.c b/src/uv-common.c
489index bfcc3ef10f4fd7763221638947da6e02e7a17c33..5c6d84155408ae4f7c3c6ff9b48bd09ccd16a92e 100644
490--- a/src/uv-common.c
491+++ b/src/uv-common.c
492@@ -951,7 +951,7 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
493 __attribute__((destructor))
494 #endif
495 void uv_library_shutdown(void) {
496- static int was_shutdown;
497+ static std::atomic<int> was_shutdown;
498
499 if (uv__exchange_int_relaxed(&was_shutdown, 1))
500 return;
501diff --git a/src/uv-common.h b/src/uv-common.h
502index cd57e5a35153d0557351b60cce0c5be7a4468b60..5dce8eaf2705b47935b218181f6dd69af0d5b61b 100644
503--- a/src/uv-common.h
504+++ b/src/uv-common.h
505@@ -32,15 +32,13 @@
506 #include <stddef.h>
507 #include <stdint.h>
508
509+#include <atomic>
510+
511 #include "uv.h"
512 #include "uv/tree.h"
513 #include "queue.h"
514 #include "strscpy.h"
515
516-#ifndef _MSC_VER
517-# include <stdatomic.h>
518-#endif
519-
520 #if EDOM > 0
521 # define UV__ERR(x) (-(x))
522 #else
523@@ -70,7 +68,7 @@ extern int snprintf(char*, size_t, const char*, ...);
524 InterlockedExchangeNoFence((LONG volatile*)(p), v)
525 #else
526 #define uv__exchange_int_relaxed(p, v) \
527- atomic_exchange_explicit((_Atomic int*)(p), v, memory_order_relaxed)
528+ std::atomic_exchange_explicit((std::atomic<int>*)(p), v, std::memory_order_relaxed)
529 #endif
530
531 #define UV__UDP_DGRAM_MAXSIZE (64 * 1024)