summaryrefslogtreecommitdiff
path: root/src/ref.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/ref.h')
-rw-r--r--src/ref.h95
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 */