X-Git-Url: http://git.liburcu.org/?p=urcu.git;a=blobdiff_plain;f=urcu%2Fref.h;h=e546da567120e086e5773950ac135d510900b4fc;hp=a422a9906fd787d1482210a5a61b6f3611b7f99c;hb=2af1c19e6a553878fcb2a5106f050d5ed7ac0f54;hpb=9d2614f07691a813a3c560a6c0bcd0a7be854ed5 diff --git a/urcu/ref.h b/urcu/ref.h index a422a99..e546da5 100644 --- a/urcu/ref.h +++ b/urcu/ref.h @@ -15,6 +15,9 @@ */ #include +#include +#include +#include #include struct urcu_ref { @@ -31,9 +34,29 @@ static inline void urcu_ref_init(struct urcu_ref *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, @@ -45,4 +68,31 @@ 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 */