Thanks for writing up something so thorough. Better to get it done now then jerry rig stuff ad hoc as we need it.
There are a couple of "XXX kill_dependency" comments in the code. Could you expand the comment a bit to explain what it's referring to? In ovs-atomic.h is it fair to assume that sparse supports c11 features? If not, does it make ense to check if __CHECKER__ before checking if HAVE_STDATOMIC? Acked-by: Ethan Jackson <et...@nicira.com> On Wed, Jun 19, 2013 at 1:17 PM, Ben Pfaff <b...@nicira.com> wrote: > This library should prove useful for the threading changes coming up. > The following commit introduces one (very simple) user. > > Signed-off-by: Ben Pfaff <b...@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 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev X-CudaMail-Whitelist-To: dev@openvswitch.org _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev