Support GCC and clang versions that lack <stdatomic.h>.
Add a code path to use the GCC builtins for atomics, which are supported in older compiler versions, rather than the new <stdatomic.h>.
This commit is contained in:
@@ -13,14 +13,20 @@
|
|||||||
#define REFCOUNT_H
|
#define REFCOUNT_H
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#if !defined(__GNUC__)
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
|
#endif
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "locking.h"
|
#include "locking.h"
|
||||||
|
|
||||||
// Simple reference counter.
|
// Simple reference counter.
|
||||||
struct LOCKABLE refcount {
|
struct LOCKABLE refcount {
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
unsigned count;
|
||||||
|
#else
|
||||||
atomic_uint count;
|
atomic_uint count;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PRODUCES(...) LOCKS_SHARED(__VA_ARGS__) NO_LOCK_ANALYSIS
|
#define PRODUCES(...) LOCKS_SHARED(__VA_ARGS__) NO_LOCK_ANALYSIS
|
||||||
@@ -28,18 +34,30 @@ struct LOCKABLE refcount {
|
|||||||
|
|
||||||
// Initialize the reference counter.
|
// Initialize the reference counter.
|
||||||
static void refcount_init(struct refcount *r, unsigned int count) PRODUCES(*r) {
|
static void refcount_init(struct refcount *r, unsigned int count) PRODUCES(*r) {
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
__atomic_store_n(&r->count, count, __ATOMIC_SEQ_CST);
|
||||||
|
#else
|
||||||
atomic_init(&r->count, count);
|
atomic_init(&r->count, count);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment the reference counter.
|
// Increment the reference counter.
|
||||||
static inline void refcount_acquire(struct refcount *r) PRODUCES(*r) {
|
static inline void refcount_acquire(struct refcount *r) PRODUCES(*r) {
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
__atomic_fetch_add(&r->count, 1, __ATOMIC_ACQUIRE);
|
||||||
|
#else
|
||||||
atomic_fetch_add_explicit(&r->count, 1, memory_order_acquire);
|
atomic_fetch_add_explicit(&r->count, 1, memory_order_acquire);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrement the reference counter, returning whether the reference
|
// Decrement the reference counter, returning whether the reference
|
||||||
// dropped to zero.
|
// dropped to zero.
|
||||||
static inline bool refcount_release(struct refcount *r) CONSUMES(*r) {
|
static inline bool refcount_release(struct refcount *r) CONSUMES(*r) {
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
int old = __atomic_fetch_sub(&r->count, 1, __ATOMIC_RELEASE);
|
||||||
|
#else
|
||||||
int old = atomic_fetch_sub_explicit(&r->count, 1, memory_order_release);
|
int old = atomic_fetch_sub_explicit(&r->count, 1, memory_order_release);
|
||||||
|
#endif
|
||||||
assert(old != 0 && "Reference count becoming negative");
|
assert(old != 0 && "Reference count becoming negative");
|
||||||
return old == 1;
|
return old == 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user