*/
#include <assert.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <stdlib.h>
#include <urcu/uatomic.h>
struct urcu_ref {
urcu_ref_set(ref, 1);
}
+static inline bool __attribute__((warn_unused_result))
+ urcu_ref_get_safe(struct urcu_ref *ref)
+{
+ long old, _new, res;
+
+ old = uatomic_read(&ref->refcount);
+ for (;;) {
+ if (old == LONG_MAX) {
+ return false; /* Failure. */
+ }
+ _new = old + 1;
+ res = uatomic_cmpxchg(&ref->refcount, old, _new);
+ if (res == old) {
+ return true; /* Success. */
+ }
+ old = res;
+ }
+}
+
static inline void urcu_ref_get(struct urcu_ref *ref)
{
- uatomic_add(&ref->refcount, 1);
+ if (!urcu_ref_get_safe(ref))
+ abort();
}
static inline void urcu_ref_put(struct urcu_ref *ref,
release(ref);
}
+/*
+ * urcu_ref_get_unless_zero
+ *
+ * Allows getting a reference atomically if the reference count is not
+ * zero. Returns true if the reference is taken, false otherwise. This
+ * needs to be used in conjunction with another synchronization
+ * technique (e.g. RCU or mutex) to ensure existence of the reference
+ * count. False is also returned in case incrementing the refcount would
+ * result in an overflow.
+ */
+static inline bool urcu_ref_get_unless_zero(struct urcu_ref *ref)
+{
+ long old, _new, res;
+
+ old = uatomic_read(&ref->refcount);
+ for (;;) {
+ if (old == 0 || old == LONG_MAX)
+ return false; /* Failure. */
+ _new = old + 1;
+ res = uatomic_cmpxchg(&ref->refcount, old, _new);
+ if (res == old) {
+ return true; /* Success. */
+ }
+ old = res;
+ }
+}
+
#endif /* _URCU_REF_H */