Skip to content

Commit 5d74a5b

Browse files
committed
unix: switch to c11 atomics
Fixes: #3683
1 parent 495ffca commit 5d74a5b

File tree

5 files changed

+48
-134
lines changed

5 files changed

+48
-134
lines changed

Makefile.am

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ else # WINNT
9696
uvinclude_HEADERS += include/uv/unix.h
9797
AM_CPPFLAGS += -I$(top_srcdir)/src/unix
9898
libuv_la_SOURCES += src/unix/async.c \
99-
src/unix/atomic-ops.h \
10099
src/unix/core.c \
101100
src/unix/dl.c \
102101
src/unix/fs.c \
@@ -110,7 +109,6 @@ libuv_la_SOURCES += src/unix/async.c \
110109
src/unix/process.c \
111110
src/unix/random-devurandom.c \
112111
src/unix/signal.c \
113-
src/unix/spinlock.h \
114112
src/unix/stream.c \
115113
src/unix/tcp.c \
116114
src/unix/thread.c \

src/unix/async.c

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424

2525
#include "uv.h"
2626
#include "internal.h"
27-
#include "atomic-ops.h"
2827

2928
#include <errno.h>
29+
#include <stdatomic.h>
3030
#include <stdio.h> /* snprintf() */
3131
#include <assert.h>
3232
#include <stdlib.h>
@@ -40,6 +40,7 @@
4040

4141
static void uv__async_send(uv_loop_t* loop);
4242
static int uv__async_start(uv_loop_t* loop);
43+
static void uv__cpu_relax(void);
4344

4445

4546
int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
@@ -61,19 +62,26 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
6162

6263

6364
int uv_async_send(uv_async_t* handle) {
65+
_Atomic int* pending;
66+
int expected;
67+
68+
pending = (_Atomic int*) &handle->pending;
69+
6470
/* Do a cheap read first. */
65-
if (ACCESS_ONCE(int, handle->pending) != 0)
71+
if (atomic_load_explicit(pending, memory_order_relaxed) != 0)
6672
return 0;
6773

6874
/* Tell the other thread we're busy with the handle. */
69-
if (cmpxchgi(&handle->pending, 0, 1) != 0)
75+
expected = 0;
76+
if (!atomic_compare_exchange_strong(pending, &expected, 1))
7077
return 0;
7178

7279
/* Wake up the other thread's event loop. */
7380
uv__async_send(handle->loop);
7481

7582
/* Tell the other thread we're done. */
76-
if (cmpxchgi(&handle->pending, 1, 2) != 1)
83+
expected = 1;
84+
if (!atomic_compare_exchange_strong(pending, &expected, 2))
7785
abort();
7886

7987
return 0;
@@ -82,8 +90,11 @@ int uv_async_send(uv_async_t* handle) {
8290

8391
/* Only call this from the event loop thread. */
8492
static int uv__async_spin(uv_async_t* handle) {
93+
_Atomic int* pending;
94+
int expected;
8595
int i;
86-
int rc;
96+
97+
pending = (_Atomic int*) &handle->pending;
8798

8899
for (;;) {
89100
/* 997 is not completely chosen at random. It's a prime number, acyclical
@@ -94,13 +105,14 @@ static int uv__async_spin(uv_async_t* handle) {
94105
* rc=1 -- handle is pending, other thread is still working with it.
95106
* rc=2 -- handle is pending, other thread is done.
96107
*/
97-
rc = cmpxchgi(&handle->pending, 2, 0);
108+
expected = 2;
109+
atomic_compare_exchange_strong(pending, &expected, 0);
98110

99-
if (rc != 1)
100-
return rc;
111+
if (expected != 1)
112+
return expected;
101113

102114
/* Other thread is busy with this handle, spin until it's done. */
103-
cpu_relax();
115+
uv__cpu_relax();
104116
}
105117

106118
/* Yield the CPU. We may have preempted the other thread while it's
@@ -251,3 +263,16 @@ void uv__async_stop(uv_loop_t* loop) {
251263
uv__close(loop->async_io_watcher.fd);
252264
loop->async_io_watcher.fd = -1;
253265
}
266+
267+
268+
static void uv__cpu_relax(void) {
269+
#if defined(__i386__) || defined(__x86_64__)
270+
__asm__ __volatile__ ("rep; nop" ::: "memory"); /* a.k.a. PAUSE */
271+
#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
272+
__asm__ __volatile__ ("yield" ::: "memory");
273+
#elif (defined(__ppc__) || defined(__ppc64__)) && defined(__APPLE__)
274+
__asm volatile ("" : : : "memory");
275+
#elif !defined(__APPLE__) && (defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__))
276+
__asm__ __volatile__ ("or 1,1,1; or 2,2,2" ::: "memory");
277+
#endif
278+
}

src/unix/atomic-ops.h

Lines changed: 0 additions & 64 deletions
This file was deleted.

src/unix/spinlock.h

Lines changed: 0 additions & 53 deletions
This file was deleted.

src/unix/tty.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121

2222
#include "uv.h"
2323
#include "internal.h"
24-
#include "spinlock.h"
2524

25+
#include <stdatomic.h>
2626
#include <stdlib.h>
2727
#include <assert.h>
2828
#include <unistd.h>
@@ -64,7 +64,7 @@ static int isreallyatty(int file) {
6464

6565
static int orig_termios_fd = -1;
6666
static struct termios orig_termios;
67-
static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
67+
static _Atomic int termios_spinlock = 0;
6868

6969
int uv__tcsetattr(int fd, int how, const struct termios *term) {
7070
int rc;
@@ -280,6 +280,7 @@ static void uv__tty_make_raw(struct termios* tio) {
280280

281281
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
282282
struct termios tmp;
283+
int expected;
283284
int fd;
284285
int rc;
285286

@@ -296,12 +297,16 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
296297
return UV__ERR(errno);
297298

298299
/* This is used for uv_tty_reset_mode() */
299-
uv_spinlock_lock(&termios_spinlock);
300+
do
301+
expected = 0;
302+
while (!atomic_compare_exchange_strong(&termios_spinlock, &expected, 1));
303+
300304
if (orig_termios_fd == -1) {
301305
orig_termios = tty->orig_termios;
302306
orig_termios_fd = fd;
303307
}
304-
uv_spinlock_unlock(&termios_spinlock);
308+
309+
atomic_store(&termios_spinlock, 0);
305310
}
306311

307312
tmp = tty->orig_termios;
@@ -442,17 +447,20 @@ uv_handle_type uv_guess_handle(uv_file file) {
442447
*/
443448
int uv_tty_reset_mode(void) {
444449
int saved_errno;
450+
int expected;
445451
int err;
446452

447453
saved_errno = errno;
448-
if (!uv_spinlock_trylock(&termios_spinlock))
454+
455+
expected = 0;
456+
if (!atomic_compare_exchange_strong(&termios_spinlock, &expected, 1))
449457
return UV_EBUSY; /* In uv_tty_set_mode(). */
450458

451459
err = 0;
452460
if (orig_termios_fd != -1)
453461
err = uv__tcsetattr(orig_termios_fd, TCSANOW, &orig_termios);
454462

455-
uv_spinlock_unlock(&termios_spinlock);
463+
atomic_store(&termios_spinlock, 0);
456464
errno = saved_errno;
457465

458466
return err;

0 commit comments

Comments
 (0)