/** * \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 */