Remove silly break (bug #3217)
[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                         } \
206                         ASTOBJ_UNLOCK(iterator); \
207                         if (found) \
208                                 break; \
209                         prev = iterator; \
210                 } while (0)); \
211                 found; \
212         })
213
214 #define ASTOBJ_CONTAINER_PRUNE_MARKED(container,destructor) \
215         do { \
216                 typeof((container)->head) prev = NULL; \
217                 ASTOBJ_CONTAINER_TRAVERSE(container, do { \
218                         ASTOBJ_RDLOCK(iterator); \
219                         if (iterator->objflags & ASTOBJ_FLAG_MARKED) { \
220                                 ASTOBJ_CONTAINER_WRLOCK(container); \
221                                 if (prev) \
222                                         prev->next[0] = next; \
223                                 else \
224                                         (container)->head = next; \
225                                 ASTOBJ_CONTAINER_UNLOCK(container); \
226                                 ASTOBJ_UNLOCK(iterator); \
227                                 ASTOBJ_DESTROY(iterator,destructor); \
228                                 continue; \
229                         } \
230                         ASTOBJ_UNLOCK(iterator); \
231                         prev = iterator; \
232                 } while (0)); \
233         } while(0)
234
235 #define ASTOBJ_CONTAINER_LINK_FULL(container,newobj,data,field,hashfunc,hashoffset,comparefunc) \
236         do { \
237                 ASTOBJ_CONTAINER_WRLOCK(container); \
238                 (newobj)->next[0] = (container)->head; \
239                 (container)->head = ASTOBJ_REF(newobj); \
240                 ASTOBJ_CONTAINER_UNLOCK(container); \
241         } while(0)
242
243 #endif /* List model */
244
245 /* Common to hash and linked list models */
246 #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type) \
247         ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,1,ASTOBJ_DEFAULT_BUCKETS)
248
249 #define ASTOBJ_CONTAINER_COMPONENTS(type) \
250         ast_mutex_t _lock; \
251         ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type)
252
253 #define ASTOBJ_CONTAINER_INIT(container) \
254         ASTOBJ_CONTAINER_INIT_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
255
256 #define ASTOBJ_CONTAINER_DESTROY(container) \
257         ASTOBJ_CONTAINER_DESTROY_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
258
259 #define ASTOBJ_CONTAINER_FIND(container,namestr) \
260         ASTOBJ_CONTAINER_FIND_FULL(container,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
261
262 #define ASTOBJ_CONTAINER_FIND_UNLINK(container,namestr) \
263         ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
264
265 #define ASTOBJ_CONTAINER_LINK(container,newobj) \
266         ASTOBJ_CONTAINER_LINK_FULL(container,newobj,(newobj)->name,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
267
268 #define ASTOBJ_CONTAINER_MARKALL(container) \
269         ASTOBJ_CONTAINER_TRAVERSE(container,ASTOBJ_MARK(iterator))
270
271 #define ASTOBJ_CONTAINER_UNMARKALL(container) \
272         ASTOBJ_CONTAINER_TRAVERSE(container,ASTOBJ_UNMARK(iterator))
273
274 #define ASTOBJ_DUMP(s,slen,obj) \
275         snprintf((s),(slen),"name: %s\nobjflags: %d\nrefcount: %d\n\n", (obj)->name, (obj)->objflags, (obj)->refcount);
276
277 #define ASTOBJ_CONTAINER_DUMP(fd,s,slen,container) \
278         ASTOBJ_CONTAINER_TRAVERSE(container,do { ASTOBJ_DUMP(s,slen,iterator); ast_cli(fd, s); } while(0))
279
280 #if defined(__cplusplus) || defined(c_plusplus)
281 }
282 #endif
283
284 #endif