1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * Copyright (c) 2017, Linaro Limited
4 */
5
6 #ifndef __KERNEL_REFCOUNT_H
7 #define __KERNEL_REFCOUNT_H
8
9 #include <atomic.h>
10
11 /*
12 * Reference counter
13 *
14 * When val is 0, refcount_inc() does not change the value and returns false.
15 * Otherwise, it increments the value and returns true.
16 *
17 * refcount_dec() decrements the value and returns true when the call
18 * caused the value to become 0, false otherwise.
19 *
20 * Since each call to refcount_dec() is supposed to match a call to
21 * refcount_inc(), refcount_dec() called for val == 0 should never happen.
22 *
23 * This behaviour makes this pattern possible:
24 * if (!refcount_inc(r)) {
25 * mutex_lock(m);
26 * // Some other thread may have initialized o by now so check that
27 * // we still need to initialize o.
28 * if (!o) {
29 * o = initialize();
30 * refcount_set(r, 1);
31 * }
32 * mutex_unlock(m);
33 * }
34 *
35 * or
36 * if (refcount_dec(r)) {
37 * mutex_lock(m);
38 * // Now that we have the mutex o can't be ininialized/uninitialized
39 * // by any other thread, check that the refcount value is still 0
40 * // to guard against the thread above already having reinitialized o
41 * if (!refcount_val(r) && o)
42 * uninitialize(o)
43 * mutex_unlock(m);
44 * }
45 *
46 * where r if the reference counter, o is the object and m the mutex
47 * protecting the object.
48 */
49
50 struct refcount {
51 unsigned int val;
52 };
53
54 /* Increases refcount by 1, return true if val > 0 else false */
55 bool refcount_inc(struct refcount *r);
56 /* Decreases refcount by 1, return true if val == 0 else false */
57 bool refcount_dec(struct refcount *r);
58
refcount_set(struct refcount * r,unsigned int val)59 static inline void refcount_set(struct refcount *r, unsigned int val)
60 {
61 atomic_store_uint(&r->val, val);
62 }
63
refcount_val(struct refcount * r)64 static inline unsigned int refcount_val(struct refcount *r)
65 {
66 return atomic_load_uint(&r->val);
67 }
68
69 #endif /*!__KERNEL_REFCOUNT_H*/
70