Files
ResInsight/ThirdParty/Ert/lib/include/ert/util/atomic.h
Magne Sjaastad 04091ad77d #4266 Update libecl
Use commit 0e1e780fd6f18ce93119061e36a4fca9711bc020

Excluded multibuild folder, as this caused git issues
2019-05-09 08:40:32 +02:00

184 lines
4.8 KiB
C
Raw Blame History

/*
Copyright (C) 2011 Equinor ASA, Norway.
The file 'atomic.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT 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 General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
/*
This whole file was something I found on the internet - it was
posted as beeing in the public domain. The essential functions
__sync_add_and_fetch() and do on are (as I understand it) built in
gcc functions. Only available in reasonably new gcc versions
(4.1???).
*/
#ifndef _ATOMIC_H
#define _ATOMIC_H
/**
<EFBFBD>* Atomic type.
<EFBFBD>*/
typedef struct {
volatile int counter;
} atomic_t;
#define ATOMIC_INIT(i) <20>{ (i) }
/**
<EFBFBD>* Read atomic variable
<EFBFBD>* @param v pointer of type atomic_t
<EFBFBD>*
<EFBFBD>* Atomically reads the value of @v.
<EFBFBD>*/
#define atomic_read(v) ((v)->counter)
/**
<EFBFBD>* Set atomic variable
<EFBFBD>* @param v pointer of type atomic_t
<EFBFBD>* @param i required value
<EFBFBD>*/
#define atomic_set(v,i) (((v)->counter) = (i))
/**
<EFBFBD>* Add to the atomic variable
<EFBFBD>* @param i integer value to add
<EFBFBD>* @param v pointer of type atomic_t
<EFBFBD>*/
static inline void atomic_add( int i, atomic_t *v )
{
(void)__sync_add_and_fetch(&v->counter, i);
}
/**
<EFBFBD>* Subtract the atomic variable
<EFBFBD>* @param i integer value to subtract
<EFBFBD>* @param v pointer of type atomic_t
<EFBFBD>*
<EFBFBD>* Atomically subtracts @i from @v.
<EFBFBD>*/
static inline void atomic_sub( int i, atomic_t *v )
{
(void)__sync_sub_and_fetch(&v->counter, i);
}
/**
<EFBFBD>* Subtract value from variable and test result
<EFBFBD>* @param i integer value to subtract
<EFBFBD>* @param v pointer of type atomic_t
<EFBFBD>*
<EFBFBD>* Atomically subtracts @i from @v and returns
<EFBFBD>* true if the result is zero, or false for all
<EFBFBD>* other cases.
<EFBFBD>*/
static inline int atomic_sub_and_test( int i, atomic_t *v )
{
return !(__sync_sub_and_fetch(&v->counter, i));
}
/**
<EFBFBD>* Increment atomic variable
<EFBFBD>* @param v pointer of type atomic_t
<EFBFBD>*
<EFBFBD>* Atomically increments @v by 1.
<EFBFBD>*/
static inline void atomic_inc( atomic_t *v )
{
(void)__sync_fetch_and_add(&v->counter, 1);
}
/**
<EFBFBD>* @brief decrement atomic variable
<EFBFBD>* @param v: pointer of type atomic_t
<EFBFBD>*
<EFBFBD>* Atomically decrements @v by 1. <20>Note that the guaranteed
<EFBFBD>* useful range of an atomic_t is only 24 bits.
<EFBFBD>*/
static inline void atomic_dec( atomic_t *v )
{
(void)__sync_fetch_and_sub(&v->counter, 1);
}
/**
<EFBFBD>* @brief Decrement and test
<EFBFBD>* @param v pointer of type atomic_t
<EFBFBD>*
<EFBFBD>* Atomically decrements @v by 1 and
<EFBFBD>* returns true if the result is 0, or false for all other
<EFBFBD>* cases.
<EFBFBD>*/
static inline int atomic_dec_and_test( atomic_t *v )
{
return !(__sync_sub_and_fetch(&v->counter, 1));
}
/**
<EFBFBD>* @brief Increment and test
<EFBFBD>* @param v pointer of type atomic_t
<EFBFBD>*
<EFBFBD>* Atomically increments @v by 1
<EFBFBD>* and returns true if the result is zero, or false for all
<EFBFBD>* other cases.
<EFBFBD>*/
static inline int atomic_inc_and_test( atomic_t *v )
{
return !(__sync_add_and_fetch(&v->counter, 1));
}
/**
<EFBFBD>* @brief add and test if negative
<EFBFBD>* @param v pointer of type atomic_t
<EFBFBD>* @param i integer value to add
<EFBFBD>*
<EFBFBD>* Atomically adds @i to @v and returns true
<EFBFBD>* if the result is negative, or false when
<EFBFBD>* result is greater than or equal to zero.
<EFBFBD>*/
static inline int atomic_add_negative( int i, atomic_t *v )
{
return (__sync_add_and_fetch(&v->counter, i) < 0);
}
#endif
/*****************************************************************/
/*****************************************************************/
/*****************************************************************/
///* ALternative implementations: */
////Pretty straight forward isn't it? It could be even more powerful and simpler if you don't need precise compatibility with atomic.h. For example, atomic_add could easily return the result values:
//static inline int atomic_add( int i, atomic_t *v )
//{
// return __sync_add_and_fetch(&v->counter, i);
//}
//
////As a second example, consider a compare and swap operation, frequently used in lock-free algorithms. Once again, it's trivially:
///**
//<2F>* @brief compare and swap
//<2F>* @param v pointer of type atomic_t
//<2F>*
//<2F>* If the current value of @b v is @b oldval,
//<2F>* then write @b newval into @b v. Returns #TRUE if
//<2F>* the comparison is successful and @b newval was
//<2F>* written.
//<2F>*/
//static inline int atomic_cas( atomic_t *v, int oldval, int newval )
//{
// return __sync_bool_compare_and_swap(&v->counter, oldval, newval);
//}