From 6f382aaade4369df28b23737fff43512ca2a08d0 Mon Sep 17 00:00:00 2001 From: Angus Salkeld Date: Mon, 13 May 2013 10:06:18 +1000 Subject: [PATCH] Add internal support for the new __atomic gcc builtins Signed-off-by: Angus Salkeld --- configure.ac | 26 +++++++++- lib/atomic_int.h | 131 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 lib/atomic_int.h diff --git a/configure.ac b/configure.ac index a381cc1..a4dc7c0 100644 --- a/configure.ac +++ b/configure.ac @@ -365,6 +365,30 @@ if test "x$gcc_has_builtin_sync_operations" = xyes; then [have builtin sync operations]) fi +# __atomic_XXX +AC_MSG_CHECKING([whether GCC supports builtin atomic intrinsics]) +if test -z "$gcc_has_builtin_atomic_operations"; then + gcc_has_builtin_atomic_operations=no + if test x"$GCC" = xyes && test x$have_mingw != xyes; then + AC_TRY_LINK([], + [int i; + __atomic_load_n(&i, __ATOMIC_ACQUIRE); + __atomic_exchange_n(&i, 0, __ATOMIC_RELEASE); + ], + [gcc_has_builtin_atomic_operations=yes], + [gcc_has_builtin_atomic_operations=no]) + fi +fi +AC_MSG_RESULT($gcc_has_builtin_atomic_operations) +AM_CONDITIONAL(HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS, + [test "x$gcc_has_builtin_atomic_operations" = xyes]) + +if test "x$gcc_has_builtin_atomic_operations" = xyes; then + AC_DEFINE_UNQUOTED(HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS, 1, + [have builtin atomic operations]) +fi + + AC_MSG_CHECKING([whether atomics need memory barrier]) if test -n "$ac_cv_atomic_need_memory_barrier"; then memory_barrier_needed=$ac_cv_atomic_need_memory_barrier @@ -389,7 +413,7 @@ fi LINT_FLAGS="-syntax -weak -unrecog +posixlib +ignoresigns -fcnuse \ -badflag -D__gnuc_va_list=va_list -D__attribute\(x\)= \ - -warnposix +matchanyintegral" + -warnposix +matchanyintegral -sysunrecog" # local options AC_ARG_ENABLE([ansi], diff --git a/lib/atomic_int.h b/lib/atomic_int.h new file mode 100644 index 0000000..63f49fd --- /dev/null +++ b/lib/atomic_int.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * Author: Angus Salkeld + * + * libqb is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * libqb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libqb. If not, see . + */ + +#ifndef QB_ATOMIC_INT_H_DEFINED +#define QB_ATOMIC_INT_H_DEFINED + +/* + * This adds some extra atomic functionality, building on the + * gcc atomic builtins. + */ + +#include "os_base.h" +#include +#include + +/* This is a thin wrapper around the new gcc atomics. + */ +enum qb_atomic_model { + QB_ATOMIC_RELAXED, + QB_ATOMIC_CONSUME, + QB_ATOMIC_ACQUIRE, + QB_ATOMIC_RELEASE, + QB_ATOMIC_ACQ_REL, + QB_ATOMIC_SEQ_CST, +}; + +#ifdef HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS +static inline int +qb_model_map(enum qb_atomic_model model) +{ + switch (model) { + case QB_ATOMIC_ACQUIRE: + return __ATOMIC_ACQUIRE; + case QB_ATOMIC_RELEASE: + return __ATOMIC_RELEASE; + case QB_ATOMIC_RELAXED: + return __ATOMIC_RELAXED; + case QB_ATOMIC_CONSUME: + return __ATOMIC_CONSUME; + case QB_ATOMIC_ACQ_REL: + return __ATOMIC_ACQ_REL; + case QB_ATOMIC_SEQ_CST: + default: + return __ATOMIC_SEQ_CST; + } +} +#endif /* HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS */ + +#ifdef QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED + +#ifdef HAVE_GCC_BUILTINS_FOR_SYNC_OPERATIONS +#define QB_ATOMIC_MEMORY_BARRIER __sync_synchronize () +#else +#ifndef HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS +#warning you need memory barriers but do not have an implementation. +#endif /* HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS */ +#endif /* HAVE_GCC_BUILTINS_FOR_SYNC_OPERATIONS */ + +#ifndef QB_ATOMIC_MEMORY_BARRIER +#define QB_ATOMIC_MEMORY_BARRIER +#endif /* QB_ATOMIC_MEMORY_BARRIER */ + +#endif /* QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ + +/** + * Reads the value of the integer pointed to by atomic. + * Also acts as a memory barrier. + * + * @param atomic a pointer to an integer + * @param model the memory model to use. + * + * @return the value of atomic + */ +static inline int32_t +qb_atomic_int_get_ex(volatile int32_t QB_GNUC_MAY_ALIAS * atomic, + enum qb_atomic_model model) +{ +#ifdef HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS + return __atomic_load_n(atomic, qb_model_map(model)); +#else + return qb_atomic_int_get(atomic); +#endif +} + + +/** + * Sets the value of the integer pointed to by atomic. + * Also acts as a memory barrier. + * + * @param atomic a pointer to an integer + * @param newval the new value + * @param model the memory model to use. + */ +static inline void +qb_atomic_int_set_ex(volatile int32_t QB_GNUC_MAY_ALIAS * atomic, + int32_t newval, + enum qb_atomic_model model) +{ +#ifdef HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS + __atomic_store_n(atomic, newval, qb_model_map(model)); +#else +/* + * If the model is acquire we need the barrier afterwards, + * and if its cst we need it before and after. + * Note: qb_atomic_int_set already has a memory barrier after + * the set. + */ + if (model != QB_ATOMIC_RELAXED && model != QB_ATOMIC_CONSUME) { + QB_ATOMIC_MEMORY_BARRIER; + } + qb_atomic_int_set(atomic, newval); +#endif +} + +#endif /* QB_ATOMIC_INT_H_DEFINED */