2004-12-25 22:15:32 +00:00
|
|
|
/*
|
|
|
|
* Asterisk -- A telephony toolkit for Linux.
|
|
|
|
*
|
|
|
|
* Object Model for Asterisk
|
|
|
|
*
|
|
|
|
* Copyright (C) 2004-2005, Digium, Inc.
|
|
|
|
*
|
|
|
|
* Mark Spencer <markster@digium.com>
|
|
|
|
*
|
|
|
|
* This program is free software, distributed under the terms of
|
|
|
|
* the GNU General Public License
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _ASTERISK_ASTOBJ_H
|
|
|
|
#define _ASTERISK_ASTOBJ_H
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\file astobj.h
|
|
|
|
\brief A set of macros implementing the asterisk object and container. Macros
|
|
|
|
are used for maximum performance, to support multiple inheritance, and
|
|
|
|
to be easily integrated into existing structures without additional
|
|
|
|
malloc calls, etc.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if defined(__cplusplus) || defined(c_plusplus)
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define ASTOBJ_DEFAULT_NAMELEN 80
|
|
|
|
#define ASTOBJ_DEFAULT_BUCKETS 256
|
|
|
|
#define ASTOBJ_DEFAULT_HASH ast_strhash
|
|
|
|
|
|
|
|
#define ASTOBJ_FLAG_DELME (1 << 0) /* Object has been deleted, remove on last unref */
|
|
|
|
#define ASTOBJ_FLAG_MARKED (1 << 1) /* Object has been marked for possible deletion */
|
|
|
|
|
|
|
|
/* C++ is simply a syntactic crutch for those who cannot think for themselves
|
|
|
|
in an object oriented way. */
|
|
|
|
|
2004-12-28 23:27:44 +00:00
|
|
|
#define ASTOBJ_RDLOCK(object) ast_mutex_lock(&(object)->_lock)
|
|
|
|
#define ASTOBJ_WRLOCK(object) ast_mutex_lock(&(object)->_lock)
|
|
|
|
#define ASTOBJ_UNLOCK(object) ast_mutex_unlock(&(object)->_lock)
|
|
|
|
|
2004-12-25 22:15:32 +00:00
|
|
|
#ifdef ASTOBJ_CONTAINER_HASHMODEL
|
|
|
|
#define __ASTOBJ_HASH(type,hashes) \
|
|
|
|
type *next[hashes]
|
|
|
|
#else
|
|
|
|
#define __ASTOBJ_HASH(type,hashes) \
|
|
|
|
type *next[1]
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes) \
|
|
|
|
char name[namelen]; \
|
|
|
|
int refcount; \
|
|
|
|
int objflags; \
|
|
|
|
__ASTOBJ_HASH(type,hashes)
|
|
|
|
|
|
|
|
#define ASTOBJ_COMPONENTS_NOLOCK(type) \
|
|
|
|
ASTOBJ_COMPONENTS_NOLOCK_FULL(type,ASTOBJ_DEFAULT_NAMELEN,1)
|
|
|
|
|
|
|
|
#define ASTOBJ_COMPONENTS(type) \
|
2004-12-28 23:27:44 +00:00
|
|
|
ast_mutex_t _lock; \
|
2004-12-25 22:15:32 +00:00
|
|
|
ASTOBJ_COMPONENTS_NOLOCK(type)
|
|
|
|
|
|
|
|
#define ASTOBJ_COMPONENTS_FULL(type,namelen,hashes) \
|
2004-12-28 23:27:44 +00:00
|
|
|
ast_mutex_t _lock; \
|
2004-12-25 22:15:32 +00:00
|
|
|
ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes)
|
|
|
|
|
|
|
|
#define ASTOBJ_REF(object) \
|
2004-12-28 23:27:44 +00:00
|
|
|
({ \
|
|
|
|
ASTOBJ_WRLOCK(object); \
|
2004-12-25 22:15:32 +00:00
|
|
|
(object)->refcount++; \
|
2004-12-28 23:27:44 +00:00
|
|
|
ASTOBJ_UNLOCK(object); \
|
|
|
|
(object); \
|
|
|
|
})
|
2004-12-25 22:15:32 +00:00
|
|
|
|
|
|
|
#define ASTOBJ_UNREF(object,destructor) \
|
|
|
|
do { \
|
2004-12-28 23:27:44 +00:00
|
|
|
ASTOBJ_WRLOCK(object); \
|
|
|
|
if (__builtin_expect((object)->refcount, 1)) \
|
2004-12-25 22:15:32 +00:00
|
|
|
(object)->refcount--; \
|
|
|
|
else \
|
|
|
|
ast_log(LOG_WARNING, "Unreferencing unreferenced (object)!\n"); \
|
2004-12-28 23:27:44 +00:00
|
|
|
ASTOBJ_UNLOCK(object); \
|
|
|
|
ASTOBJ_DESTROY(object,destructor); \
|
|
|
|
(object) = NULL; \
|
2004-12-25 22:15:32 +00:00
|
|
|
} while(0)
|
|
|
|
|
|
|
|
#define ASTOBJ_MARK(object) \
|
2004-12-28 23:27:44 +00:00
|
|
|
do { \
|
|
|
|
ASTOBJ_WRLOCK(object); \
|
|
|
|
(object)->objflags |= ASTOBJ_FLAG_MARKED; \
|
|
|
|
ASTOBJ_UNLOCK(object); \
|
|
|
|
} while(0)
|
2004-12-25 22:15:32 +00:00
|
|
|
|
|
|
|
#define ASTOBJ_UNMARK(object) \
|
2004-12-28 23:27:44 +00:00
|
|
|
do { \
|
|
|
|
ASTOBJ_WRLOCK(object); \
|
|
|
|
(object)->objflags &= ~ASTOBJ_FLAG_MARKED; \
|
|
|
|
ASTOBJ_UNLOCK(object); \
|
|
|
|
} while(0)
|
2004-12-25 22:15:32 +00:00
|
|
|
|
|
|
|
#define ASTOBJ_DESTROY(object,destructor) \
|
|
|
|
do { \
|
2004-12-28 23:27:44 +00:00
|
|
|
if (__builtin_expect((object)->refcount, 1)) { \
|
|
|
|
ASTOBJ_WRLOCK(object); \
|
|
|
|
(object)->objflags |= ASTOBJ_FLAG_DELME; \
|
|
|
|
ASTOBJ_UNLOCK(object); \
|
|
|
|
} else { \
|
|
|
|
ast_mutex_destroy(&(object)->_lock); \
|
2004-12-25 22:15:32 +00:00
|
|
|
destructor((object)); \
|
2004-12-28 23:27:44 +00:00
|
|
|
} \
|
2004-12-25 22:15:32 +00:00
|
|
|
} while(0)
|
|
|
|
|
|
|
|
#define ASTOBJ_INIT(object) \
|
|
|
|
do { \
|
2004-12-28 23:27:44 +00:00
|
|
|
ast_mutex_init(&(object)->_lock); \
|
2004-12-25 22:15:32 +00:00
|
|
|
object->name[0] = '\0'; \
|
2004-12-28 23:27:44 +00:00
|
|
|
object->refcount = 1; \
|
2004-12-25 22:15:32 +00:00
|
|
|
} while(0)
|
|
|
|
|
|
|
|
/* Containers for objects -- current implementation is linked lists, but
|
|
|
|
should be able to be converted to hashes relatively easily */
|
|
|
|
|
2004-12-28 23:27:44 +00:00
|
|
|
#define ASTOBJ_CONTAINER_RDLOCK(container) ast_mutex_lock(&(container)->_lock)
|
|
|
|
#define ASTOBJ_CONTAINER_WRLOCK(container) ast_mutex_lock(&(container)->_lock)
|
|
|
|
#define ASTOBJ_CONTAINER_UNLOCK(container) ast_mutex_unlock(&(container)->_lock)
|
|
|
|
|
2004-12-25 22:15:32 +00:00
|
|
|
#ifdef ASTOBJ_CONTAINER_HASHMODEL
|
|
|
|
#error "Hash model for object containers not yet implemented!"
|
|
|
|
#else
|
|
|
|
/* Linked lists */
|
|
|
|
#define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,hashes,buckets) \
|
|
|
|
type *head
|
|
|
|
|
|
|
|
#define ASTOBJ_CONTAINER_INIT_FULL(container,hashes,buckets) \
|
|
|
|
do { \
|
2004-12-28 23:27:44 +00:00
|
|
|
ast_mutex_init(&(container)->_lock); \
|
2004-12-25 22:15:32 +00:00
|
|
|
} while(0)
|
|
|
|
|
2004-12-28 23:27:44 +00:00
|
|
|
#define ASTOBJ_CONTAINER_DESTROY_FULL(container,hashes,buckets) \
|
2004-12-25 22:15:32 +00:00
|
|
|
do { \
|
2004-12-28 23:27:44 +00:00
|
|
|
ast_mutex_destroy(&(container)->_lock); \
|
2004-12-25 22:15:32 +00:00
|
|
|
} while(0)
|
|
|
|
|
2004-12-28 23:27:44 +00:00
|
|
|
#define ASTOBJ_CONTAINER_TRAVERSE(container,eval) \
|
2004-12-25 22:15:32 +00:00
|
|
|
do { \
|
2004-12-28 23:27:44 +00:00
|
|
|
typeof((container)->head) iterator; \
|
|
|
|
typeof((container)->head) next; \
|
|
|
|
ASTOBJ_CONTAINER_RDLOCK(container); \
|
|
|
|
next = (container)->head; \
|
|
|
|
while((iterator = next)) { \
|
|
|
|
next = iterator->next[0]; \
|
2004-12-25 22:15:32 +00:00
|
|
|
eval; \
|
|
|
|
} \
|
2004-12-28 23:27:44 +00:00
|
|
|
ASTOBJ_CONTAINER_UNLOCK(container); \
|
2004-12-25 22:15:32 +00:00
|
|
|
} while(0)
|
|
|
|
|
2004-12-28 23:27:44 +00:00
|
|
|
#define ASTOBJ_CONTAINER_FIND_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \
|
|
|
|
({ \
|
|
|
|
typeof((container)->head) found = NULL; \
|
|
|
|
ASTOBJ_CONTAINER_TRAVERSE(container, do { \
|
|
|
|
ASTOBJ_RDLOCK(iterator); \
|
|
|
|
if (!(comparefunc(iterator->field, (data)))) { \
|
|
|
|
found = ASTOBJ_REF(iterator); \
|
|
|
|
} \
|
|
|
|
ASTOBJ_UNLOCK(iterator); \
|
|
|
|
if (found) \
|
2004-12-25 22:15:32 +00:00
|
|
|
break; \
|
2004-12-28 23:27:44 +00:00
|
|
|
} while (0)); \
|
|
|
|
found; \
|
|
|
|
})
|
2004-12-25 22:15:32 +00:00
|
|
|
|
2004-12-28 23:27:44 +00:00
|
|
|
#define ASTOBJ_CONTAINER_DESTROYALL(container,destructor) \
|
2004-12-25 22:15:32 +00:00
|
|
|
do { \
|
2004-12-28 23:27:44 +00:00
|
|
|
typeof((container)->head) iterator; \
|
|
|
|
ASTOBJ_CONTAINER_WRLOCK(container); \
|
|
|
|
while((iterator = (container)->head)) { \
|
2004-12-25 22:15:32 +00:00
|
|
|
(container)->head = (iterator)->next[0]; \
|
|
|
|
ASTOBJ_DESTROY(iterator,destructor); \
|
|
|
|
} \
|
2004-12-28 23:27:44 +00:00
|
|
|
ASTOBJ_CONTAINER_UNLOCK(container); \
|
2004-12-25 22:15:32 +00:00
|
|
|
} while(0)
|
|
|
|
|
2004-12-28 23:27:44 +00:00
|
|
|
#define ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \
|
|
|
|
({ \
|
|
|
|
typeof((container)->head) found = NULL; \
|
|
|
|
typeof((container)->head) prev = NULL; \
|
|
|
|
ASTOBJ_CONTAINER_TRAVERSE(container, do { \
|
|
|
|
ASTOBJ_RDLOCK(iterator); \
|
|
|
|
if (!(comparefunc(iterator->field, (data)))) { \
|
|
|
|
found = ASTOBJ_REF(iterator); \
|
|
|
|
ASTOBJ_CONTAINER_WRLOCK(container); \
|
|
|
|
if (prev) \
|
|
|
|
prev->next[0] = next; \
|
|
|
|
else \
|
|
|
|
(container)->head = next; \
|
|
|
|
ASTOBJ_CONTAINER_UNLOCK(container); \
|
|
|
|
break; \
|
2004-12-25 22:15:32 +00:00
|
|
|
} \
|
2004-12-28 23:27:44 +00:00
|
|
|
ASTOBJ_UNLOCK(iterator); \
|
|
|
|
if (found) \
|
|
|
|
break; \
|
|
|
|
prev = iterator; \
|
|
|
|
} while (0)); \
|
|
|
|
found; \
|
|
|
|
})
|
2004-12-25 22:15:32 +00:00
|
|
|
|
2004-12-28 23:27:44 +00:00
|
|
|
#define ASTOBJ_CONTAINER_PRUNE_MARKED(container,destructor) \
|
2004-12-25 22:15:32 +00:00
|
|
|
do { \
|
2004-12-28 23:27:44 +00:00
|
|
|
typeof((container)->head) prev = NULL; \
|
|
|
|
ASTOBJ_CONTAINER_TRAVERSE(container, do { \
|
|
|
|
ASTOBJ_RDLOCK(iterator); \
|
|
|
|
if (iterator->objflags & ASTOBJ_FLAG_MARKED) { \
|
|
|
|
ASTOBJ_CONTAINER_WRLOCK(container); \
|
|
|
|
if (prev) \
|
|
|
|
prev->next[0] = next; \
|
2004-12-25 22:15:32 +00:00
|
|
|
else \
|
2004-12-28 23:27:44 +00:00
|
|
|
(container)->head = next; \
|
|
|
|
ASTOBJ_CONTAINER_UNLOCK(container); \
|
|
|
|
ASTOBJ_UNLOCK(iterator); \
|
2004-12-25 22:15:32 +00:00
|
|
|
ASTOBJ_DESTROY(iterator,destructor); \
|
2004-12-28 23:27:44 +00:00
|
|
|
continue; \
|
2004-12-25 22:15:32 +00:00
|
|
|
} \
|
2004-12-28 23:27:44 +00:00
|
|
|
ASTOBJ_UNLOCK(iterator); \
|
|
|
|
prev = iterator; \
|
|
|
|
} while (0)); \
|
2004-12-25 22:15:32 +00:00
|
|
|
} while(0)
|
|
|
|
|
|
|
|
#define ASTOBJ_CONTAINER_LINK_FULL(container,newobj,data,field,hashfunc,hashoffset,comparefunc) \
|
|
|
|
do { \
|
2004-12-28 23:27:44 +00:00
|
|
|
ASTOBJ_CONTAINER_WRLOCK(container); \
|
2004-12-25 22:15:32 +00:00
|
|
|
(newobj)->next[0] = (container)->head; \
|
|
|
|
(container)->head = (newobj); \
|
2004-12-28 23:27:44 +00:00
|
|
|
ASTOBJ_CONTAINER_UNLOCK(container); \
|
2004-12-25 22:15:32 +00:00
|
|
|
} while(0)
|
|
|
|
|
2004-12-28 23:27:44 +00:00
|
|
|
#endif /* List model */
|
2004-12-25 22:15:32 +00:00
|
|
|
|
|
|
|
/* Common to hash and linked list models */
|
|
|
|
#define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type) \
|
|
|
|
ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,1,ASTOBJ_DEFAULT_BUCKETS)
|
|
|
|
|
|
|
|
#define ASTOBJ_CONTAINER_COMPONENTS(type) \
|
2004-12-28 23:27:44 +00:00
|
|
|
ast_mutex_t _lock; \
|
2004-12-25 22:15:32 +00:00
|
|
|
ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type)
|
|
|
|
|
|
|
|
#define ASTOBJ_CONTAINER_INIT(container) \
|
|
|
|
ASTOBJ_CONTAINER_INIT_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
|
|
|
|
|
2004-12-28 23:27:44 +00:00
|
|
|
#define ASTOBJ_CONTAINER_DESTROY(container) \
|
|
|
|
ASTOBJ_CONTAINER_DESTROY_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
|
2004-12-25 22:15:32 +00:00
|
|
|
|
2004-12-28 23:27:44 +00:00
|
|
|
#define ASTOBJ_CONTAINER_FIND(container,namestr) \
|
|
|
|
ASTOBJ_CONTAINER_FIND_FULL(container,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
|
2004-12-25 22:15:32 +00:00
|
|
|
|
2004-12-28 23:27:44 +00:00
|
|
|
#define ASTOBJ_CONTAINER_FIND_UNLINK(container,namestr) \
|
|
|
|
ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
|
2004-12-25 22:15:32 +00:00
|
|
|
|
|
|
|
#define ASTOBJ_CONTAINER_LINK(container,newobj) \
|
|
|
|
ASTOBJ_CONTAINER_LINK_FULL(container,newobj,(newobj)->name,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
|
|
|
|
|
2004-12-28 23:27:44 +00:00
|
|
|
#define ASTOBJ_CONTAINER_MARKALL(container) \
|
|
|
|
ASTOBJ_CONTAINER_TRAVERSE(container,ASTOBJ_MARK(iterator))
|
2004-12-25 22:15:32 +00:00
|
|
|
|
2004-12-28 23:27:44 +00:00
|
|
|
#define ASTOBJ_CONTAINER_UNMARKALL(container) \
|
|
|
|
ASTOBJ_CONTAINER_TRAVERSE(container,ASTOBJ_UNMARK(iterator))
|
2004-12-25 22:15:32 +00:00
|
|
|
|
|
|
|
#define ASTOBJ_DUMP(s,slen,obj) \
|
|
|
|
snprintf((s),(slen),"name: %s\nobjflags: %d\nrefcount: %d\n\n", (obj)->name, (obj)->objflags, (obj)->refcount);
|
|
|
|
|
2004-12-28 23:27:44 +00:00
|
|
|
#define ASTOBJ_CONTAINER_DUMP(fd,s,slen,container) \
|
|
|
|
ASTOBJ_CONTAINER_TRAVERSE(container,do { ASTOBJ_DUMP(s,slen,iterator); ast_cli(fd, s); } while(0))
|
2004-12-25 22:15:32 +00:00
|
|
|
|
|
|
|
#if defined(__cplusplus) || defined(c_plusplus)
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|