From 150b6a71c9f65d410b9755df79e7a7733e6cafeb Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 18 Oct 2013 15:39:47 +0200 Subject: [PATCH] unix: add spinlock.h Add an atomic, non-blocking spinlock type. The primary use case is to have a mutex type that we can use while inside a signal handler. --- Makefile.am | 1 + src/unix/spinlock.h | 53 +++++++++++++++++++++++++++++++++++++++++++++ uv.gyp | 1 + 3 files changed, 55 insertions(+) create mode 100644 src/unix/spinlock.h diff --git a/Makefile.am b/Makefile.am index 6c48c864..4962c1d1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -92,6 +92,7 @@ libuv_la_SOURCES += src/unix/async.c \ src/unix/poll.c \ src/unix/process.c \ src/unix/signal.c \ + src/unix/spinlock.h \ src/unix/stream.c \ src/unix/tcp.c \ src/unix/thread.c \ diff --git a/src/unix/spinlock.h b/src/unix/spinlock.h new file mode 100644 index 00000000..a20c83cc --- /dev/null +++ b/src/unix/spinlock.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef UV_SPINLOCK_H_ +#define UV_SPINLOCK_H_ + +#include "internal.h" /* ACCESS_ONCE, UV_UNUSED */ +#include "atomic-ops.h" + +#define UV_SPINLOCK_INITIALIZER { 0 } + +typedef struct { + int lock; +} uv_spinlock_t; + +UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)); +UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)); +UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)); +UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)); + +UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)) { + ACCESS_ONCE(int, spinlock->lock) = 0; +} + +UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)) { + while (!uv_spinlock_trylock(spinlock)) cpu_relax(); +} + +UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)) { + ACCESS_ONCE(int, spinlock->lock) = 0; +} + +UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)) { + /* TODO(bnoordhuis) Maybe change to a ticket lock to guarantee fair queueing. + * Not really critical until we have locks that are (frequently) contended + * for by several threads. + */ + return 0 == cmpxchgi(&spinlock->lock, 0, 1); +} + +#endif /* UV_SPINLOCK_H_ */ diff --git a/uv.gyp b/uv.gyp index 31ec918a..74768a09 100644 --- a/uv.gyp +++ b/uv.gyp @@ -146,6 +146,7 @@ 'src/unix/poll.c', 'src/unix/process.c', 'src/unix/signal.c', + 'src/unix/spinlock.h', 'src/unix/stream.c', 'src/unix/tcp.c', 'src/unix/thread.c',