1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * lt-mem.c
4 * Copyright (C) 2011-2012 Akira TAGOH
5 *
6 * Authors:
7 * Akira TAGOH <akira@tagoh.org>
8 *
9 * You may distribute under the terms of either the GNU
10 * Lesser General Public License or the Mozilla Public
11 * License, as specified in the README file.
12 */
13 #ifdef HAVE_CONFIG_H
14 #include "config.h"
15 #endif
16
17 #include <stdlib.h>
18 #include "lt-atomic.h"
19 #include "lt-mem.h"
20 #include "lt-messages.h"
21
22 struct _lt_mem_slist_t {
23 lt_mem_slist_t *next;
24 lt_pointer_t key;
25 lt_destroy_func_t func;
26 };
27
28 lt_mem_slist_t *lt_mem_slist_new (void);
29 void lt_mem_slist_free (lt_mem_slist_t *list);
30 lt_mem_slist_t *lt_mem_slist_last (lt_mem_slist_t *list);
31 lt_mem_slist_t *lt_mem_slist_append (lt_mem_slist_t *list,
32 lt_pointer_t key,
33 lt_destroy_func_t func);
34 lt_mem_slist_t *lt_mem_slist_delete (lt_mem_slist_t *list,
35 lt_pointer_t *data);
36 lt_mem_slist_t *lt_mem_slist_delete_link(lt_mem_slist_t *list,
37 lt_mem_slist_t *link_);
38 lt_mem_slist_t *lt_mem_slist_find (lt_mem_slist_t *list,
39 const lt_pointer_t data);
40
41
42 /*< private >*/
43
44 /*< protected >*/
45 lt_mem_slist_t *
lt_mem_slist_new(void)46 lt_mem_slist_new(void)
47 {
48 return malloc(sizeof (lt_mem_slist_t));
49 }
50
51 void
lt_mem_slist_free(lt_mem_slist_t * list)52 lt_mem_slist_free(lt_mem_slist_t *list)
53 {
54 lt_mem_slist_t *l = list;
55
56 while (l) {
57 list = l;
58 l = l->next;
59 free(list);
60 }
61 }
62
63 lt_mem_slist_t *
lt_mem_slist_last(lt_mem_slist_t * list)64 lt_mem_slist_last(lt_mem_slist_t *list)
65 {
66 if (list) {
67 while (list->next)
68 list = list->next;
69 }
70
71 return list;
72 }
73
74 lt_mem_slist_t *
lt_mem_slist_append(lt_mem_slist_t * list,lt_pointer_t key,lt_destroy_func_t func)75 lt_mem_slist_append(lt_mem_slist_t *list,
76 lt_pointer_t key,
77 lt_destroy_func_t func)
78 {
79 lt_mem_slist_t *l = lt_mem_slist_new();
80 lt_mem_slist_t *last;
81
82 l->key = key;
83 l->func = func;
84 l->next = NULL;
85 if (list) {
86 last = lt_mem_slist_last(list);
87 last->next = l;
88 } else {
89 list = l;
90 }
91
92 return list;
93 }
94
95 lt_mem_slist_t *
lt_mem_slist_delete(lt_mem_slist_t * list,lt_pointer_t * data)96 lt_mem_slist_delete(lt_mem_slist_t *list,
97 lt_pointer_t *data)
98 {
99 lt_mem_slist_t *l = list;
100
101 while (l) {
102 if (l->key == data) {
103 list = lt_mem_slist_delete_link(list, l);
104 break;
105 } else {
106 l = l->next;
107 }
108 }
109
110 return list;
111 }
112
113 lt_mem_slist_t *
lt_mem_slist_delete_link(lt_mem_slist_t * list,lt_mem_slist_t * link_)114 lt_mem_slist_delete_link(lt_mem_slist_t *list,
115 lt_mem_slist_t *link_)
116 {
117 lt_mem_slist_t *prev = NULL, *l = list;
118
119 while (l) {
120 if (l == link_) {
121 if (prev)
122 prev->next = l->next;
123 if (list == l)
124 list = list->next;
125 free(link_);
126 break;
127 }
128 prev = l;
129 l = l->next;
130 }
131
132 return list;
133 }
134
135 lt_mem_slist_t *
lt_mem_slist_find(lt_mem_slist_t * list,const lt_pointer_t data)136 lt_mem_slist_find(lt_mem_slist_t *list,
137 const lt_pointer_t data)
138 {
139 while (list) {
140 if (list->key == data)
141 break;
142 list = list->next;
143 }
144
145 return list;
146 }
147
148 /*< public >*/
149 lt_pointer_t
lt_mem_alloc_object(size_t size)150 lt_mem_alloc_object(size_t size)
151 {
152 lt_mem_t *retval;
153
154 lt_return_val_if_fail (size > 0, NULL);
155
156 retval = calloc(1, size);
157 if (retval) {
158 retval->ref_count = 1;
159 retval->refs = NULL;
160 retval->size = size;
161 }
162
163 return retval;
164 }
165
166 lt_pointer_t
lt_mem_ref(lt_mem_t * object)167 lt_mem_ref(lt_mem_t *object)
168 {
169 lt_return_val_if_fail (object != NULL, NULL);
170
171 lt_atomic_int_inc((volatile int *)&object->ref_count);
172
173 return object;
174 }
175
176 void
lt_mem_unref(lt_mem_t * object)177 lt_mem_unref(lt_mem_t *object)
178 {
179 lt_return_if_fail (object != NULL);
180
181 if (lt_atomic_int_dec_and_test((volatile int *)&object->ref_count)) {
182 lt_mem_slist_t *ll, *l;
183
184 if (object->refs) {
185 ll = object->refs;
186 while (ll) {
187 l = ll;
188 ll = ll->next;
189 if (l->func)
190 l->func(l->key);
191 free(l);
192 }
193 }
194 if (object->weak_pointers) {
195 ll = object->weak_pointers;
196 while (ll) {
197 lt_pointer_t *p;
198
199 l = ll;
200 ll = ll->next;
201 p = (lt_pointer_t *)l->key;
202 *p = NULL;
203 free(l);
204 }
205 }
206 free(object);
207 }
208 }
209
210 void
lt_mem_add_ref(lt_mem_t * object,lt_pointer_t p,lt_destroy_func_t func)211 lt_mem_add_ref(lt_mem_t *object,
212 lt_pointer_t p,
213 lt_destroy_func_t func)
214 {
215 if (!object ||
216 !p ||
217 !func)
218 return;
219
220 object->refs = lt_mem_slist_append(object->refs, p, func);
221 }
222
223 void
lt_mem_remove_ref(lt_mem_t * object,lt_pointer_t p)224 lt_mem_remove_ref(lt_mem_t *object,
225 lt_pointer_t p)
226 {
227 lt_mem_slist_t *l;
228
229 lt_return_if_fail (object != NULL);
230 lt_return_if_fail (p != NULL);
231
232 if ((l = lt_mem_slist_find(object->refs, p)) != NULL) {
233 object->refs = lt_mem_slist_delete_link(object->refs, l);
234 }
235 }
236
237 void
lt_mem_delete_ref(lt_mem_t * object,lt_pointer_t p)238 lt_mem_delete_ref(lt_mem_t *object,
239 lt_pointer_t p)
240 {
241 lt_mem_slist_t *l;
242
243 lt_return_if_fail (object != NULL);
244 lt_return_if_fail (p != NULL);
245
246 if ((l = lt_mem_slist_find(object->refs, p)) != NULL) {
247 if (l->func)
248 l->func(l->key);
249 object->refs = lt_mem_slist_delete_link(object->refs, l);
250 }
251 }
252
253 void
lt_mem_add_weak_pointer(lt_mem_t * object,lt_pointer_t * p)254 lt_mem_add_weak_pointer(lt_mem_t *object,
255 lt_pointer_t *p)
256 {
257 lt_return_if_fail (object != NULL);
258 lt_return_if_fail (p != NULL);
259
260 if (!lt_mem_slist_find(object->weak_pointers, p))
261 object->weak_pointers = lt_mem_slist_append(object->weak_pointers, p, NULL);
262 }
263
264 void
lt_mem_remove_weak_pointer(lt_mem_t * object,lt_pointer_t * p)265 lt_mem_remove_weak_pointer(lt_mem_t *object,
266 lt_pointer_t *p)
267 {
268 lt_return_if_fail (object != NULL);
269 lt_return_if_fail (p != NULL);
270
271 object->weak_pointers = lt_mem_slist_delete(object->weak_pointers, p);
272 }
273