/* * 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 */