Add Asterisk "object model" and update chan_sip to use it for peers/regs/users
[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
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_DELME       (1 << 0)                /* Object has been deleted, remove on last unref */
37 #define ASTOBJ_FLAG_MARKED      (1 << 1)                /* Object has been marked for possible deletion */
38
39 /* C++ is simply a syntactic crutch for those who cannot think for themselves
40    in an object oriented way. */
41
42 #ifdef ASTOBJ_CONTAINER_HASHMODEL 
43 #define __ASTOBJ_HASH(type,hashes) \
44         type *next[hashes] 
45 #else 
46 #define __ASTOBJ_HASH(type,hashes) \
47         type *next[1] 
48 #endif  
49
50 #define ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes) \
51         char name[namelen]; \
52         int refcount; \
53         int objflags; \
54         __ASTOBJ_HASH(type,hashes)
55         
56 #define ASTOBJ_COMPONENTS_NOLOCK(type) \
57         ASTOBJ_COMPONENTS_NOLOCK_FULL(type,ASTOBJ_DEFAULT_NAMELEN,1)
58
59 #define ASTOBJ_COMPONENTS(type) \
60         ast_mutex_t lock; \
61         ASTOBJ_COMPONENTS_NOLOCK(type)
62         
63 #define ASTOBJ_COMPONENTS_FULL(type,namelen,hashes) \
64         ast_mutex_t lock; \
65         ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes)
66
67 #define ASTOBJ_REF(object) \
68         do { \
69                 ast_mutex_lock(&(object)->lock); \
70                 (object)->refcount++; \
71                 ast_mutex_unlock(&(object)->lock); \
72         } while(0)
73         
74 #define ASTOBJ_UNREF(object,destructor) \
75         do { \
76                 int destroyme; \
77                 ast_mutex_lock(&(object)->lock); \
78                 if ((object)->refcount > 0) \
79                         (object)->refcount--; \
80                 else \
81                         ast_log(LOG_WARNING, "Unreferencing unreferenced (object)!\n"); \
82                 destroyme = (!(object)->refcount) && ((object)->objflags & ASTOBJ_FLAG_DELME); \
83                 ast_mutex_unlock(&(object)->lock); \
84                 if (destroyme) \
85                         destructor((object)); \
86         } while(0)
87
88 #define ASTOBJ_MARK(object) \
89         (object)->objflags |= ASTOBJ_FLAG_MARKED;
90         
91 #define ASTOBJ_UNMARK(object) \
92         (object)->objflags &= ~ASTOBJ_FLAG_MARKED;
93
94 #define ASTOBJ_DESTROY(object,destructor) \
95         do { \
96                 int destroyme; \
97                 ast_mutex_lock(&(object)->lock); \
98                 destroyme = (!(object)->refcount); \
99                 (object)->objflags |= ASTOBJ_FLAG_DELME; \
100                 ast_mutex_unlock(&(object)->lock); \
101                 if (destroyme) \
102                         destructor((object)); \
103         } while(0)
104         
105 #define ASTOBJ_INIT(object) \
106         do { \
107                 ast_mutex_init(&(object)->lock); \
108                 object->name[0] = '\0'; \
109         } while(0)
110
111 /* Containers for objects -- current implementation is linked lists, but
112    should be able to be converted to hashes relatively easily */
113
114 #ifdef ASTOBJ_CONTAINER_HASHMODEL
115 #error "Hash model for object containers not yet implemented!"
116 #else
117 /* Linked lists */
118 #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,hashes,buckets) \
119         type *head
120
121 #define ASTOBJ_CONTAINER_INIT_FULL(container,hashes,buckets) \
122         do { \
123                 ast_mutex_init(&(container)->lock); \
124         } while(0)
125         
126 #define ASTOBJ_CONTAINER_RELEASE_FULL(container,hashes,buckets) \
127         do { \
128                 ast_mutex_destroy(&(container)->lock); \
129         } while(0)
130
131 #define ASTOBJ_CONTAINER_TRAVERSE(container,iterator,eval) \
132         do { \
133                 ast_mutex_lock(&((container)->lock)); \
134                 (iterator) = (container)->head; \
135                 while((iterator)) { \
136                         ast_mutex_lock(&(iterator)->lock); \
137                         eval; \
138                         ast_mutex_unlock(&(iterator)->lock); \
139                         (iterator) = (iterator)->next[0]; \
140                 } \
141                 ast_mutex_unlock(&(container)->lock); \
142         } while(0)
143
144 #define ASTOBJ_CONTAINER_FIND_FULL(container,iterator,data,field,hashfunc,hashoffset,comparefunc) \
145         do { \
146                 int res; \
147                 ast_mutex_lock(&((container)->lock)); \
148                 (iterator) = (container)->head; \
149                 while((iterator)) { \
150                         ast_mutex_lock(&(iterator)->lock); \
151                         res = (comparefunc((iterator)->field,(data))); \
152                         if (!res) \
153                                 ASTOBJ_REF((iterator)); \
154                         ast_mutex_unlock(&(iterator)->lock); \
155                         if (!res) \
156                                 break; \
157                         (iterator) = (iterator)->next[0]; \
158                 } \
159                 ast_mutex_unlock(&(container)->lock); \
160         } while(0)
161
162 #define ASTOBJ_CONTAINER_DESTROYALL(container,iterator,destructor) \
163         do { \
164                 ast_mutex_lock(&((container)->lock)); \
165                 (iterator) = (container)->head; \
166                 while((iterator)) { \
167                         (container)->head = (iterator)->next[0]; \
168                         ASTOBJ_DESTROY(iterator,destructor); \
169                         (iterator) = (container)->head; \
170                 } \
171                 ast_mutex_unlock(&(container)->lock); \
172         } while(0)
173
174 #define ASTOBJ_CONTAINER_UNLINK_FULL(container,iterator,data,field,hashfunc,hashoffset,comparefunc) \
175         do { \
176                 int res=-1; \
177                 ast_mutex_lock(&((container)->lock)); \
178                 (iterator) = (container)->head; \
179                 if ((iterator)) { \
180                         ast_mutex_lock(&(iterator)->lock); \
181                         res = (comparefunc((iterator)->field,(data))); \
182                         if (!res && ((iterator)->refcount < 1)) \
183                                 ast_log(LOG_WARNING, "Unlink called with refcount < 1!\n"); \
184                         ast_mutex_unlock(&(iterator)->lock); \
185                         if (!res) \
186                                 (container)->head = (iterator)->next[0]; \
187                         else while((iterator)->next[0]) { \
188                                 ast_mutex_lock(&(iterator)->next[0]->lock); \
189                                 res = (comparefunc((iterator)->next[0]->field,(data))); \
190                                 if (!res && ((iterator)->next[0]->refcount < 1)) \
191                                         ast_log(LOG_WARNING, "Unlink called with refcount < 1!\n"); \
192                                 ast_mutex_unlock(&(iterator)->next[0]->lock); \
193                                 if (!res) { \
194                                         (iterator)->next[0] = (iterator)->next[0]->next[0]; \
195                                         break; \
196                                 } \
197                                 (iterator) = (iterator)->next[0]; \
198                         } \
199                 } \
200                 ast_mutex_unlock(&(container)->lock); \
201         } while(0)
202
203 #define ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,reiterator,iterator,data,field,hashfunc,hashoffset,comparefunc) \
204         do { \
205                 int res=-1; \
206                 (reiterator) = NULL; \
207                 ast_mutex_lock(&((container)->lock)); \
208                 (iterator) = (container)->head; \
209                 if ((iterator)) { \
210                         ast_mutex_lock(&(iterator)->lock); \
211                         res = (comparefunc((iterator)->field,(data))); \
212                         if (!res && ((iterator)->refcount < 1)) \
213                                 ast_log(LOG_WARNING, "Unlink called with refcount < 1!\n"); \
214                         ast_mutex_unlock(&(iterator)->lock); \
215                         if (!res) {\
216                                 (reiterator) = (container)->head; \
217                                 (container)->head = (iterator)->next[0]; \
218                         } else while((iterator)->next[0]) { \
219                                 ast_mutex_lock(&(iterator)->next[0]->lock); \
220                                 res = (comparefunc((iterator)->next[0]->field,(data))); \
221                                 ast_mutex_unlock(&(iterator)->next[0]->lock); \
222                                 if (!res) { \
223                                         (reiterator) = (iterator)->next[0]; \
224                                         (iterator)->next[0] = (iterator)->next[0]->next[0]; \
225                                         break; \
226                                 } \
227                                 (iterator) = (iterator)->next[0]; \
228                         } \
229                 } \
230                 ast_mutex_unlock(&(container)->lock); \
231         } while(0)
232
233 #define ASTOBJ_CONTAINER_PRUNE_MARKED(container,previ,nexti,iterator,destructor) \
234         do { \
235                 (previ) = NULL; \
236                 ast_mutex_lock(&((container)->lock)); \
237                 (iterator) = (container)->head; \
238                 while((iterator)) { \
239                         ast_mutex_lock(&(iterator)->lock); \
240                         (nexti) = (iterator)->next[0]; \
241                         if ((iterator)->objflags & ASTOBJ_FLAG_MARKED) { \
242                                 if ((previ)) \
243                                         (previ)->next[0] = (nexti); \
244                                 else \
245                                         (container)->head = (nexti); \
246                                 ast_mutex_unlock(&(iterator)->lock); \
247                                 ASTOBJ_DESTROY(iterator,destructor); \
248                         } else { \
249                                 (previ) = (iterator); \
250                                 ast_mutex_unlock(&(iterator)->lock); \
251                         } \
252                         (iterator) = (nexti); \
253                 } \
254                 ast_mutex_unlock(&(container)->lock); \
255         } while(0)
256
257 #define ASTOBJ_CONTAINER_LINK_FULL(container,newobj,data,field,hashfunc,hashoffset,comparefunc) \
258         do { \
259                 ASTOBJ_REF(newobj); \
260                 ast_mutex_lock(&(container)->lock); \
261                 (newobj)->next[0] = (container)->head; \
262                 (container)->head = (newobj); \
263                 ast_mutex_unlock(&(container)->lock); \
264         } while(0)
265
266 #endif /* Hash model */
267
268 /* Common to hash and linked list models */
269 #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type) \
270         ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,1,ASTOBJ_DEFAULT_BUCKETS)
271
272 #define ASTOBJ_CONTAINER_COMPONENTS(type) \
273         ast_mutex_t lock; \
274         ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type)
275
276 #define ASTOBJ_CONTAINER_INIT(container) \
277         ASTOBJ_CONTAINER_INIT_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
278
279 #define ASTOBJ_CONTAINER_RELEASE(container) \
280         ASTOBJ_CONTAINER_RELEASE_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
281
282 #define ASTOBJ_CONTAINER_FIND(container,iterator,namestr) \
283         ASTOBJ_CONTAINER_FIND_FULL(container,iterator,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
284
285 #define ASTOBJ_CONTAINER_FIND_UNLINK(container,reiterator,iterator,namestr) \
286         ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,reiterator,iterator,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
287
288 #define ASTOBJ_CONTAINER_UNLINK(container,iterator,namestr) \
289         ASTOBJ_CONTAINER_UNLINK_FULL(container,iterator,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
290
291 #define ASTOBJ_CONTAINER_LINK(container,newobj) \
292         ASTOBJ_CONTAINER_LINK_FULL(container,newobj,(newobj)->name,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
293
294 #define ASTOBJ_CONTAINER_MARKALL(container,iterator) \
295         ASTOBJ_CONTAINER_TRAVERSE(container,iterator,(iterator)->objflags |= ASTOBJ_FLAG_MARKED)
296
297 #define ASTOBJ_CONTAINER_UNMARKALL(container,iterator) \
298         ASTOBJ_CONTAINER_TRAVERSE(container,iterator,(iterator)->objflags &= ~ASTOBJ_FLAG_MARKED)
299
300 #define ASTOBJ_DUMP(s,slen,obj) \
301         snprintf((s),(slen),"name: %s\nobjflags: %d\nrefcount: %d\n\n", (obj)->name, (obj)->objflags, (obj)->refcount);
302
303 #define ASTOBJ_CONTAINER_DUMP(fd,s,slen,container,iterator) \
304         ASTOBJ_CONTAINER_TRAVERSE(container,iterator,do { ASTOBJ_DUMP(s,slen,iterator); ast_cli(fd, s); } while(0))
305
306 #if defined(__cplusplus) || defined(c_plusplus)
307 }
308 #endif
309
310
311
312 #endif