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

Ethan Jackson ethan at nicira.com
Fri Jun 28 22:14:36 UTC 2013


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 <ethan at nicira.com>

On Wed, Jun 19, 2013 at 1:17 PM, Ben Pfaff <blp at 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 <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
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
X-CudaMail-Whitelist-To: dev at openvswitch.org



More information about the dev mailing list