1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2022-3-1       zhouxiaohu   first version
9  * 2023-5-18      GuEe-GUI     implemented by rtatomic
10  */
11 
12 #ifndef __UTIL_REF_H__
13 #define __UTIL_REF_H__
14 
15 #include <rtatomic.h>
16 
17 /**
18  * struct ref must be embedded in an object.
19  * it acts as a reference counter for the object.
20  */
21 struct rt_ref
22 {
23     rt_atomic_t refcount;
24 };
25 
26 #define RT_REF_INIT(n)  { .refcount = n, }
27 
rt_ref_init(struct rt_ref * r)28 rt_inline void rt_ref_init(struct rt_ref *r)
29 {
30     rt_atomic_store(&r->refcount, 1);
31 }
32 
rt_ref_read(struct rt_ref * r)33 rt_inline unsigned int rt_ref_read(struct rt_ref *r)
34 {
35     return rt_atomic_load(&r->refcount);
36 }
37 
38 /**
39  * ref_get
40  * increment reference counter for object.
41  */
rt_ref_get(struct rt_ref * r)42 rt_inline void rt_ref_get(struct rt_ref *r)
43 {
44     rt_atomic_add(&r->refcount, 1);
45 }
46 
47 /**
48  * ref_put
49  * decrement reference counter for object.
50  * If the reference counter is zero, call release().
51  *
52  * Return 1 means the object's reference counter is zero and release() is called.
53  */
rt_ref_put(struct rt_ref * r,void (* release)(struct rt_ref * r))54 rt_inline int rt_ref_put(struct rt_ref *r, void (*release)(struct rt_ref *r))
55 {
56     if (rt_atomic_dec_and_test(&r->refcount))
57     {
58         release(r);
59 
60         return 1;
61     }
62 
63     return 0;
64 }
65 
66 /**
67  * ref_get_unless_zero - Increment refcount for object unless it is zero.
68  * Return non-zero if the increment succeeded. Otherwise return 0.
69  */
rt_ref_get_unless_zero(struct rt_ref * r)70 rt_inline int rt_ref_get_unless_zero(struct rt_ref *r)
71 {
72     return (int)rt_atomic_inc_not_zero(&r->refcount);
73 }
74 
75 #endif /* __UTIL_REF_H__ */
76