#ifndef OFI_ATOMIC_QUEUE_H
#define OFI_ATOMIC_QUEUE_H
#include <ofi_atom.h>
#ifdef __cplusplus
extern "C" {
#endif
#define OFI_CACHE_LINE_SIZE (64)
#define OFI_DECLARE_ATOMIC_Q(entrytype, name) \
struct name ## _entry { \
ofi_atomic64_t seq; \
bool noop; \
entrytype buf; \
} __attribute__((__aligned__(64))); \
\
struct name { \
ofi_atomic64_t write_pos; \
uint8_t pad0[OFI_CACHE_LINE_SIZE - \
sizeof(ofi_atomic64_t)]; \
ofi_atomic64_t read_pos; \
uint8_t pad1[OFI_CACHE_LINE_SIZE - \
sizeof(ofi_atomic64_t)]; \
int size; \
int size_mask; \
uint8_t pad2[OFI_CACHE_LINE_SIZE - \
(sizeof(int) * 2)]; \
struct name ## _entry entry[]; \
} __attribute__((__aligned__(64))); \
\
static inline void name ## _init(struct name *aq, size_t size) \
{ \
size_t i; \
assert(size == roundup_power_of_two(size)); \
assert(!((uintptr_t) aq % OFI_CACHE_LINE_SIZE)); \
aq->size = size; \
aq->size_mask = aq->size - 1; \
ofi_atomic_initialize64(&aq->write_pos, 0); \
ofi_atomic_initialize64(&aq->read_pos, 0); \
for (i = 0; i < size; i++) \
ofi_atomic_initialize64(&aq->entry[i].seq, i); \
} \
\
static inline struct name * name ## _create(size_t size) \
{ \
struct name *aq; \
aq = (struct name*) calloc(1, sizeof(*aq) + \
sizeof(struct name ## _entry) * \
(roundup_power_of_two(size))); \
if (aq) \
name ##_init(aq, roundup_power_of_two(size)); \
return aq; \
} \
\
static inline void name ## _free(struct name *aq) \
{ \
free(aq); \
} \
static inline int name ## _next(struct name *aq, \
entrytype **buf, int64_t *pos) \
{ \
struct name ## _entry *ce; \
int64_t diff, seq; \
*pos = ofi_atomic_load_explicit64(&aq->write_pos, \
memory_order_relaxed); \
for (;;) { \
ce = &aq->entry[*pos & aq->size_mask]; \
seq = ofi_atomic_load_explicit64(&(ce->seq), \
memory_order_acquire); \
diff = seq - *pos; \
if (diff == 0) { \
if (ofi_atomic_compare_exchange_weak64( \
&aq->write_pos, pos, \
*pos + 1)) \
break; \
} else if (diff < 0) { \
return -FI_ENOENT; \
} else { \
*pos = ofi_atomic_load_explicit64( \
&aq->write_pos, \
memory_order_relaxed); \
} \
} \
*buf = &ce->buf; \
return FI_SUCCESS; \
} \
static inline void name ## _release(struct name *aq, \
entrytype *buf, \
int64_t pos) \
{ \
struct name ## _entry *ce; \
ce = container_of(buf, struct name ## _entry, buf); \
ofi_atomic_store_explicit64(&ce->seq, \
pos + aq->size, \
memory_order_release); \
} \
static inline int name ## _head(struct name *aq, \
entrytype **buf, int64_t *pos) \
{ \
int64_t diff, seq; \
struct name ## _entry *ce; \
again: \
*pos = ofi_atomic_load_explicit64(&aq->read_pos, \
memory_order_relaxed); \
for (;;) { \
ce = &aq->entry[*pos & aq->size_mask]; \
seq = ofi_atomic_load_explicit64(&(ce->seq), \
memory_order_acquire); \
diff = seq - (*pos + 1); \
if (diff == 0) { \
if (ofi_atomic_compare_exchange_weak64( \
&aq->read_pos, pos, \
*pos + 1)) \
break; \
} else if (diff < 0) { \
return -FI_ENOENT; \
} else { \
*pos = ofi_atomic_load_explicit64( \
&aq->read_pos, \
memory_order_relaxed); \
} \
} \
*buf = &ce->buf; \
if (ce->noop) { \
ce->noop = false; \
name ##_release(aq, *buf, *pos); \
goto again; \
} \
return FI_SUCCESS; \
} \
static inline void name ## _commit(entrytype *buf, \
int64_t pos) \
{ \
struct name ## _entry *ce; \
ce = container_of(buf, struct name ## _entry, buf); \
ofi_atomic_store_explicit64(&ce->seq, pos + 1, \
memory_order_release); \
} \
static inline void name ## _discard(entrytype *buf, \
int64_t pos) \
{ \
struct name ## _entry *ce; \
ce = container_of(buf, struct name ## _entry, buf); \
ce->noop = true; \
ofi_atomic_store_explicit64(&ce->seq, pos + 1, \
memory_order_release); \
} \
void dummy ## name (void)
#ifdef __cplusplus
}
#endif
#endif