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