[ovs-dev] [threads 03/11] ovs-atomic: New library for atomic operations.

Ben Pfaff blp at nicira.com
Wed Jun 19 20:17:04 UTC 2013


This library should prove useful for the threading changes coming up.
The following commit introduces one (very simple) user.

Signed-off-by: Ben Pfaff <blp at nicira.com>
---
 configure.ac              |    6 +-
 lib/automake.mk           |    7 +
 lib/ovs-atomic-c11.h      |   62 +++++++++++
 lib/ovs-atomic-gcc4+.c    |   68 ++++++++++++
 lib/ovs-atomic-gcc4+.h    |  267 +++++++++++++++++++++++++++++++++++++++++++++
 lib/ovs-atomic-gcc4.7+.h  |  141 ++++++++++++++++++++++++
 lib/ovs-atomic-pthreads.c |   61 ++++++++++
 lib/ovs-atomic-pthreads.h |  157 ++++++++++++++++++++++++++
 lib/ovs-atomic.h          |  250 ++++++++++++++++++++++++++++++++++++++++++
 m4/openvswitch.m4         |   21 ++++
 tests/automake.mk         |    5 +
 tests/library.at          |    4 +
 tests/test-atomic.c       |   94 ++++++++++++++++
 13 files changed, 1142 insertions(+), 1 deletions(-)
 create mode 100644 lib/ovs-atomic-c11.h
 create mode 100644 lib/ovs-atomic-gcc4+.c
 create mode 100644 lib/ovs-atomic-gcc4+.h
 create mode 100644 lib/ovs-atomic-gcc4.7+.h
 create mode 100644 lib/ovs-atomic-pthreads.c
 create mode 100644 lib/ovs-atomic-pthreads.h
 create mode 100644 lib/ovs-atomic.h
 create mode 100644 tests/test-atomic.c

diff --git a/configure.ac b/configure.ac
index a6c68a9..6db4a00 100644
--- a/configure.ac
+++ b/configure.ac
@@ -64,7 +64,7 @@ AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec],
   [], [], [[#include <sys/stat.h>]])
 AC_CHECK_MEMBERS([struct ifreq.ifr_flagshigh], [], [], [[#include <net/if.h>]])
 AC_CHECK_FUNCS([mlockall strnlen getloadavg statvfs getmntent_r])
-AC_CHECK_HEADERS([mntent.h sys/statvfs.h linux/types.h linux/if_ether.h])
+AC_CHECK_HEADERS([mntent.h sys/statvfs.h linux/types.h linux/if_ether.h stdatomic.h])
 AC_CHECK_HEADERS([net/if_mib.h], [], [], [[#include <sys/types.h>
 #include <net/if.h>]])
 
@@ -81,6 +81,10 @@ OVS_CHECK_GROFF
 OVS_CHECK_GNU_MAKE
 OVS_CHECK_CACHE_TIME
 OVS_CHECK___THREAD
+OVS_CHECK_ATOMIC_ALWAYS_LOCK_FREE(1)
+OVS_CHECK_ATOMIC_ALWAYS_LOCK_FREE(2)
+OVS_CHECK_ATOMIC_ALWAYS_LOCK_FREE(4)
+OVS_CHECK_ATOMIC_ALWAYS_LOCK_FREE(8)
 
 OVS_ENABLE_OPTION([-Wall])
 OVS_ENABLE_OPTION([-Wno-sign-compare])
diff --git a/lib/automake.mk b/lib/automake.mk
index c6de4fe..c8550c3 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -121,6 +121,13 @@ lib_libopenvswitch_a_SOURCES = \
 	lib/ofp-version-opt.c \
 	lib/ofpbuf.c \
 	lib/ofpbuf.h \
+	lib/ovs-atomic-c11.h \
+	lib/ovs-atomic-gcc4+.c \
+	lib/ovs-atomic-gcc4+.h \
+	lib/ovs-atomic-gcc4.7+.h \
+	lib/ovs-atomic-pthreads.c \
+	lib/ovs-atomic-pthreads.h \
+	lib/ovs-atomic.h \
 	lib/ovs-thread.c \
 	lib/ovs-thread.h \
 	lib/ovsdb-data.c \
diff --git a/lib/ovs-atomic-c11.h b/lib/ovs-atomic-c11.h
new file mode 100644
index 0000000..26fa25e
--- /dev/null
+++ b/lib/ovs-atomic-c11.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This header implements atomic operation primitives on compilers that
+ * have built-in support for C11 <stdatomic.h>  */
+#ifndef IN_OVS_ATOMIC_H
+#error "This header should only be included indirectly via ovs-atomic.h."
+#endif
+
+#include <stdatomic.h>
+
+/* Nonstandard atomic types. */
+typedef _Atomic uint8_t   atomic_uint8_t;
+typedef _Atomic uint16_t  atomic_uint16_t;
+typedef _Atomic uint32_t  atomic_uint32_t;
+typedef _Atomic uint64_t  atomic_uint64_t;
+
+typedef _Atomic int8_t    atomic_int8_t;
+typedef _Atomic int16_t   atomic_int16_t;
+typedef _Atomic int32_t   atomic_int32_t;
+typedef _Atomic int64_t   atomic_int64_t;
+
+#define atomic_read(SRC, DST) \
+    atomic_read_explicit(SRC, DST, memory_order_seq_cst)
+#define atomic_read_explicit(SRC, DST, ORDER)   \
+    (*(DST) = atomic_load_explicit(SRC, ORDER), \
+     (void) 0)
+
+#define atomic_add(RMW, ARG, ORIG) \
+    atomic_add_explicit(RMW, ARG, ORIG, memory_order_seq_cst)
+#define atomic_sub(RMW, ARG, ORIG) \
+    atomic_sub_explicit(RMW, ARG, ORIG, memory_order_seq_cst)
+#define atomic_or(RMW, ARG, ORIG) \
+    atomic_or_explicit(RMW, ARG, ORIG, memory_order_seq_cst)
+#define atomic_xor(RMW, ARG, ORIG) \
+    atomic_xor_explicit(RMW, ARG, ORIG, memory_order_seq_cst)
+#define atomic_and(RMW, ARG, ORIG) \
+    atomic_and_explicit(RMW, ARG, ORIG, memory_order_seq_cst)
+
+#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \
+    (*(ORIG) = atomic_fetch_add_explicit(RMW, ARG, ORDER), (void) 0)
+#define atomic_sub_explicit(RMW, ARG, ORIG, ORDER) \
+    (*(ORIG) = atomic_fetch_sub_explicit(RMW, ARG, ORDER), (void) 0)
+#define atomic_or_explicit(RMW, ARG, ORIG, ORDER) \
+    (*(ORIG) = atomic_fetch_or_explicit(RMW, ARG, ORDER), (void) 0)
+#define atomic_xor_explicit(RMW, ARG, ORIG, ORDER) \
+    (*(ORIG) = atomic_fetch_xor_explicit(RMW, ARG, ORDER), (void) 0)
+#define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \
+    (*(ORIG) = atomic_fetch_and_explicit(RMW, ARG, ORDER), (void) 0)
diff --git a/lib/ovs-atomic-gcc4+.c b/lib/ovs-atomic-gcc4+.c
new file mode 100644
index 0000000..aeff845
--- /dev/null
+++ b/lib/ovs-atomic-gcc4+.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include "ovs-atomic.h"
+#include "ovs-thread.h"
+
+#if OVS_ATOMIC_GCC4P_IMPL
+static pthread_mutex_t mutex = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER;
+
+#define DEFINE_LOCKED_OP(TYPE, NAME, OPERATOR)                          \
+    TYPE##_t                                                            \
+    locked_##TYPE##_##NAME(struct locked_##TYPE *u, TYPE##_t arg)       \
+    {                                                                   \
+        TYPE##_t old_value;                                             \
+                                                                        \
+        xpthread_mutex_lock(&mutex);                                    \
+        old_value = u->value;                                           \
+        u->value OPERATOR arg;                                          \
+        xpthread_mutex_unlock(&mutex);                                  \
+                                                                        \
+        return old_value;                                               \
+    }
+
+#define DEFINE_LOCKED_TYPE(TYPE)                                        \
+    TYPE##_t                                                            \
+    locked_##TYPE##_load(const struct locked_##TYPE *u)                 \
+    {                                                                   \
+        TYPE##_t value;                                                 \
+                                                                        \
+        xpthread_mutex_lock(&mutex);                                    \
+        value = u->value;                                               \
+        xpthread_mutex_unlock(&mutex);                                  \
+                                                                        \
+        return value;                                                   \
+    }                                                                   \
+                                                                        \
+    void                                                                \
+    locked_##TYPE##_store(struct locked_##TYPE *u, TYPE##_t value)      \
+    {                                                                   \
+        xpthread_mutex_lock(&mutex);                                    \
+        u->value = value;                                               \
+        xpthread_mutex_unlock(&mutex);                                  \
+    }                                                                   \
+    DEFINE_LOCKED_OP(TYPE, add, +=);                                    \
+    DEFINE_LOCKED_OP(TYPE, sub, -=);                                    \
+    DEFINE_LOCKED_OP(TYPE, or,  |=);                                    \
+    DEFINE_LOCKED_OP(TYPE, xor, ^=);                                    \
+    DEFINE_LOCKED_OP(TYPE, and, &=)
+
+DEFINE_LOCKED_TYPE(uint64);
+DEFINE_LOCKED_TYPE(int64);
+
+#endif  /* OVS_ATOMIC_GCC4P_IMPL */
diff --git a/lib/ovs-atomic-gcc4+.h b/lib/ovs-atomic-gcc4+.h
new file mode 100644
index 0000000..5f06a7b
--- /dev/null
+++ b/lib/ovs-atomic-gcc4+.h
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2013 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This header implements atomic operation primitives on GCC 4.x. */
+#ifndef IN_OVS_ATOMIC_H
+#error "This header should only be included indirectly via ovs-atomic.h."
+#endif
+
+#define OVS_ATOMIC_GCC4P_IMPL 1
+
+#define DEFINE_LOCKLESS_ATOMIC(TYPE, NAME) typedef struct { TYPE value; } NAME
+
+#define ATOMIC_BOOL_LOCK_FREE 2
+DEFINE_LOCKLESS_ATOMIC(bool, atomic_bool);
+
+#define ATOMIC_CHAR_LOCK_FREE 2
+DEFINE_LOCKLESS_ATOMIC(char, atomic_char);
+DEFINE_LOCKLESS_ATOMIC(signed char, atomic_schar);
+DEFINE_LOCKLESS_ATOMIC(unsigned char, atomic_uchar);
+
+#define ATOMIC_SHORT_LOCK_FREE 2
+DEFINE_LOCKLESS_ATOMIC(short, atomic_short);
+DEFINE_LOCKLESS_ATOMIC(unsigned short, atomic_ushort);
+
+#define ATOMIC_INT_LOCK_FREE 2
+DEFINE_LOCKLESS_ATOMIC(int, atomic_int);
+DEFINE_LOCKLESS_ATOMIC(unsigned int, atomic_uint);
+
+#if ULONG_MAX <= UINTPTR_MAX
+    #define ATOMIC_LONG_LOCK_FREE 2
+    DEFINE_LOCKLESS_ATOMIC(long, atomic_long);
+    DEFINE_LOCKLESS_ATOMIC(unsigned long, atomic_ulong);
+#elif ULONG_MAX == UINT64_MAX
+    #define ATOMIC_LONG_LOCK_FREE 0
+    typedef struct locked_int64  atomic_long;
+    typedef struct locked_uint64 atomic_ulong;
+#else
+    #error "not implemented"
+#endif
+
+#if ULLONG_MAX <= UINTPTR_MAX
+    #define ATOMIC_LLONG_LOCK_FREE 2
+    DEFINE_LOCKLESS_ATOMIC(long long, atomic_llong);
+    DEFINE_LOCKLESS_ATOMIC(unsigned long long, atomic_ullong);
+#elif ULLONG_MAX == UINT64_MAX
+    #define ATOMIC_LLONG_LOCK_FREE 0
+    typedef struct locked_int64  atomic_llong;
+    typedef struct locked_uint64 atomic_ullong;
+#else
+    #error "not implemented"
+#endif
+
+#if SIZE_MAX <= UINTPTR_MAX
+    DEFINE_LOCKLESS_ATOMIC(size_t, atomic_size_t);
+    DEFINE_LOCKLESS_ATOMIC(ptrdiff_t, atomic_ptrdiff_t);
+#elif SIZE_MAX == UINT64_MAX
+    typedef struct locked_uint64 atomic_size_t;
+    typedef struct locked_int64  atomic_ptrdiff_t;
+#else
+    #error "not implemented"
+#endif
+
+#if UINTMAX_MAX <= UINTPTR_MAX
+    DEFINE_LOCKLESS_ATOMIC(intmax_t, atomic_intmax_t);
+    DEFINE_LOCKLESS_ATOMIC(uintmax_t, atomic_uintmax_t);
+#elif UINTMAX_MAX == UINT64_MAX
+    typedef struct locked_int64  atomic_intmax_t;
+    typedef struct locked_uint64 atomic_uintmax_t;
+#else
+    #error "not implemented"
+#endif
+
+#define ATOMIC_POINTER_LOCK_FREE 2
+DEFINE_LOCKLESS_ATOMIC(intptr_t, atomic_intptr_t);
+DEFINE_LOCKLESS_ATOMIC(uintptr_t, atomic_uintptr_t);
+
+/* Nonstandard atomic types. */
+DEFINE_LOCKLESS_ATOMIC(uint8_t,  atomic_uint8_t);
+DEFINE_LOCKLESS_ATOMIC(uint16_t, atomic_uint16_t);
+DEFINE_LOCKLESS_ATOMIC(uint32_t, atomic_uint32_t);
+DEFINE_LOCKLESS_ATOMIC(int8_t,   atomic_int8_t);
+DEFINE_LOCKLESS_ATOMIC(int16_t,  atomic_int16_t);
+DEFINE_LOCKLESS_ATOMIC(int32_t,  atomic_int32_t);
+#if UINT64_MAX <= UINTPTR_MAX
+    DEFINE_LOCKLESS_ATOMIC(uint64_t, atomic_uint64_t);
+    DEFINE_LOCKLESS_ATOMIC(int64_t,  atomic_int64_t);
+#else
+    typedef struct locked_uint64 atomic_uint64_t;
+    typedef struct locked_int64  atomic_int64_t;
+#endif
+
+typedef enum {
+    memory_order_relaxed,
+    memory_order_consume,
+    memory_order_acquire,
+    memory_order_release,
+    memory_order_acq_rel,
+    memory_order_seq_cst
+} memory_order;
+
+/* locked_uint64. */
+
+#define IF_LOCKED_UINT64(OBJECT, THEN, ELSE)                            \
+    __builtin_choose_expr(                                              \
+        __builtin_types_compatible_p(typeof(OBJECT), struct locked_uint64), \
+        (THEN), (ELSE))
+#define AS_LOCKED_UINT64(OBJECT) ((struct locked_uint64 *) (OBJECT))
+#define AS_UINT64(OBJECT) ((uint64_t *) (OBJECT))
+struct locked_uint64 {
+    uint64_t value;
+};
+
+uint64_t locked_uint64_load(const struct locked_uint64 *);
+void locked_uint64_store(struct locked_uint64 *, uint64_t);
+uint64_t locked_uint64_add(struct locked_uint64 *, uint64_t arg);
+uint64_t locked_uint64_sub(struct locked_uint64 *, uint64_t arg);
+uint64_t locked_uint64_or(struct locked_uint64 *, uint64_t arg);
+uint64_t locked_uint64_xor(struct locked_uint64 *, uint64_t arg);
+uint64_t locked_uint64_and(struct locked_uint64 *, uint64_t arg);
+
+#define IF_LOCKED_INT64(OBJECT, THEN, ELSE)                             \
+    __builtin_choose_expr(                                              \
+        __builtin_types_compatible_p(typeof(OBJECT), struct locked_int64), \
+        (THEN), (ELSE))
+#define AS_LOCKED_INT64(OBJECT) ((struct locked_int64 *) (OBJECT))
+#define AS_INT64(OBJECT) ((int64_t *) (OBJECT))
+struct locked_int64 {
+    int64_t value;
+};
+int64_t locked_int64_load(const struct locked_int64 *);
+void locked_int64_store(struct locked_int64 *, int64_t);
+int64_t locked_int64_add(struct locked_int64 *, int64_t arg);
+int64_t locked_int64_sub(struct locked_int64 *, int64_t arg);
+int64_t locked_int64_or(struct locked_int64 *, int64_t arg);
+int64_t locked_int64_xor(struct locked_int64 *, int64_t arg);
+int64_t locked_int64_and(struct locked_int64 *, int64_t arg);
+
+#define ATOMIC_VAR_INIT(VALUE) { .value = (VALUE) }
+#define atomic_init(OBJECT, VALUE) ((OBJECT)->value = (VALUE), (void) 0)
+
+/* XXX kill_dependency */
+
+static inline void
+atomic_thread_fence(memory_order order)
+{
+    if (order != memory_order_relaxed) {
+        __sync_synchronize();
+    }
+}
+
+static inline void
+atomic_thread_fence_if_seq_cst(memory_order order)
+{
+    if (order == memory_order_seq_cst) {
+        __sync_synchronize();
+    }
+}
+
+static inline void
+atomic_signal_fence(memory_order order OVS_UNUSED)
+{
+    if (order != memory_order_relaxed) {
+        asm volatile("" : : : "memory");
+    }
+}
+
+#define ATOMIC_SWITCH(OBJECT, LOCKLESS_CASE,                    \
+                      LOCKED_UINT64_CASE, LOCKED_INT64_CASE)    \
+    IF_LOCKED_UINT64(OBJECT, LOCKED_UINT64_CASE,                \
+                     IF_LOCKED_INT64(OBJECT, LOCKED_INT64_CASE, \
+                                     LOCKLESS_CASE))
+
+#define atomic_is_lock_free(OBJ)                \
+    ((void) (OBJ)->value,                       \
+     ATOMIC_SWITCH(OBJ, true, false, false))
+
+#define atomic_store(DST, SRC) \
+    atomic_store_explicit(DST, SRC, memory_order_seq_cst)
+#define atomic_store_explicit(DST, SRC, ORDER)                          \
+    (ATOMIC_SWITCH(DST,                                                 \
+                   (atomic_thread_fence(ORDER),                         \
+                    (DST)->value = (SRC),                               \
+                    atomic_thread_fence_if_seq_cst(ORDER)),             \
+                   locked_uint64_store(AS_LOCKED_UINT64(DST), SRC),     \
+                   locked_int64_store(AS_LOCKED_INT64(DST), SRC)),      \
+     (void) 0)
+
+#define atomic_read(SRC, DST) \
+    atomic_read_explicit(SRC, DST, memory_order_seq_cst)
+#define atomic_read_explicit(SRC, DST, ORDER)                           \
+    (ATOMIC_SWITCH(SRC,                                                 \
+                   (atomic_thread_fence_if_seq_cst(ORDER),              \
+                    (*DST) = (SRC)->value,                              \
+                    atomic_thread_fence(ORDER)),                        \
+                   *(DST) = locked_uint64_load(AS_LOCKED_UINT64(SRC)),  \
+                   *(DST) = locked_int64_load(AS_LOCKED_INT64(SRC))),   \
+     (void) 0)
+
+#define atomic_op__(RMW, OP, ARG, ORIG)                                 \
+    (ATOMIC_SWITCH(RMW,                                                 \
+                   *(ORIG) = __sync_fetch_and_##OP(&(RMW)->value, ARG), \
+                   *(ORIG) = locked_uint64_##OP(AS_LOCKED_UINT64(RMW), ARG), \
+                   *(ORIG) = locked_int64_##OP(AS_LOCKED_INT64(RMW), ARG)), \
+     (void) 0)
+
+#define atomic_add(RMW, ARG, ORIG) atomic_op__(RMW, add, ARG, ORIG)
+#define atomic_sub(RMW, ARG, ORIG) atomic_op__(RMW, sub, ARG, ORIG)
+#define atomic_or( RMW, ARG, ORIG) atomic_op__(RMW, or,  ARG, ORIG)
+#define atomic_xor(RMW, ARG, ORIG) atomic_op__(RMW, xor, ARG, ORIG)
+#define atomic_and(RMW, ARG, ORIG) atomic_op__(RMW, and, ARG, ORIG)
+
+#define atomic_add_explicit(RMW, OPERAND, ORIG, ORDER)  \
+    ((void) (ORDER), atomic_add(RMW, OPERAND, ORIG))
+#define atomic_sub_explicit(RMW, OPERAND, ORIG, ORDER)  \
+    ((void) (ORDER), atomic_sub(RMW, OPERAND, ORIG))
+#define atomic_or_explicit(RMW, OPERAND, ORIG, ORDER)   \
+    ((void) (ORDER), atomic_or(RMW, OPERAND, ORIG))
+#define atomic_xor_explicit(RMW, OPERAND, ORIG, ORDER)  \
+    ((void) (ORDER), atomic_xor(RMW, OPERAND, ORIG))
+#define atomic_and_explicit(RMW, OPERAND, ORIG, ORDER)  \
+    ((void) (ORDER), atomic_and(RMW, OPERAND, ORIG))
+
+/* atomic_flag */
+
+typedef struct {
+    int b;
+} atomic_flag;
+#define ATOMIC_FLAG_INIT { false }
+
+static inline bool
+atomic_flag_test_and_set(volatile atomic_flag *object)
+{
+    return __sync_lock_test_and_set(&object->b, 1);
+}
+
+static inline bool
+atomic_flag_test_and_set_explicit(volatile atomic_flag *object,
+                                  memory_order order OVS_UNUSED)
+{
+    return atomic_flag_test_and_set(object);
+}
+
+static inline void
+atomic_flag_clear(volatile atomic_flag *object)
+{
+    __sync_lock_release(&object->b);
+}
+
+static inline void
+atomic_flag_clear_explicit(volatile atomic_flag *object,
+                           memory_order order OVS_UNUSED)
+{
+    atomic_flag_clear(object);
+}
diff --git a/lib/ovs-atomic-gcc4.7+.h b/lib/ovs-atomic-gcc4.7+.h
new file mode 100644
index 0000000..07bef2a
--- /dev/null
+++ b/lib/ovs-atomic-gcc4.7+.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2013 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This header implements atomic operation primitives on GCC 4.7 and later. */
+#ifndef IN_OVS_ATOMIC_H
+#error "This header should only be included indirectly via ovs-atomic.h."
+#endif
+
+/* C11 standardized atomic type. */
+typedef bool               atomic_bool;
+
+typedef char               atomic_char;
+typedef signed char        atomic_schar;
+typedef unsigned char      atomic_uchar;
+
+typedef short              atomic_short;
+typedef unsigned short     atomic_ushort;
+
+typedef int                atomic_int;
+typedef unsigned int       atomic_uint;
+
+typedef long               atomic_long;
+typedef unsigned long      atomic_ulong;
+
+typedef long long          atomic_llong;
+typedef unsigned long long atomic_ullong;
+
+typedef size_t             atomic_size_t;
+typedef ptrdiff_t          atomic_ptrdiff_t;
+
+typedef intmax_t           atomic_intmax_t;
+typedef uintmax_t          atomic_uintmax_t;
+
+typedef intptr_t           atomic_intptr_t;
+typedef uintptr_t          atomic_uintptr_t;
+
+/* Nonstandard atomic types. */
+typedef int8_t             atomic_int8_t;
+typedef uint8_t            atomic_uint8_t;
+
+typedef int16_t            atomic_int16_t;
+typedef uint16_t           atomic_uint16_t;
+
+typedef int32_t            atomic_int32_t;
+typedef uint32_t           atomic_uint32_t;
+
+typedef int64_t            atomic_int64_t;
+typedef uint64_t           atomic_uint64_t;
+
+typedef enum {
+    memory_order_relaxed = __ATOMIC_RELAXED,
+    memory_order_consume = __ATOMIC_CONSUME,
+    memory_order_acquire = __ATOMIC_ACQUIRE,
+    memory_order_release = __ATOMIC_RELEASE,
+    memory_order_acq_rel = __ATOMIC_ACQ_REL,
+    memory_order_seq_cst = __ATOMIC_SEQ_CST
+} memory_order;
+
+#define ATOMIC_VAR_INIT(VALUE) (VALUE)
+#define atomic_init(OBJECT, VALUE) (*(OBJECT) = (VALUE), (void) 0)
+
+#define atomic_thread_fence __atomic_thread_fence
+#define atomic_signal_fence __atomic_signal_fence
+#define atomic_is_lock_free __atomic_is_lock_free
+
+#define atomic_store(DST, SRC) \
+    atomic_store_explicit(DST, SRC, memory_order_seq_cst)
+#define atomic_store_explicit __atomic_store_n
+
+#define atomic_read(SRC, DST) \
+    atomic_read_explicit(SRC, DST, memory_order_seq_cst)
+#define atomic_read_explicit(SRC, DST, ORDER)   \
+    (*(DST) = __atomic_load_n(SRC, ORDER),      \
+     (void) 0)
+
+#define atomic_add(RMW, OPERAND, ORIG) \
+        atomic_add_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst)
+#define atomic_sub(RMW, OPERAND, ORIG) \
+        atomic_sub_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst)
+#define atomic_or(RMW, OPERAND, ORIG) \
+        atomic_or_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst)
+#define atomic_xor(RMW, OPERAND, ORIG) \
+        atomic_xor_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst)
+#define atomic_and(RMW, OPERAND, ORIG) \
+        atomic_and_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst)
+
+#define atomic_add_explicit(RMW, OPERAND, ORIG, ORDER)  \
+    (*(ORIG) = __atomic_fetch_add(RMW, OPERAND, ORDER), (void) 0)
+#define atomic_sub_explicit(RMW, OPERAND, ORIG, ORDER)  \
+    (*(ORIG) = __atomic_fetch_sub(RMW, OPERAND, ORDER), (void) 0)
+#define atomic_or_explicit(RMW, OPERAND, ORIG, ORDER)  \
+    (*(ORIG) = __atomic_fetch_or(RMW, OPERAND, ORDER), (void) 0)
+#define atomic_xor_explicit(RMW, OPERAND, ORIG, ORDER)  \
+    (*(ORIG) = __atomic_fetch_xor(RMW, OPERAND, ORDER), (void) 0)
+#define atomic_and_explicit(RMW, OPERAND, ORIG, ORDER)  \
+    (*(ORIG) = __atomic_fetch_and(RMW, OPERAND, ORDER), (void) 0)
+
+/* atomic_flag */
+
+typedef struct {
+    unsigned char b;
+} atomic_flag;
+#define ATOMIC_FLAG_INIT { .b = false }
+
+static inline bool
+atomic_flag_test_and_set_explicit(volatile atomic_flag *object,
+                                  memory_order order)
+{
+    return __atomic_test_and_set(&object->b, order);
+}
+
+static inline bool
+atomic_flag_test_and_set(volatile atomic_flag *object)
+{
+    return atomic_flag_test_and_set_explicit(object, memory_order_seq_cst);
+}
+
+static inline void
+atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order)
+{
+    __atomic_clear(object, order);
+}
+
+static inline void
+atomic_flag_clear(volatile atomic_flag *object)
+{
+    atomic_flag_clear_explicit(object, memory_order_seq_cst);
+}
diff --git a/lib/ovs-atomic-pthreads.c b/lib/ovs-atomic-pthreads.c
new file mode 100644
index 0000000..a501b82
--- /dev/null
+++ b/lib/ovs-atomic-pthreads.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include "ovs-atomic.h"
+#include "ovs-thread.h"
+
+#if OVS_ATOMIC_PTHREADS_IMPL
+bool
+atomic_flag_test_and_set(volatile atomic_flag *flag_)
+{
+    atomic_flag *flag = CONST_CAST(atomic_flag *, flag_);
+    bool old_value;
+
+    xpthread_mutex_lock(&flag->mutex);
+    old_value = flag->b;
+    flag->b = true;
+    xpthread_mutex_unlock(&flag->mutex);
+
+    return old_value;
+}
+
+bool
+atomic_flag_test_and_set_explicit(volatile atomic_flag *flag,
+                                  memory_order order OVS_UNUSED)
+{
+    return atomic_flag_test_and_set(flag);
+}
+
+void
+atomic_flag_clear(volatile atomic_flag *flag_)
+{
+    atomic_flag *flag = CONST_CAST(atomic_flag *, flag_);
+
+    xpthread_mutex_lock(&flag->mutex);
+    flag->b = false;
+    xpthread_mutex_unlock(&flag->mutex);
+}
+
+void
+atomic_flag_clear_explicit(volatile atomic_flag *flag,
+                           memory_order order OVS_UNUSED)
+{
+    return atomic_flag_clear(flag);
+}
+
+#endif  /* OVS_ATOMIC_PTHREADS_IMPL */
diff --git a/lib/ovs-atomic-pthreads.h b/lib/ovs-atomic-pthreads.h
new file mode 100644
index 0000000..9944a2a
--- /dev/null
+++ b/lib/ovs-atomic-pthreads.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2013 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This header implements atomic operation primitives using pthreads. */
+#ifndef IN_OVS_ATOMIC_H
+#error "This header should only be included indirectly via ovs-atomic.h."
+#endif
+
+#define OVS_ATOMIC_PTHREADS_IMPL 1
+
+#define DEFINE_PTHREAD_ATOMIC(TYPE, NAME)       \
+    typedef struct {                            \
+        TYPE value;                             \
+        pthread_mutex_t mutex;                  \
+    } NAME;
+
+#define ATOMIC_BOOL_LOCK_FREE 0
+DEFINE_PTHREAD_ATOMIC(bool, atomic_bool);
+
+#define ATOMIC_CHAR_LOCK_FREE 0
+DEFINE_PTHREAD_ATOMIC(char, atomic_char);
+DEFINE_PTHREAD_ATOMIC(signed char, atomic_schar);
+DEFINE_PTHREAD_ATOMIC(unsigned char, atomic_uchar);
+
+#define ATOMIC_SHORT_LOCK_FREE 0
+DEFINE_PTHREAD_ATOMIC(short, atomic_short);
+DEFINE_PTHREAD_ATOMIC(unsigned short, atomic_ushort);
+
+#define ATOMIC_INT_LOCK_FREE 0
+DEFINE_PTHREAD_ATOMIC(int, atomic_int);
+DEFINE_PTHREAD_ATOMIC(unsigned int, atomic_uint);
+
+#define ATOMIC_LONG_LOCK_FREE 0
+DEFINE_PTHREAD_ATOMIC(long, atomic_long);
+DEFINE_PTHREAD_ATOMIC(unsigned long, atomic_ulong);
+
+#define ATOMIC_LLONG_LOCK_FREE 0
+DEFINE_PTHREAD_ATOMIC(long long, atomic_llong);
+DEFINE_PTHREAD_ATOMIC(unsigned long long, atomic_ullong);
+
+DEFINE_PTHREAD_ATOMIC(size_t, atomic_size_t);
+DEFINE_PTHREAD_ATOMIC(ptrdiff_t, atomic_ptrdiff_t);
+
+DEFINE_PTHREAD_ATOMIC(intmax_t, atomic_intmax_t);
+DEFINE_PTHREAD_ATOMIC(uintmax_t, atomic_uintmax_t);
+
+#define ATOMIC_POINTER_LOCK_FREE 0
+DEFINE_PTHREAD_ATOMIC(intptr_t, atomic_intptr_t);
+DEFINE_PTHREAD_ATOMIC(uintptr_t, atomic_uintptr_t);
+
+/* Nonstandard atomic types. */
+DEFINE_PTHREAD_ATOMIC(uint8_t,  atomic_uint8_t);
+DEFINE_PTHREAD_ATOMIC(uint16_t, atomic_uint16_t);
+DEFINE_PTHREAD_ATOMIC(uint32_t, atomic_uint32_t);
+DEFINE_PTHREAD_ATOMIC(int8_t,   atomic_int8_t);
+DEFINE_PTHREAD_ATOMIC(int16_t,  atomic_int16_t);
+DEFINE_PTHREAD_ATOMIC(int32_t,  atomic_int32_t);
+DEFINE_PTHREAD_ATOMIC(uint64_t, atomic_uint64_t);
+DEFINE_PTHREAD_ATOMIC(int64_t,  atomic_int64_t);
+
+typedef enum {
+    memory_order_relaxed,
+    memory_order_consume,
+    memory_order_acquire,
+    memory_order_release,
+    memory_order_acq_rel,
+    memory_order_seq_cst
+} memory_order;
+
+#define ATOMIC_VAR_INIT(VALUE) { VALUE, PTHREAD_MUTEX_INITIALIZER }
+#define atomic_init(OBJECT, VALUE)                      \
+    ((OBJECT)->value = (VALUE),                         \
+     pthread_mutex_init(&(OBJECT)->mutex, NULL),        \
+     (void) 0)
+
+/* XXX kill_dependency */
+
+static inline void
+atomic_thread_fence(memory_order order OVS_UNUSED)
+{
+    /* Nothing to do. */
+}
+
+static inline void
+atomic_signal_fence(memory_order order OVS_UNUSED)
+{
+    /* Nothing to do. */
+}
+
+#define atomic_is_lock_free(OBJ) false
+
+#define atomic_store(DST, SRC)                  \
+    (pthread_mutex_lock(&(DST)->mutex),         \
+     (DST)->value = (SRC),                      \
+     pthread_mutex_unlock(&(DST)->mutex),       \
+     (void) 0)
+#define atomic_store_explicit(DST, SRC, ORDER) \
+    ((void) (ORDER), atomic_store(DST, SRC))
+
+#define atomic_read(SRC, DST)                                           \
+    (pthread_mutex_lock(CONST_CAST(pthread_mutex_t *, &(SRC)->mutex)),  \
+     *(DST) = (SRC)->value,                                             \
+     pthread_mutex_unlock(CONST_CAST(pthread_mutex_t *, &(SRC)->mutex)), \
+     (void) 0)
+#define atomic_read_explicit(SRC, DST, ORDER)   \
+    ((void) (ORDER), atomic_read(SRC, DST))
+
+#define atomic_op__(RMW, OPERATOR, OPERAND, ORIG)       \
+    (pthread_mutex_lock(&(RMW)->mutex),                 \
+     *(ORIG) = (RMW)->value,                            \
+     (RMW)->value OPERATOR (OPERAND),                   \
+     pthread_mutex_unlock(&(RMW)->mutex),               \
+     (void) 0)
+
+#define atomic_add(RMW, OPERAND, ORIG) atomic_op__(RMW, +=, OPERAND, ORIG)
+#define atomic_sub(RMW, OPERAND, ORIG) atomic_op__(RMW, -=, OPERAND, ORIG)
+#define atomic_or( RMW, OPERAND, ORIG) atomic_op__(RMW, |=, OPERAND, ORIG)
+#define atomic_xor(RMW, OPERAND, ORIG) atomic_op__(RMW, ^=, OPERAND, ORIG)
+#define atomic_and(RMW, OPERAND, ORIG) atomic_op__(RMW, &=, OPERAND, ORIG)
+
+#define atomic_add_explicit(RMW, OPERAND, ORIG, ORDER)  \
+    ((void) (ORDER), atomic_add(RMW, OPERAND, ORIG))
+#define atomic_sub_explicit(RMW, OPERAND, ORIG, ORDER)  \
+    ((void) (ORDER), atomic_sub(RMW, OPERAND, ORIG))
+#define atomic_or_explicit(RMW, OPERAND, ORIG, ORDER)   \
+    ((void) (ORDER), atomic_or(RMW, OPERAND, ORIG))
+#define atomic_xor_explicit(RMW, OPERAND, ORIG, ORDER)  \
+    ((void) (ORDER), atomic_xor(RMW, OPERAND, ORIG))
+#define atomic_and_explicit(RMW, OPERAND, ORIG, ORDER)  \
+    ((void) (ORDER), atomic_and(RMW, OPERAND, ORIG))
+
+/* atomic_flag */
+
+typedef struct {
+    bool b;
+    pthread_mutex_t mutex;
+} atomic_flag;
+#define ATOMIC_FLAG_INIT { false, PTHREAD_MUTEX_INITIALIZER }
+
+bool atomic_flag_test_and_set(volatile atomic_flag *);
+bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order);
+
+void atomic_flag_clear(volatile atomic_flag *);
+void atomic_flag_clear_explicit(volatile atomic_flag *, memory_order);
diff --git a/lib/ovs-atomic.h b/lib/ovs-atomic.h
new file mode 100644
index 0000000..257a8ce
--- /dev/null
+++ b/lib/ovs-atomic.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2013 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OVS_ATOMIC_H
+#define OVS_ATOMIC_H 1
+
+/* Atomic operations.
+ *
+ * This library implements atomic operations with an API based on the one
+ * defined in C11.  It includes multiple implementations for compilers and
+ * libraries with varying degrees of built-in support for C11, including an
+ * fallback implementation for systems that have pthreads but no other support
+ * for atomics.
+ *
+ * This comment describes the common features of all the implementations.
+ *
+ *
+ * Types
+ * =====
+ *
+ * The following atomic types are supported as typedefs for atomic versions of
+ * the listed ordinary types:
+ *
+ *     ordinary type            atomic version
+ *     -------------------      ----------------------
+ *     bool                     atomic_bool
+ *
+ *     char                     atomic_char
+ *     signed char              atomic_schar
+ *     unsigned char            atomic_uchar
+ *
+ *     short                    atomic_short
+ *     unsigned short           atomic_ushort
+ *
+ *     int                      atomic_int
+ *     unsigned int             atomic_uint
+ *
+ *     long                     atomic_long
+ *     unsigned long            atomic_ulong
+ *
+ *     long long                atomic_llong
+ *     unsigned long long       atomic_ullong
+ *
+ *     size_t                   atomic_size_t
+ *     ptrdiff_t                atomic_ptrdiff_t
+ *
+ *     intmax_t                 atomic_intmax_t
+ *     uintmax_t                atomic_uintmax_t
+ *
+ *     intptr_t                 atomic_intptr_t
+ *     uintptr_t                atomic_uintptr_t
+ *
+ *     uint8_t                  atomic_uint8_t     (*)
+ *     uint16_t                 atomic_uint16_t    (*)
+ *     uint32_t                 atomic_uint32_t    (*)
+ *     int8_t                   atomic_int8_t      (*)
+ *     int16_t                  atomic_int16_t     (*)
+ *     int32_t                  atomic_int32_t     (*)
+ *     uint64_t                 atomic_uint64_t    (*)
+ *     int64_t                  atomic_int64_t     (*)
+ *
+ *     (*) Not specified by C11.
+ *
+ * The atomic version of a type doesn't necessarily have the same size or
+ * representation as the ordinary version; for example, atomic_int might be a
+ * typedef for a struct that also includes a mutex.  The range of an atomic
+ * type does match the range of the corresponding ordinary type.
+ *
+ * C11 says that one may use the _Atomic keyword in place of the typedef name,
+ * e.g. "_Atomic int" instead of "atomic_int".  This library doesn't support
+ * that.
+ *
+ *
+ * Initialization
+ * ==============
+ *
+ * To initialize an atomic variable at its point of definition, use
+ * ATOMIC_VAR_INIT:
+ *
+ *     static atomic_int ai = ATOMIC_VAR_INIT(123);
+ *
+ * To initialize an atomic variable in code, use atomic_init():
+ *
+ *     static atomic_int ai;
+ * ...
+ *     atomic_init(&ai, 123);
+ *
+ *
+ * Barriers
+ * ========
+ *
+ * enum memory_order specifies the strictness of a memory barrier.  It has the
+ * following values:
+ *
+ *    memory_order_relaxed:
+ *
+ *        Compiler barrier only.  Does not imply any CPU memory ordering.
+ *
+ *    memory_order_acquire:
+ *
+ *        Memory accesses after an acquire barrier cannot be moved before the
+ *        barrier.  Memory accesses before an acquire barrier *can* be moved
+ *        after it.
+ *
+ *    memory_order_release:
+ *
+ *        Memory accesses before a release barrier cannot be moved after the
+ *        barrier.  Memory accesses after a release barrier *can* be moved
+ *        before it.
+ *
+ *    memory_order_acq_rel:
+ *
+ *        Memory accesses cannot be moved across an acquire-release barrier in
+ *        either direction.
+ *
+ *    memory_order_seq_cst:
+ *
+ *        Prevents movement of memory accesses like an acquire-release barrier,
+ *        but whereas acquire-release synchronizes cooperating threads,
+ *        sequential-consistency synchronizes the whole system.
+ *
+ *    memory_order_consume:
+ *
+ *        A slight relaxation of memory_order_acquire.
+ *
+ * The following functions insert explicit barriers.  Most of the other atomic
+ * functions also include barriers.
+ *
+ *     void atomic_thread_fence(memory_order order);
+ *
+ *         Inserts a barrier of the specified type.
+ *
+ *         For memory_order_relaxed, this is a no-op.
+ *
+ *     void atomic_signal_fence(memory_order order);
+ *
+ *         Inserts a barrier of the specified type, but only with respect to
+ *         signal handlers in the same thread as the barrier.  This is
+ *         basically a compiler optimization barrier, except for
+ *         memory_order_relaxed, which is a no-op.
+ *
+ *
+ * Atomic Operations
+ * =================
+ *
+ * In this section, A is an atomic type and C is the corresponding non-atomic
+ * type.
+ *
+ * The "store" primitives match C11:
+ *
+ *     void atomic_store(A *object, C value);
+ *     void atomic_store_explicit(A *object, C value, memory_order);
+ *
+ *         Atomically stores 'value' into '*object', respecting the given
+ *         memory order (or memory_order_seq_cst for atomic_store()).
+ *
+ * The following primitives differ from the C11 ones (and have different names)
+ * because there does not appear to be a way to implement the standard
+ * primitives in standard C:
+ *
+ *     void atomic_read(A *src, C *dst);
+ *     void atomic_read_explicit(A *src, C *dst, memory_order);
+ *
+ *         Atomically loads a value from 'src', writing the value read into
+ *         '*dst', respecting the given memory order (or memory_order_seq_cst
+ *         for atomic_read()).
+ *
+ *     void atomic_add(A *rmw, C arg, C *orig);
+ *     void atomic_sub(A *rmw, C arg, C *orig);
+ *     void atomic_or(A *rmw, C arg, C *orig);
+ *     void atomic_xor(A *rmw, C arg, C *orig);
+ *     void atomic_and(A *rmw, C arg, C *orig);
+ *     void atomic_add_explicit(A *rmw, C arg, C *orig, memory_order);
+ *     void atomic_sub_explicit(A *rmw, C arg, C *orig, memory_order);
+ *     void atomic_or_explicit(A *rmw, C arg, C *orig, memory_order);
+ *     void atomic_xor_explicit(A *rmw, C arg, C *orig, memory_order);
+ *     void atomic_and_explicit(A *rmw, C arg, C *orig, memory_order);
+ *
+ *         Atomically applies the given operation, with 'arg' as the second
+ *         operand, to '*rmw', and stores the original value of '*rmw' into
+ *         '*orig', respecting the given memory order (or memory_order_seq_cst
+ *         if none is specified).
+ *
+ *         The results are similar to those that would be obtained with +=, -=,
+ *         |=, ^=, or |= on non-atomic types.
+ *
+ *
+ * atomic_flag
+ * ===========
+ *
+ * atomic_flag is a typedef for a type with two states, set and clear, that
+ * provides atomic test-and-set functionality.
+ *
+ * ATOMIC_FLAG_INIT is an initializer for atomic_flag.  The initial state is
+ * "clear".
+ *
+ * The following functions are available.
+ *
+ *     bool atomic_flag_test_and_set(atomic_flag *object)
+ *     bool atomic_flag_test_and_set_explicit(atomic_flag *object,
+ *                                            memory_order);
+ *
+ *         Atomically sets '*object', respsecting the given memory order (or
+ *         memory_order_seq_cst for atomic_flag_test_and_set()).  Returns the
+ *         previous value of the flag (false for clear, true for set).
+ *
+ *     void atomic_flag_clear(atomic_flag *object);
+ *     void atomic_flag_clear_explicit(atomic_flag *object, memory_order);
+ *
+ *         Atomically clears '*object', respecting the given memory order (or
+ *         memory_order_seq_cst for atomic_flag_clear()).
+ */
+
+#include <limits.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include "compiler.h"
+#include "util.h"
+
+#define IN_OVS_ATOMIC_H
+    #ifdef HAVE_STDATOMIC_H
+        #include "ovs-atomic-c11.h"
+    #elif __CHECKER__
+        /* sparse doesn't understand some GCC extensions we use. */
+        #include "ovs-atomic-pthreads.h"
+    #elif __GNUC__ >= 4 && __GNUC_MINOR__ >= 7
+        #include "ovs-atomic-gcc4.7+.h"
+    #elif __GNUC__ >= 4
+        #include "ovs-atomic-gcc4+.h"
+    #else
+        #include "ovs-atomic-pthreads.h"
+    #endif
+#undef IN_OVS_ATOMIC_H
+
+#endif /* ovs-atomic.h */
diff --git a/m4/openvswitch.m4 b/m4/openvswitch.m4
index 97aafef..236ddf2 100644
--- a/m4/openvswitch.m4
+++ b/m4/openvswitch.m4
@@ -409,3 +409,24 @@ AC_DEFUN([OVS_CHECK___THREAD],
        [Define to 1 if the C compiler and linker support the GCC __thread
         extension for thread-local storage.])
    fi])
+
+dnl OVS_CHECK_ATOMIC_ALWAYS_LOCK_FREE(SIZE)
+dnl
+dnl Checks __atomic_always_lock_free(SIZE, 0)
+AC_DEFUN([OVS_CHECK_ATOMIC_ALWAYS_LOCK_FREE], 
+  [AC_CACHE_CHECK(
+    [value of __atomic_always_lock_free($1)],
+    [ovs_cv_atomic_always_lock_free_$1],
+    [AC_COMPUTE_INT(
+        [ovs_cv_atomic_always_lock_free_$1],
+        [__atomic_always_lock_free($1, 0)],
+        [],
+        [ovs_cv_atomic_always_lock_free_$1=unsupported])])
+   if test ovs_cv_atomic_always_lock_free_$1 != unsupported; then
+     AC_DEFINE_UNQUOTED(
+       [ATOMIC_ALWAYS_LOCK_FREE_$1B],
+       [$ovs_cv_atomic_always_lock_free_$1],
+       [If the C compiler is GCC 4.7 or later, define to the return value of
+        __atomic_always_lock_free($1, 0).  If the C compiler is not GCC or is
+        an older version of GCC, the value does not matter.])
+   fi])
diff --git a/tests/automake.mk b/tests/automake.mk
index 1af41cc..12aace3 100644
--- a/tests/automake.mk
+++ b/tests/automake.mk
@@ -97,6 +97,7 @@ valgrind_wrappers = \
 	tests/valgrind/ovsdb-server \
 	tests/valgrind/ovsdb-tool \
 	tests/valgrind/test-aes128 \
+	tests/valgrind/test-atomic \
 	tests/valgrind/test-bundle \
 	tests/valgrind/test-byte-order \
 	tests/valgrind/test-classifier \
@@ -175,6 +176,10 @@ noinst_PROGRAMS += tests/test-aes128
 tests_test_aes128_SOURCES = tests/test-aes128.c
 tests_test_aes128_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
 
+noinst_PROGRAMS += tests/test-atomic
+tests_test_atomic_SOURCES = tests/test-atomic.c
+tests_test_atomic_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
+
 noinst_PROGRAMS += tests/test-bundle
 tests_test_bundle_SOURCES = tests/test-bundle.c
 tests_test_bundle_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
diff --git a/tests/library.at b/tests/library.at
index 532af3b..f84a55b 100644
--- a/tests/library.at
+++ b/tests/library.at
@@ -25,6 +25,10 @@ AT_CHECK([test-hindex], [0], [..................
 ])
 AT_CLEANUP
 
+AT_SETUP([test atomic operations])
+AT_CHECK([test-atomic])
+AT_CLEANUP
+
 AT_SETUP([test linked lists])
 AT_CHECK([test-list], [0], [..
 ])
diff --git a/tests/test-atomic.c b/tests/test-atomic.c
new file mode 100644
index 0000000..27bf552
--- /dev/null
+++ b/tests/test-atomic.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2013 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include "ovs-atomic.h"
+#include "util.h"
+
+#define TEST_ATOMIC_TYPE(ATOMIC_TYPE, BASE_TYPE)        \
+    {                                                   \
+        ATOMIC_TYPE x = ATOMIC_VAR_INIT(1);             \
+        BASE_TYPE value, orig;                          \
+                                                        \
+        atomic_read(&x, &value);                        \
+        ovs_assert(value == 1);                         \
+                                                        \
+        atomic_store(&x, 2);                            \
+        atomic_read(&x, &value);                        \
+        ovs_assert(value == 2);                         \
+                                                        \
+        atomic_init(&x, 3);                             \
+        atomic_read(&x, &value);                        \
+        ovs_assert(value == 3);                         \
+                                                        \
+        atomic_add(&x, 1, &orig);                       \
+        ovs_assert(orig == 3);                          \
+        atomic_read(&x, &value);                        \
+        ovs_assert(value == 4);                         \
+                                                        \
+        atomic_sub(&x, 2, &orig);                       \
+        ovs_assert(orig == 4);                          \
+        atomic_read(&x, &value);                        \
+        ovs_assert(value == 2);                         \
+                                                        \
+        atomic_or(&x, 6, &orig);                        \
+        ovs_assert(orig == 2);                          \
+        atomic_read(&x, &value);                        \
+        ovs_assert(value == 6);                         \
+                                                        \
+        atomic_and(&x, 10, &orig);                      \
+        ovs_assert(orig == 6);                          \
+        atomic_read(&x, &value);                        \
+        ovs_assert(value == 2);                         \
+                                                        \
+        atomic_xor(&x, 10, &orig);                      \
+        ovs_assert(orig == 2);                          \
+        atomic_read(&x, &value);                        \
+        ovs_assert(value == 8);                         \
+    }
+
+int
+main(void)
+{
+    TEST_ATOMIC_TYPE(atomic_char, char);
+    TEST_ATOMIC_TYPE(atomic_uchar, unsigned char);
+    TEST_ATOMIC_TYPE(atomic_schar, signed char);
+    TEST_ATOMIC_TYPE(atomic_short, short);
+    TEST_ATOMIC_TYPE(atomic_ushort, unsigned short);
+    TEST_ATOMIC_TYPE(atomic_int, int);
+    TEST_ATOMIC_TYPE(atomic_uint, unsigned int);
+    TEST_ATOMIC_TYPE(atomic_long, long int);
+    TEST_ATOMIC_TYPE(atomic_ulong, unsigned long int);
+    TEST_ATOMIC_TYPE(atomic_llong, long long int);
+    TEST_ATOMIC_TYPE(atomic_ullong, unsigned long long int);
+    TEST_ATOMIC_TYPE(atomic_size_t, size_t);
+    TEST_ATOMIC_TYPE(atomic_ptrdiff_t, ptrdiff_t);
+    TEST_ATOMIC_TYPE(atomic_intmax_t, intmax_t);
+    TEST_ATOMIC_TYPE(atomic_uintmax_t, uintmax_t);
+    TEST_ATOMIC_TYPE(atomic_intptr_t, intptr_t);
+    TEST_ATOMIC_TYPE(atomic_uintptr_t, uintptr_t);
+    TEST_ATOMIC_TYPE(atomic_uint8_t, uint8_t);
+    TEST_ATOMIC_TYPE(atomic_int8_t, int8_t);
+    TEST_ATOMIC_TYPE(atomic_uint16_t, uint16_t);
+    TEST_ATOMIC_TYPE(atomic_int16_t, int16_t);
+    TEST_ATOMIC_TYPE(atomic_uint32_t, uint32_t);
+    TEST_ATOMIC_TYPE(atomic_int32_t, int32_t);
+    TEST_ATOMIC_TYPE(atomic_uint64_t, uint64_t);
+    TEST_ATOMIC_TYPE(atomic_int64_t, int64_t);
+
+    return 0;
+}
-- 
1.7.2.5




More information about the dev mailing list