X-Git-Url: https://git.lttng.org/?p=urcu.git;a=blobdiff_plain;f=urcu%2Fref.h;h=2b803e5b68e4710606df29f128ff7f1637dc1472;hp=a422a9906fd787d1482210a5a61b6f3611b7f99c;hb=7ce99d0278e87880d1382cdf791bb84f7b489ea4;hpb=f9bf6d545e9e4801bec75043d716f9810ca1024d diff --git a/urcu/ref.h b/urcu/ref.h index a422a99..2b803e5 100644 --- a/urcu/ref.h +++ b/urcu/ref.h @@ -15,6 +15,9 @@ */ #include +#include +#include +#include #include struct urcu_ref { @@ -33,7 +36,20 @@ static inline void urcu_ref_init(struct urcu_ref *ref) static inline void urcu_ref_get(struct urcu_ref *ref) { - uatomic_add(&ref->refcount, 1); + long old, _new, res; + + old = uatomic_read(&ref->refcount); + for (;;) { + if (old == LONG_MAX) { + abort(); + } + _new = old + 1; + res = uatomic_cmpxchg(&ref->refcount, old, _new); + if (res == old) { + return; + } + old = res; + } } static inline void urcu_ref_put(struct urcu_ref *ref, @@ -45,4 +61,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 */