[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