|
Packit |
979a56 |
/*
|
|
Packit |
979a56 |
* Copyright (C) 2013 Red Hat, Inc.
|
|
Packit |
979a56 |
*
|
|
Packit |
979a56 |
* Author: Angus Salkeld <asalkeld@redhat.com>
|
|
Packit |
979a56 |
*
|
|
Packit |
979a56 |
* libqb is free software: you can redistribute it and/or modify
|
|
Packit |
979a56 |
* it under the terms of the GNU Lesser General Public License as published by
|
|
Packit |
979a56 |
* the Free Software Foundation, either version 2.1 of the License, or
|
|
Packit |
979a56 |
* (at your option) any later version.
|
|
Packit |
979a56 |
*
|
|
Packit |
979a56 |
* libqb is distributed in the hope that it will be useful,
|
|
Packit |
979a56 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
979a56 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
979a56 |
* GNU Lesser General Public License for more details.
|
|
Packit |
979a56 |
*
|
|
Packit |
979a56 |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit |
979a56 |
* along with libqb. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
979a56 |
*/
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
#ifndef QB_ATOMIC_INT_H_DEFINED
|
|
Packit |
979a56 |
#define QB_ATOMIC_INT_H_DEFINED
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
/*
|
|
Packit |
979a56 |
* This adds some extra atomic functionality, building on the
|
|
Packit |
979a56 |
* gcc atomic builtins.
|
|
Packit |
979a56 |
*/
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
#include "os_base.h"
|
|
Packit |
979a56 |
#include <qb/qbdefs.h>
|
|
Packit |
979a56 |
#include <qb/qbatomic.h>
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
/* This is a thin wrapper around the new gcc atomics.
|
|
Packit |
979a56 |
*/
|
|
Packit |
979a56 |
enum qb_atomic_model {
|
|
Packit |
979a56 |
QB_ATOMIC_RELAXED,
|
|
Packit |
979a56 |
QB_ATOMIC_CONSUME,
|
|
Packit |
979a56 |
QB_ATOMIC_ACQUIRE,
|
|
Packit |
979a56 |
QB_ATOMIC_RELEASE,
|
|
Packit |
979a56 |
QB_ATOMIC_ACQ_REL,
|
|
Packit |
979a56 |
QB_ATOMIC_SEQ_CST,
|
|
Packit |
979a56 |
};
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
#ifdef HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS
|
|
Packit |
979a56 |
static inline int
|
|
Packit |
979a56 |
qb_model_map(enum qb_atomic_model model)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
switch (model) {
|
|
Packit |
979a56 |
case QB_ATOMIC_ACQUIRE:
|
|
Packit |
979a56 |
return __ATOMIC_ACQUIRE;
|
|
Packit |
979a56 |
case QB_ATOMIC_RELEASE:
|
|
Packit |
979a56 |
return __ATOMIC_RELEASE;
|
|
Packit |
979a56 |
case QB_ATOMIC_RELAXED:
|
|
Packit |
979a56 |
return __ATOMIC_RELAXED;
|
|
Packit |
979a56 |
case QB_ATOMIC_CONSUME:
|
|
Packit |
979a56 |
return __ATOMIC_CONSUME;
|
|
Packit |
979a56 |
case QB_ATOMIC_ACQ_REL:
|
|
Packit |
979a56 |
return __ATOMIC_ACQ_REL;
|
|
Packit |
979a56 |
case QB_ATOMIC_SEQ_CST:
|
|
Packit |
979a56 |
default:
|
|
Packit |
979a56 |
return __ATOMIC_SEQ_CST;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
#endif /* HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS */
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
#ifdef QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
#ifdef HAVE_GCC_BUILTINS_FOR_SYNC_OPERATIONS
|
|
Packit |
979a56 |
#define QB_ATOMIC_MEMORY_BARRIER __sync_synchronize ()
|
|
Packit |
979a56 |
#else
|
|
Packit |
979a56 |
#ifndef HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS
|
|
Packit |
979a56 |
#warning you need memory barriers but do not have an implementation.
|
|
Packit |
979a56 |
#endif /* HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS */
|
|
Packit |
979a56 |
#endif /* HAVE_GCC_BUILTINS_FOR_SYNC_OPERATIONS */
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
#ifndef QB_ATOMIC_MEMORY_BARRIER
|
|
Packit |
979a56 |
#define QB_ATOMIC_MEMORY_BARRIER
|
|
Packit |
979a56 |
#endif /* QB_ATOMIC_MEMORY_BARRIER */
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
#endif /* QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
/**
|
|
Packit |
979a56 |
* Reads the value of the integer pointed to by atomic.
|
|
Packit |
979a56 |
* Also acts as a memory barrier.
|
|
Packit |
979a56 |
*
|
|
Packit |
979a56 |
* @param atomic a pointer to an integer
|
|
Packit |
979a56 |
* @param model the memory model to use.
|
|
Packit |
979a56 |
*
|
|
Packit |
979a56 |
* @return the value of atomic
|
|
Packit |
979a56 |
*/
|
|
Packit |
979a56 |
static inline int32_t
|
|
Packit |
979a56 |
qb_atomic_int_get_ex(volatile int32_t QB_GNUC_MAY_ALIAS * atomic,
|
|
Packit |
979a56 |
enum qb_atomic_model model)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
#ifdef HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS
|
|
Packit |
979a56 |
return __atomic_load_n(atomic, qb_model_map(model));
|
|
Packit |
979a56 |
#else
|
|
Packit |
979a56 |
return qb_atomic_int_get(atomic);
|
|
Packit |
979a56 |
#endif
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
/**
|
|
Packit |
979a56 |
* Sets the value of the integer pointed to by atomic.
|
|
Packit |
979a56 |
* Also acts as a memory barrier.
|
|
Packit |
979a56 |
*
|
|
Packit |
979a56 |
* @param atomic a pointer to an integer
|
|
Packit |
979a56 |
* @param newval the new value
|
|
Packit |
979a56 |
* @param model the memory model to use.
|
|
Packit |
979a56 |
*/
|
|
Packit |
979a56 |
static inline void
|
|
Packit |
979a56 |
qb_atomic_int_set_ex(volatile int32_t QB_GNUC_MAY_ALIAS * atomic,
|
|
Packit |
979a56 |
int32_t newval,
|
|
Packit |
979a56 |
enum qb_atomic_model model)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
#ifdef HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS
|
|
Packit |
979a56 |
__atomic_store_n(atomic, newval, qb_model_map(model));
|
|
Packit |
979a56 |
#else
|
|
Packit |
979a56 |
/*
|
|
Packit |
979a56 |
* If the model is acquire we need the barrier afterwards,
|
|
Packit |
979a56 |
* and if its cst we need it before and after.
|
|
Packit |
979a56 |
* Note: qb_atomic_int_set already has a memory barrier after
|
|
Packit |
979a56 |
* the set.
|
|
Packit |
979a56 |
*/
|
|
Packit |
979a56 |
if (model != QB_ATOMIC_RELAXED && model != QB_ATOMIC_CONSUME) {
|
|
Packit |
979a56 |
QB_ATOMIC_MEMORY_BARRIER;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
qb_atomic_int_set(atomic, newval);
|
|
Packit |
979a56 |
#endif
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
#endif /* QB_ATOMIC_INT_H_DEFINED */
|