Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add internal support for the new __atomic gcc builtins
Signed-off-by: Angus Salkeld <asalkeld@redhat.com>
- Loading branch information
Showing
2 changed files
with
156 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
/* | ||
* Copyright (C) 2013 Red Hat, Inc. | ||
* | ||
* Author: Angus Salkeld <asalkeld@redhat.com> | ||
* | ||
* 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 <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#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 <qb/qbdefs.h> | ||
#include <qb/qbatomic.h> | ||
|
||
/* 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 */ |