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