• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013, Google, Inc. All rights reserved
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 #ifndef __REFLIST_H
25 #define __REFLIST_H
26 
27 #include <assert.h>
28 #include <lk/compiler.h>
29 #include <lk/list.h>
30 
31 struct obj_ref {
32     struct list_node ref_node;
33 };
34 
35 struct obj {
36     struct list_node ref_list;
37 };
38 
39 typedef void (*obj_destroy_func)(struct obj* obj);
40 
41 #define OBJ_REF_INITIAL_VALUE(r) \
42     { .ref_node = LIST_INITIAL_CLEARED_VALUE }
43 
obj_ref_init(struct obj_ref * ref)44 static inline __ALWAYS_INLINE void obj_ref_init(struct obj_ref* ref) {
45     *ref = (struct obj_ref)OBJ_REF_INITIAL_VALUE(*ref);
46 }
47 
obj_ref_active(struct obj_ref * ref)48 static inline __ALWAYS_INLINE bool obj_ref_active(struct obj_ref* ref) {
49     return list_in_list(&ref->ref_node);
50 }
51 
obj_init(struct obj * obj,struct obj_ref * ref)52 static inline __ALWAYS_INLINE void obj_init(struct obj* obj,
53                                             struct obj_ref* ref) {
54     list_initialize(&obj->ref_list);
55     list_add_tail(&obj->ref_list, &ref->ref_node);
56 }
57 
obj_has_ref(struct obj * obj)58 static inline __ALWAYS_INLINE bool obj_has_ref(struct obj* obj) {
59     return !list_is_empty(&obj->ref_list);
60 }
61 
obj_has_only_ref(struct obj * obj,struct obj_ref * ref)62 static inline __ALWAYS_INLINE bool obj_has_only_ref(struct obj* obj,
63                                                     struct obj_ref* ref) {
64     assert(obj_has_ref(obj));
65     assert(list_in_list(&ref->ref_node));
66     struct list_node* head = list_peek_head(&obj->ref_list);
67     struct list_node* tail = list_peek_tail(&obj->ref_list);
68     if (head == tail) {
69         assert(head == &ref->ref_node);
70         return head == &ref->ref_node;
71     }
72     return false;
73 }
74 
75 /*
76  * Only use if you are intentionally reusing a possibly unreferenced
77  * object. A cache is an example of this use case, where the destroy
78  * callback may not actually free the object, and the code may wish to
79  * reuse it by adding a reference after it hits zero.
80  */
obj_add_ref_allow_unreferenced_obj(struct obj * obj,struct obj_ref * ref)81 static inline __ALWAYS_INLINE void obj_add_ref_allow_unreferenced_obj(
82         struct obj* obj, struct obj_ref* ref) {
83     assert(!list_in_list(&ref->ref_node));
84     list_add_tail(&obj->ref_list, &ref->ref_node);
85 }
86 
obj_add_ref(struct obj * obj,struct obj_ref * ref)87 static inline __ALWAYS_INLINE void obj_add_ref(struct obj* obj,
88                                                struct obj_ref* ref) {
89     assert(obj_has_ref(obj));
90     obj_add_ref_allow_unreferenced_obj(obj, ref);
91 }
92 
obj_del_ref(struct obj * obj,struct obj_ref * ref,obj_destroy_func destroy)93 static inline __ALWAYS_INLINE bool obj_del_ref(struct obj* obj,
94                                                struct obj_ref* ref,
95                                                obj_destroy_func destroy) {
96     bool dead;
97 
98     assert(list_in_list(&ref->ref_node));
99 
100     list_delete(&ref->ref_node);
101     dead = list_is_empty(&obj->ref_list);
102     if (dead && destroy)
103         destroy(obj);
104     return dead;
105 }
106 
obj_ref_transfer(struct obj_ref * dst,struct obj_ref * src)107 static inline __ALWAYS_INLINE void obj_ref_transfer(struct obj_ref* dst,
108                                                     struct obj_ref* src) {
109     struct list_node* prev;
110 
111     assert(!list_in_list(&dst->ref_node));
112     assert(list_in_list(&src->ref_node));
113 
114     prev = src->ref_node.prev;
115     list_delete(&src->ref_node);
116     list_add_after(prev, &dst->ref_node);
117 }
118 
119 #endif
120