72bead8fcb02e3e0422e8eae7901a865ceda33d1
[asterisk/asterisk.git] / include / asterisk / astobj.h
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Object Model for Asterisk
5  * 
6  * Copyright (C) 2004 - 2005, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #ifndef _ASTERISK_ASTOBJ_H
15 #define _ASTERISK_ASTOBJ_H
16
17 #include <string.h>
18 #include "asterisk/lock.h"
19
20 /*!
21   \file astobj.h
22   \brief A set of macros implementing the asterisk object and container.  Macros
23          are used for maximum performance, to support multiple inheritance, and
24                  to be easily integrated into existing structures without additional 
25                  malloc calls, etc.
26 */
27
28 #if defined(__cplusplus) || defined(c_plusplus)
29 extern "C" {
30 #endif
31
32 #define ASTOBJ_DEFAULT_NAMELEN  80
33 #define ASTOBJ_DEFAULT_BUCKETS  256
34 #define ASTOBJ_DEFAULT_HASH             ast_strhash
35
36 #define ASTOBJ_FLAG_MARKED      (1 << 0)                /* Object has been marked for future operation */
37
38 #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
39 #define __builtin_expect(exp, c) (exp)
40 #endif
41
42 /* C++ is simply a syntactic crutch for those who cannot think for themselves
43    in an object oriented way. */
44
45 #define ASTOBJ_RDLOCK(object) ast_mutex_lock(&(object)->_lock)
46 #define ASTOBJ_WRLOCK(object) ast_mutex_lock(&(object)->_lock)
47 #define ASTOBJ_UNLOCK(object) ast_mutex_unlock(&(object)->_lock)
48
49 #ifdef ASTOBJ_CONTAINER_HASHMODEL 
50 #define __ASTOBJ_HASH(type,hashes) \
51         type *next[hashes] 
52 #else 
53 #define __ASTOBJ_HASH(type,hashes) \
54         type *next[1] 
55 #endif  
56
57 #define ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes) \
58         char name[namelen]; \
59         int refcount; \
60         int objflags; \
61         __ASTOBJ_HASH(type,hashes)
62         
63 #define ASTOBJ_COMPONENTS_NOLOCK(type) \
64         ASTOBJ_COMPONENTS_NOLOCK_FULL(type,ASTOBJ_DEFAULT_NAMELEN,1)
65
66 #define ASTOBJ_COMPONENTS(type) \
67         ASTOBJ_COMPONENTS_NOLOCK(type); \
68         ast_mutex_t _lock; 
69         
70 #define ASTOBJ_COMPONENTS_FULL(type,namelen,hashes) \
71         ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes); \
72         ast_mutex_t _lock; 
73
74 #define ASTOBJ_REF(object) \
75         ({ \
76                 ASTOBJ_WRLOCK(object); \
77                 (object)->refcount++; \
78                 ASTOBJ_UNLOCK(object); \
79                 (object); \
80         })
81         
82 #define ASTOBJ_UNREF(object,destructor) \
83         do { \
84                 int newcount = 0; \
85                 ASTOBJ_WRLOCK(object); \
86                 if (__builtin_expect((object)->refcount, 1)) \
87                         newcount = --((object)->refcount); \
88                 else \
89                         ast_log(LOG_WARNING, "Unreferencing unreferenced (object)!\n"); \
90                 ASTOBJ_UNLOCK(object); \
91                 if (newcount == 0) { \
92                         ast_mutex_destroy(&(object)->_lock); \
93                         destructor((object)); \
94                 } \
95                 (object) = NULL; \
96         } while(0)
97
98 #define ASTOBJ_MARK(object) \
99         do { \
100                 ASTOBJ_WRLOCK(object); \
101                 (object)->objflags |= ASTOBJ_FLAG_MARKED; \
102                 ASTOBJ_UNLOCK(object); \
103         } while(0)
104         
105 #define ASTOBJ_UNMARK(object) \
106         do { \
107                 ASTOBJ_WRLOCK(object); \
108                 (object)->objflags &= ~ASTOBJ_FLAG_MARKED; \
109                 ASTOBJ_UNLOCK(object); \
110         } while(0)
111
112 #define ASTOBJ_INIT(object) \
113         do { \
114                 ast_mutex_init(&(object)->_lock); \
115                 object->name[0] = '\0'; \
116                 object->refcount = 1; \
117         } while(0)
118
119 /* Containers for objects -- current implementation is linked lists, but
120    should be able to be converted to hashes relatively easily */
121
122 #define ASTOBJ_CONTAINER_RDLOCK(container) ast_mutex_lock(&(container)->_lock)
123 #define ASTOBJ_CONTAINER_WRLOCK(container) ast_mutex_lock(&(container)->_lock)
124 #define ASTOBJ_CONTAINER_UNLOCK(container) ast_mutex_unlock(&(container)->_lock)
125
126 #ifdef ASTOBJ_CONTAINER_HASHMODEL
127 #error "Hash model for object containers not yet implemented!"
128 #else
129 /* Linked lists */
130 #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,hashes,buckets) \
131         type *head
132
133 #define ASTOBJ_CONTAINER_INIT_FULL(container,hashes,buckets) \
134         do { \
135                 ast_mutex_init(&(container)->_lock); \
136         } while(0)
137         
138 #define ASTOBJ_CONTAINER_DESTROY_FULL(container,hashes,buckets) \
139         do { \
140                 ast_mutex_destroy(&(container)->_lock); \
141         } while(0)
142
143 #define ASTOBJ_CONTAINER_TRAVERSE(container,continue,eval) \
144         do { \
145                 typeof((container)->head) iterator; \
146                 typeof((container)->head) next; \
147                 ASTOBJ_CONTAINER_RDLOCK(container); \
148                 next = (container)->head; \
149                 while((continue) && (iterator = next)) { \
150                         next = iterator->next[0]; \
151                         eval; \
152                 } \
153                 ASTOBJ_CONTAINER_UNLOCK(container); \
154         } while(0)
155
156 #define ASTOBJ_CONTAINER_FIND(container,namestr) \
157         ({ \
158                 typeof((container)->head) found = NULL; \
159                 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
160                         if (!(strcasecmp(iterator->name, (namestr)))) \
161                                 found = ASTOBJ_REF(iterator); \
162                 } while (0)); \
163                 found; \
164         })
165
166 #define ASTOBJ_CONTAINER_FIND_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \
167         ({ \
168                 typeof((container)->head) found = NULL; \
169                 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
170                         ASTOBJ_RDLOCK(iterator); \
171                         if (!(comparefunc(iterator->field, (data)))) { \
172                                 found = ASTOBJ_REF(iterator); \
173                         } \
174                         ASTOBJ_UNLOCK(iterator); \
175                 } while (0)); \
176                 found; \
177         })
178
179 #define ASTOBJ_CONTAINER_DESTROYALL(container,destructor) \
180         do { \
181                 typeof((container)->head) iterator; \
182                 ASTOBJ_CONTAINER_WRLOCK(container); \
183                 while((iterator = (container)->head)) { \
184                         (container)->head = (iterator)->next[0]; \
185                         ASTOBJ_UNREF(iterator,destructor); \
186                 } \
187                 ASTOBJ_CONTAINER_UNLOCK(container); \
188         } while(0)
189
190 #define ASTOBJ_CONTAINER_UNLINK(container,obj) \
191         ({ \
192                 typeof((container)->head) found = NULL; \
193                 typeof((container)->head) prev = NULL; \
194                 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
195                         if (iterator == obj) { \
196                                 found = iterator; \
197                                 found->next[0] = NULL; \
198                                 ASTOBJ_CONTAINER_WRLOCK(container); \
199                                 if (prev) \
200                                         prev->next[0] = next; \
201                                 else \
202                                         (container)->head = next; \
203                                 ASTOBJ_CONTAINER_UNLOCK(container); \
204                         } \
205                         prev = iterator; \
206                 } while (0)); \
207                 found; \
208         })
209
210 #define ASTOBJ_CONTAINER_FIND_UNLINK(container,namestr) \
211         ({ \
212                 typeof((container)->head) found = NULL; \
213                 typeof((container)->head) prev = NULL; \
214                 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
215                         if (!(strcasecmp(iterator->name, (namestr)))) { \
216                                 found = iterator; \
217                                 found->next[0] = NULL; \
218                                 ASTOBJ_CONTAINER_WRLOCK(container); \
219                                 if (prev) \
220                                         prev->next[0] = next; \
221                                 else \
222                                         (container)->head = next; \
223                                 ASTOBJ_CONTAINER_UNLOCK(container); \
224                         } \
225                         prev = iterator; \
226                 } while (0)); \
227                 found; \
228         })
229
230 #define ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \
231         ({ \
232                 typeof((container)->head) found = NULL; \
233                 typeof((container)->head) prev = NULL; \
234                 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
235                         ASTOBJ_RDLOCK(iterator); \
236                         if (!(comparefunc(iterator->field, (data)))) { \
237                                 found = iterator; \
238                                 found->next[0] = NULL; \
239                                 ASTOBJ_CONTAINER_WRLOCK(container); \
240                                 if (prev) \
241                                         prev->next[0] = next; \
242                                 else \
243                                         (container)->head = next; \
244                                 ASTOBJ_CONTAINER_UNLOCK(container); \
245                         } \
246                         ASTOBJ_UNLOCK(iterator); \
247                         prev = iterator; \
248                 } while (0)); \
249                 found; \
250         })
251
252 #define ASTOBJ_CONTAINER_PRUNE_MARKED(container,destructor) \
253         do { \
254                 typeof((container)->head) prev = NULL; \
255                 ASTOBJ_CONTAINER_TRAVERSE(container, 1, do { \
256                         ASTOBJ_RDLOCK(iterator); \
257                         if (iterator->objflags & ASTOBJ_FLAG_MARKED) { \
258                                 ASTOBJ_CONTAINER_WRLOCK(container); \
259                                 if (prev) \
260                                         prev->next[0] = next; \
261                                 else \
262                                         (container)->head = next; \
263                                 ASTOBJ_CONTAINER_UNLOCK(container); \
264                                 ASTOBJ_UNLOCK(iterator); \
265                                 ASTOBJ_UNREF(iterator,destructor); \
266                                 continue; \
267                         } \
268                         ASTOBJ_UNLOCK(iterator); \
269                         prev = iterator; \
270                 } while (0)); \
271         } while(0)
272
273 #define ASTOBJ_CONTAINER_LINK_FULL(container,newobj,data,field,hashfunc,hashoffset,comparefunc) \
274         do { \
275                 ASTOBJ_CONTAINER_WRLOCK(container); \
276                 (newobj)->next[0] = (container)->head; \
277                 (container)->head = ASTOBJ_REF(newobj); \
278                 ASTOBJ_CONTAINER_UNLOCK(container); \
279         } while(0)
280
281 #endif /* List model */
282
283 /* Common to hash and linked list models */
284 #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type) \
285         ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,1,ASTOBJ_DEFAULT_BUCKETS)
286
287 #define ASTOBJ_CONTAINER_COMPONENTS(type) \
288         ast_mutex_t _lock; \
289         ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type)
290
291 #define ASTOBJ_CONTAINER_INIT(container) \
292         ASTOBJ_CONTAINER_INIT_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
293
294 #define ASTOBJ_CONTAINER_DESTROY(container) \
295         ASTOBJ_CONTAINER_DESTROY_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
296
297 #define ASTOBJ_CONTAINER_LINK(container,newobj) \
298         ASTOBJ_CONTAINER_LINK_FULL(container,newobj,(newobj)->name,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
299
300 #define ASTOBJ_CONTAINER_MARKALL(container) \
301         ASTOBJ_CONTAINER_TRAVERSE(container, 1, ASTOBJ_MARK(iterator))
302
303 #define ASTOBJ_CONTAINER_UNMARKALL(container) \
304         ASTOBJ_CONTAINER_TRAVERSE(container, 1, ASTOBJ_UNMARK(iterator))
305
306 #define ASTOBJ_DUMP(s,slen,obj) \
307         snprintf((s),(slen),"name: %s\nobjflags: %d\nrefcount: %d\n\n", (obj)->name, (obj)->objflags, (obj)->refcount);
308
309 #define ASTOBJ_CONTAINER_DUMP(fd,s,slen,container) \
310         ASTOBJ_CONTAINER_TRAVERSE(container, 1, do { ASTOBJ_DUMP(s,slen,iterator); ast_cli(fd, s); } while(0))
311
312 #if defined(__cplusplus) || defined(c_plusplus)
313 }
314 #endif
315
316 #endif