X-Git-Url: http://git.liburcu.org/?p=userspace-rcu.git;a=blobdiff_plain;f=include%2Furcu%2Fref.h;fp=include%2Furcu%2Fref.h;h=e546da567120e086e5773950ac135d510900b4fc;hp=0000000000000000000000000000000000000000;hb=6893800a4d1cc14dff0395ddcd660a5138db183d;hpb=a59f39055b5ecb77b68cf78b9839aa9e8e4ec332 diff --git a/include/urcu/ref.h b/include/urcu/ref.h new file mode 100644 index 0000000..e546da5 --- /dev/null +++ b/include/urcu/ref.h @@ -0,0 +1,98 @@ +#ifndef _URCU_REF_H +#define _URCU_REF_H + +/* + * Userspace RCU - Reference counting + * + * Copyright (C) 2009 Novell Inc. + * Copyright (C) 2010 Mathieu Desnoyers + * + * Author: Jan Blunck + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +struct urcu_ref { + long refcount; /* ATOMIC */ +}; + +static inline void urcu_ref_set(struct urcu_ref *ref, long val) +{ + uatomic_set(&ref->refcount, val); +} + +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) +{ + if (!urcu_ref_get_safe(ref)) + abort(); +} + +static inline void urcu_ref_put(struct urcu_ref *ref, + void (*release)(struct urcu_ref *)) +{ + long res = uatomic_sub_return(&ref->refcount, 1); + assert (res >= 0); + if (res == 0) + 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 */