Home | History | Annotate | Line # | Download | only in urcu
      1 // SPDX-FileCopyrightText: 2009 Novell Inc.
      2 // SPDX-FileCopyrightText: 2010 Mathieu Desnoyers <mathieu.desnoyers (at) efficios.com>
      3 //
      4 // SPDX-License-Identifier: LGPL-2.1-only
      5 
      6 #ifndef _URCU_REF_H
      7 #define _URCU_REF_H
      8 
      9 /*
     10  * Userspace RCU - Reference counting
     11  *
     12  * Author: Jan Blunck <jblunck (at) suse.de>
     13  */
     14 
     15 #include <stdbool.h>
     16 #include <limits.h>
     17 #include <stdlib.h>
     18 #include <urcu/assert.h>
     19 #include <urcu/uatomic.h>
     20 
     21 struct urcu_ref {
     22 	long refcount; /* ATOMIC */
     23 };
     24 
     25 static inline void urcu_ref_set(struct urcu_ref *ref, long val)
     26 {
     27 	uatomic_set(&ref->refcount, val);
     28 }
     29 
     30 static inline void urcu_ref_init(struct urcu_ref *ref)
     31 {
     32 	urcu_ref_set(ref, 1);
     33 }
     34 
     35 static inline bool  __attribute__((warn_unused_result))
     36 		urcu_ref_get_safe(struct urcu_ref *ref)
     37 {
     38 	long old, _new, res;
     39 
     40 	old = uatomic_read(&ref->refcount);
     41 	for (;;) {
     42 		if (old == LONG_MAX) {
     43 			return false;	/* Failure. */
     44 		}
     45 		_new = old + 1;
     46 		res = uatomic_cmpxchg(&ref->refcount, old, _new);
     47 		if (res == old) {
     48 			return true;	/* Success. */
     49 		}
     50 		old = res;
     51 	}
     52 }
     53 
     54 static inline void urcu_ref_get(struct urcu_ref *ref)
     55 {
     56 	if (!urcu_ref_get_safe(ref))
     57 		abort();
     58 }
     59 
     60 static inline void urcu_ref_put(struct urcu_ref *ref,
     61 				void (*release)(struct urcu_ref *))
     62 {
     63 	long res = uatomic_sub_return(&ref->refcount, 1);
     64 	urcu_posix_assert(res >= 0);
     65 	if (res == 0)
     66 		release(ref);
     67 }
     68 
     69 /*
     70  * urcu_ref_get_unless_zero
     71  *
     72  * Allows getting a reference atomically if the reference count is not
     73  * zero. Returns true if the reference is taken, false otherwise. This
     74  * needs to be used in conjunction with another synchronization
     75  * technique (e.g.  RCU or mutex) to ensure existence of the reference
     76  * count. False is also returned in case incrementing the refcount would
     77  * result in an overflow.
     78  */
     79 static inline bool urcu_ref_get_unless_zero(struct urcu_ref *ref)
     80 {
     81 	long old, _new, res;
     82 
     83 	old = uatomic_read(&ref->refcount);
     84 	for (;;) {
     85 		if (old == 0 || old == LONG_MAX)
     86 			return false;	/* Failure. */
     87 		_new = old + 1;
     88 		res = uatomic_cmpxchg(&ref->refcount, old, _new);
     89 		if (res == old) {
     90 			return true;	/* Success. */
     91 		}
     92 		old = res;
     93 	}
     94 }
     95 
     96 #endif /* _URCU_REF_H */
     97