Fix astobj to compile against GCC 2.95
[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
19 /*!
20   \file astobj.h
21   \brief A set of macros implementing the asterisk object and container.  Macros
22          are used for maximum performance, to support multiple inheritance, and
23                  to be easily integrated into existing structures without additional 
24                  malloc calls, etc.
25 */
26
27 #if defined(__cplusplus) || defined(c_plusplus)
28 extern "C" {
29 #endif
30
31 #define ASTOBJ_DEFAULT_NAMELEN  80
32 #define ASTOBJ_DEFAULT_BUCKETS  256
33 #define ASTOBJ_DEFAULT_HASH             ast_strhash
34
35 #define ASTOBJ_FLAG_DELME       (1 << 0)                /* Object has been deleted, remove on last unref */
36 #define ASTOBJ_FLAG_MARKED      (1 << 1)                /* Object has been marked for possible deletion */
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                 ASTOBJ_WRLOCK(object); \
85                 if (__builtin_expect((object)->refcount, 1)) \
86                         (object)->refcount--; \
87                 else \
88                         ast_log(LOG_WARNING, "Unreferencing unreferenced (object)!\n"); \
89                 ASTOBJ_UNLOCK(object); \
90                 ASTOBJ_DESTROY(object,destructor); \
91                 (object) = NULL; \
92         } while(0)
93
94 #define ASTOBJ_MARK(object) \
95         do { \
96                 ASTOBJ_WRLOCK(object); \
97                 (object)->objflags |= ASTOBJ_FLAG_MARKED; \
98                 ASTOBJ_UNLOCK(object); \
99         } while(0)
100         
101 #define ASTOBJ_UNMARK(object) \
102         do { \
103                 ASTOBJ_WRLOCK(object); \
104                 (object)->objflags &= ~ASTOBJ_FLAG_MARKED; \
105                 ASTOBJ_UNLOCK(object); \
106         } while(0)
107
108 #define ASTOBJ_DESTROY(object,destructor) \
109         do { \
110                 if (__builtin_expect((object)->refcount, 1)) { \
111                         ASTOBJ_WRLOCK(object); \
112                         (object)->objflags |= ASTOBJ_FLAG_DELME; \
113                         ASTOBJ_UNLOCK(object); \
114                 } else { \
115                         ast_mutex_destroy(&(object)->_lock); \
116                         destructor((object)); \
117                 } \
118         } while(0)
119         
120 #define ASTOBJ_INIT(object) \
121         do { \
122                 ast_mutex_init(&(object)->_lock); \
123                 object->name[0] = '\0'; \
124                 object->refcount = 1; \
125         } while(0)
126
127 /* Containers for objects -- current implementation is linked lists, but
128    should be able to be converted to hashes relatively easily */
129
130 #define ASTOBJ_CONTAINER_RDLOCK(container) ast_mutex_lock(&(container)->_lock)
131 #define ASTOBJ_CONTAINER_WRLOCK(container) ast_mutex_lock(&(container)->_lock)
132 #define ASTOBJ_CONTAINER_UNLOCK(container) ast_mutex_unlock(&(container)->_lock)
133
134 #ifdef ASTOBJ_CONTAINER_HASHMODEL
135 #error "Hash model for object containers not yet implemented!"
136 #else
137 /* Linked lists */
138 #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,hashes,buckets) \
139         type *head
140
141 #define ASTOBJ_CONTAINER_INIT_FULL(container,hashes,buckets) \
142         do { \
143                 ast_mutex_init(&(container)->_lock); \
144         } while(0)
145         
146 #define ASTOBJ_CONTAINER_DESTROY_FULL(container,hashes,buckets) \
147         do { \
148                 ast_mutex_destroy(&(container)->_lock); \
149         } while(0)
150
151 #define ASTOBJ_CONTAINER_TRAVERSE(container,eval) \
152         do { \
153                 typeof((container)->head) iterator; \
154                 typeof((container)->head) next; \
155                 ASTOBJ_CONTAINER_RDLOCK(container); \
156                 next = (container)->head; \
157                 while((iterator = next)) { \
158                         next = iterator->next[0]; \
159                         eval; \
160                 } \
161                 ASTOBJ_CONTAINER_UNLOCK(container); \
162         } while(0)
163
164 #define ASTOBJ_CONTAINER_FIND_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \
165         ({ \
166                 typeof((container)->head) found = NULL; \
167                 ASTOBJ_CONTAINER_TRAVERSE(container, do { \
168                         ASTOBJ_RDLOCK(iterator); \
169                         if (!(comparefunc(iterator->field, (data)))) { \
170                                 found = ASTOBJ_REF(iterator); \
171                         } \
172                         ASTOBJ_UNLOCK(iterator); \
173                         if (found) \
174                                 break; \
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_DESTROY(iterator,destructor); \
186                         ASTOBJ_UNREF(iterator,destructor); \
187                 } \
188                 ASTOBJ_CONTAINER_UNLOCK(container); \
189         } while(0)
190
191 #define ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \
192         ({ \
193                 typeof((container)->head) found = NULL; \
194                 typeof((container)->head) prev = NULL; \
195                 ASTOBJ_CONTAINER_TRAVERSE(container, do { \
196                         ASTOBJ_RDLOCK(iterator); \
197                         if (!(comparefunc(iterator->field, (data)))) { \
198                                 found = iterator; \
199                                 ASTOBJ_CONTAINER_WRLOCK(container); \
200                                 if (prev) \
201                                         prev->next[0] = next; \
202                                 else \
203                                         (container)->head = next; \
204                                 ASTOBJ_CONTAINER_UNLOCK(container); \
205                                 break; \
206                         } \
207                         ASTOBJ_UNLOCK(iterator); \
208                         if (found) \
209                                 break; \
210                         prev = iterator; \
211                 } while (0)); \
212                 found; \
213         })
214
215 #define ASTOBJ_CONTAINER_PRUNE_MARKED(container,destructor) \
216         do { \
217                 typeof((container)->head) prev = NULL; \
218                 ASTOBJ_CONTAINER_TRAVERSE(container, do { \
219                         ASTOBJ_RDLOCK(iterator); \
220                         if (iterator->objflags & ASTOBJ_FLAG_MARKED) { \
221                                 ASTOBJ_CONTAINER_WRLOCK(container); \
222                                 if (prev) \
223                                         prev->next[0] = next; \
224                                 else \
225                                         (container)->head = next; \
226                                 ASTOBJ_CONTAINER_UNLOCK(container); \
227                                 ASTOBJ_UNLOCK(iterator); \
228                                 ASTOBJ_DESTROY(iterator,destructor); \
229                                 continue; \
230                         } \
231                         ASTOBJ_UNLOCK(iterator); \
232                         prev = iterator; \
233                 } while (0)); \
234         } while(0)
235
236 #define ASTOBJ_CONTAINER_LINK_FULL(container,newobj,data,field,hashfunc,hashoffset,comparefunc) \
237         do { \
238                 ASTOBJ_CONTAINER_WRLOCK(container); \
239                 (newobj)->next[0] = (container)->head; \
240                 (container)->head = ASTOBJ_REF(newobj); \
241                 ASTOBJ_CONTAINER_UNLOCK(container); \
242         } while(0)
243
244 #endif /* List model */
245
246 /* Common to hash and linked list models */
247 #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type) \
248         ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,1,ASTOBJ_DEFAULT_BUCKETS)
249
250 #define ASTOBJ_CONTAINER_COMPONENTS(type) \
251         ast_mutex_t _lock; \
252         ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type)
253
254 #define ASTOBJ_CONTAINER_INIT(container) \
255         ASTOBJ_CONTAINER_INIT_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
256
257 #define ASTOBJ_CONTAINER_DESTROY(container) \
258         ASTOBJ_CONTAINER_DESTROY_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
259
260 #define ASTOBJ_CONTAINER_FIND(container,namestr) \
261         ASTOBJ_CONTAINER_FIND_FULL(container,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
262
263 #define ASTOBJ_CONTAINER_FIND_UNLINK(container,namestr) \
264         ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
265
266 #define ASTOBJ_CONTAINER_LINK(container,newobj) \
267         ASTOBJ_CONTAINER_LINK_FULL(container,newobj,(newobj)->name,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
268
269 #define ASTOBJ_CONTAINER_MARKALL(container) \
270         ASTOBJ_CONTAINER_TRAVERSE(container,ASTOBJ_MARK(iterator))
271
272 #define ASTOBJ_CONTAINER_UNMARKALL(container) \
273         ASTOBJ_CONTAINER_TRAVERSE(container,ASTOBJ_UNMARK(iterator))
274
275 #define ASTOBJ_DUMP(s,slen,obj) \
276         snprintf((s),(slen),"name: %s\nobjflags: %d\nrefcount: %d\n\n", (obj)->name, (obj)->objflags, (obj)->refcount);
277
278 #define ASTOBJ_CONTAINER_DUMP(fd,s,slen,container) \
279         ASTOBJ_CONTAINER_TRAVERSE(container,do { ASTOBJ_DUMP(s,slen,iterator); ast_cli(fd, s); } while(0))
280
281 #if defined(__cplusplus) || defined(c_plusplus)
282 }
283 #endif
284
285 #endif