diff options
Diffstat (limited to 'src/ref.h')
| -rw-r--r-- | src/ref.h | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/src/ref.h b/src/ref.h new file mode 100644 index 0000000..ea36ec7 --- /dev/null +++ b/src/ref.h @@ -0,0 +1,95 @@ +/** + * \file ref.h + * Thread-safe reference counter. + */ + +#ifndef REF_H +#define REF_H + +#if __GNUC__ >= 4 +# define REF_DECLARE() volatile int _ref +# define REF_INIT(ptr) \ + ((ptr)->_ref = 1) +# define REF_FREE(ptr) +# define REF_INC(ptr) \ + __sync_add_and_fetch(&((ptr)->_ref), 1) +# define REF_DEC(ptr) \ + (__sync_sub_and_fetch(&((ptr)->_ref), 1) <= 0) + +#else +# warning Unsupported compiler, horrible fallback threadsafe reference counters + +# include "thread.h" + +/** + * Declare reference counter. Use in struct declaration. + */ +# define REF_DECLARE() int _ref; thread_lock_t* _reflock +/** + * Initialize reference counter. Must be first MACRO used. + * @param ptr pointer to the struct, may not be NULL + * @return false in case of allocation errors + */ +# define REF_INIT(ptr) \ + _ref_init(&((ptr)->_ref), &((ptr)->_reflock)) +/** + * Free reference counter. + * @param ptr pointer to the struct, may not be NULL + */ +# define REF_FREE(ptr) thread_lock_free((ptr)->_reflock) +/** + * Increase reference counter. + * @param ptr pointer to the struct, may not be NULL + */ +# define REF_INC(ptr) _ref_inc(&((ptr)->_ref), (ptr)->_reflock) +/** + * Decrease reference counter. + * @param ptr pointer to the struct, may not be NULL + * @return true if reference counter now is zero + */ +# define REF_DEC(ptr) _ref_dec(&((ptr)->_ref), (ptr)->_reflock) + +/** + * Fallback implementation of REF_INIT. + * @param value pointer to reference counter, may not be NULL + * @param lock pointer to reference counter lock, may not be NULL + * @return true if both pointers was initialized correctly + */ +static inline NONULL bool _ref_init(int* value, thread_lock_t** lock) +{ + assert(value); + assert(lock); + *value = 1; + *lock = thread_lock_new(); + return *lock; +} + +/** + * Fallback implementation of REF_INC. + * @param value pointer to reference counter, may not be NULL + * @param lock reference counter lock, may not be NULL + */ +static inline NONULL void _ref_inc(int* value, thread_lock_t* lock) +{ + thread_lock_lock(lock); + (*value)++; + thread_lock_unlock(lock); +} + +/** + * Fallback implementation of REF_DEC. + * @param value pointer to reference counter, may not be NULL + * @param lock reference counter lock, may not be NULL + * @return true if reference counter was decreased to 0 + */ +static inline NONULL bool _ref_dec(int* value, thread_lock_t* lock) +{ + bool ret; + thread_lock_lock(lock); + ret = --(*value) == 0; + thread_lock_unlock(lock); + return ret; +} +#endif + +#endif /* REF_H */ |
