#ifndef _FI_ATOM_H_
#define _FI_ATOM_H_
#include "config.h"
#include <assert.h>
#include <pthread.h>
#include <stdlib.h>
#include <fi_lock.h>
#include <fi_osd.h>
#ifdef HAVE_ATOMICS
# include <stdatomic.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if ENABLE_DEBUG
#define ATOMIC_DEF_INIT int is_initialized
#define ATOMIC_IS_INITIALIZED(atomic) assert(atomic->is_initialized)
#define ATOMIC_INIT(atomic) atomic->is_initialized = 1
#else
#define ATOMIC_DEF_INIT
#define ATOMIC_IS_INITIALIZED(atomic)
#define ATOMIC_INIT(atomic)
#endif
#ifdef HAVE_ATOMICS
typedef atomic_int_least32_t ofi_atomic_int32_t;
typedef atomic_int_least64_t ofi_atomic_int64_t;
#define OFI_ATOMIC_DEFINE(radix) \
typedef struct { \
ofi_atomic_int##radix##_t val; \
ATOMIC_DEF_INIT; \
} ofi_atomic##radix##_t; \
\
static inline \
int##radix##_t ofi_atomic_inc##radix(ofi_atomic##radix##_t *atomic) \
{ \
ATOMIC_IS_INITIALIZED(atomic); \
return (int##radix##_t)atomic_fetch_add_explicit(&atomic->val, 1, \
memory_order_acq_rel) + 1; \
} \
static inline \
int##radix##_t ofi_atomic_dec##radix(ofi_atomic##radix##_t *atomic) \
{ \
ATOMIC_IS_INITIALIZED(atomic); \
return (int##radix##_t)atomic_fetch_sub_explicit(&atomic->val, 1, \
memory_order_acq_rel) - 1; \
} \
static inline \
int##radix##_t ofi_atomic_set##radix(ofi_atomic##radix##_t *atomic, int##radix##_t value) \
{ \
ATOMIC_IS_INITIALIZED(atomic); \
atomic_store(&atomic->val, value); \
return (int##radix##_t)value; \
} \
static inline \
int##radix##_t ofi_atomic_get##radix(ofi_atomic##radix##_t *atomic) \
{ \
ATOMIC_IS_INITIALIZED(atomic); \
return (int##radix##_t)atomic_load(&atomic->val); \
} \
static inline \
void ofi_atomic_initialize##radix(ofi_atomic##radix##_t *atomic, int##radix##_t value) \
{ \
atomic_init(&atomic->val, value); \
ATOMIC_INIT(atomic); \
} \
static inline \
int##radix##_t ofi_atomic_add##radix(ofi_atomic##radix##_t *atomic, int##radix##_t val) \
{ \
ATOMIC_IS_INITIALIZED(atomic); \
return (int##radix##_t)atomic_fetch_add_explicit(&atomic->val, val, \
memory_order_acq_rel) + val; \
} \
static inline \
int##radix##_t ofi_atomic_sub##radix(ofi_atomic##radix##_t *atomic, int##radix##_t val) \
{ \
ATOMIC_IS_INITIALIZED(atomic); \
return (int##radix##_t)atomic_fetch_sub_explicit(&atomic->val, val, \
memory_order_acq_rel) - val; \
}
#else
#define OFI_ATOMIC_DEFINE(radix) \
typedef struct { \
fastlock_t lock; \
int##radix##_t val; \
ATOMIC_DEF_INIT; \
} ofi_atomic##radix##_t; \
\
static inline \
int##radix##_t ofi_atomic_inc##radix(ofi_atomic##radix##_t *atomic) \
{ \
int##radix##_t v = 0; \
ATOMIC_IS_INITIALIZED(atomic); \
fastlock_acquire(&atomic->lock); \
v = ++(atomic->val); \
fastlock_release(&atomic->lock); \
return v; \
} \
static inline \
int##radix##_t ofi_atomic_dec##radix(ofi_atomic##radix##_t *atomic) \
{ \
int##radix##_t v = 0; \
ATOMIC_IS_INITIALIZED(atomic); \
fastlock_acquire(&atomic->lock); \
v = --(atomic->val); \
fastlock_release(&atomic->lock); \
return v; \
} \
static inline \
int##radix##_t ofi_atomic_set##radix(ofi_atomic##radix##_t *atomic, \
int##radix##_t value) \
{ \
ATOMIC_IS_INITIALIZED(atomic); \
fastlock_acquire(&atomic->lock); \
atomic->val = value; \
fastlock_release(&atomic->lock); \
return value; \
} \
static inline int##radix##_t ofi_atomic_get##radix(ofi_atomic##radix##_t *atomic) \
{ \
ATOMIC_IS_INITIALIZED(atomic); \
return atomic->val; \
} \
static inline \
void ofi_atomic_initialize##radix(ofi_atomic##radix##_t *atomic, \
int##radix##_t value) \
{ \
fastlock_init(&atomic->lock); \
atomic->val = value; \
ATOMIC_INIT(atomic); \
} \
static inline \
int##radix##_t ofi_atomic_add##radix(ofi_atomic##radix##_t *atomic, \
int##radix##_t val) \
{ \
int##radix##_t v; \
ATOMIC_IS_INITIALIZED(atomic); \
fastlock_acquire(&atomic->lock); \
atomic->val += val; \
v = atomic->val; \
fastlock_release(&atomic->lock); \
return v; \
} \
static inline \
int##radix##_t ofi_atomic_sub##radix(ofi_atomic##radix##_t *atomic, \
int##radix##_t val) \
{ \
int##radix##_t v; \
ATOMIC_IS_INITIALIZED(atomic); \
fastlock_acquire(&atomic->lock); \
atomic->val -= val; \
v = atomic->val; \
fastlock_release(&atomic->lock); \
return v; \
}
#endif
OFI_ATOMIC_DEFINE(32)
OFI_ATOMIC_DEFINE(64)
#ifdef __cplusplus
}
#endif
#endif