[asterisk-commits] murf: branch murf/bug11210 r103829 - in /team/murf/bug11210: channels/ main/ ...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Feb 19 16:15:12 CST 2008
Author: murf
Date: Tue Feb 19 16:15:12 2008
New Revision: 103829
URL: http://svn.digium.com/view/asterisk?view=rev&rev=103829
Log:
A reorganization of the changes to astobj2.c; all funcs (debug & normal) will be present at all times. Common code to both is gathered into __ao2_xxx funcs, which reduces duplicated code, which is a better way to go. Made a mistake and spent a couple hours tracking it down. Tested. Looks good.
Modified:
team/murf/bug11210/channels/chan_iax2.c
team/murf/bug11210/main/astobj2.c
team/murf/bug11210/utils/refcounter.c
Modified: team/murf/bug11210/channels/chan_iax2.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug11210/channels/chan_iax2.c?view=diff&rev=103829&r1=103828&r2=103829
==============================================================================
--- team/murf/bug11210/channels/chan_iax2.c (original)
+++ team/murf/bug11210/channels/chan_iax2.c Tue Feb 19 16:15:12 2008
@@ -92,7 +92,7 @@
might be crashes during the destruction of astobj2 objects, which could
be a symptom of the object being destroyed multiple times.
*/
-/* #define REF_DEBUG 1 */
+#define REF_DEBUG 1
#include "asterisk/astobj2.h"
#include "iax2.h"
Modified: team/murf/bug11210/main/astobj2.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug11210/main/astobj2.c?view=diff&rev=103829&r1=103828&r2=103829
==============================================================================
--- team/murf/bug11210/main/astobj2.c (original)
+++ team/murf/bug11210/main/astobj2.c Tue Feb 19 16:15:12 2008
@@ -22,6 +22,9 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/_private.h"
+/* make ALL functions available so if any file needs to use
+ the refcount debug tracing, it will be available. Turn
+ it off you want to save a little space */
#define REF_DEBUG 1
#include "asterisk/astobj2.h"
#include "asterisk/utils.h"
@@ -128,6 +131,18 @@
*/
#define EXTERNAL_OBJ(_p) ((_p) == NULL ? NULL : (_p)->user_data)
+/* the underlying functions common to debug and non-debug versions */
+
+static int __ao2_ref(void *user_data, const int delta);
+static void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn);
+static struct ao2_container *__ao2_container_alloc(struct ao2_container *c, const uint n_buckets, ao2_hash_fn *hash_fn,
+ ao2_callback_fn *cmp_fn);
+static struct bucket_list *__ao2_link(struct ao2_container *c, void *user_data);
+static void *__ao2_callback(struct ao2_container *c,
+ const enum search_flags flags, ao2_callback_fn *cb_fn, void *arg,
+ char *tag, char *file, int line, const char *funcname);
+static void * __ao2_iterator_next(struct ao2_iterator *a, struct bucket_list **q);
+
int ao2_lock(void *user_data)
{
struct astobj2 *p = INTERNAL_OBJ(user_data);
@@ -160,25 +175,39 @@
* The argument is a pointer to the user portion.
*/
-#ifdef REF_DEBUG
-#define REF_FILE "/tmp/refs"
int ao2_ref_debug(void *user_data, const int delta, char *tag, char *file, int line, const char *funcname)
{
- int current_value;
- int ret;
struct astobj2 *obj = INTERNAL_OBJ(user_data);
if (obj == NULL)
return -1;
if (delta != 0) {
-
FILE *refo = fopen(REF_FILE,"a");
fprintf(refo, "%p %s%d %s:%d:%s (%s) [@%d]\n", user_data, (delta<0? "":"+"), delta, file, line, funcname, tag, obj->priv_data.ref_counter);
fclose(refo);
}
-
+ return __ao2_ref(user_data, delta);
+
+}
+
+int ao2_ref(void *user_data, const int delta)
+{
+ struct astobj2 *obj = INTERNAL_OBJ(user_data);
+
+ if (obj == NULL)
+ return -1;
+
+ return __ao2_ref(user_data, delta);
+}
+
+static int __ao2_ref(void *user_data, const int delta)
+{
+ struct astobj2 *obj = INTERNAL_OBJ(user_data);
+ int current_value;
+ int ret;
+
/* if delta is 0, just return the refcount */
if (delta == 0)
return (obj->priv_data.ref_counter);
@@ -193,15 +222,12 @@
/* this case must never happen */
if (current_value < 0)
- ast_log(LOG_ERROR, "refcount %d on object %p -- fix your code!\n", current_value, user_data);
-
- if (current_value == 0) { /* last reference, destroy the object */
- if (obj->priv_data.destructor_fn != NULL) {
- FILE *refo = fopen(REF_FILE,"a");
- fprintf(refo, "%p **call destructor** %s:%d:%s (%s)\n", user_data, file, line, funcname, tag);
- fclose(refo);
+ ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, user_data);
+
+ if (current_value <= 0) { /* last reference, destroy the object */
+ if (obj->priv_data.destructor_fn != NULL)
obj->priv_data.destructor_fn(user_data);
- }
+
ast_mutex_destroy(&obj->priv_data.lock);
#ifdef AO2_DEBUG
ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
@@ -212,55 +238,6 @@
* allocated. */
bzero(obj, sizeof(struct astobj2 *) + sizeof(void *) );
free(obj);
- } else if (current_value < 0) {
- FILE *refo = fopen(REF_FILE,"a");
- fprintf(refo, "%p **Refcount 0 or less** [%d] %s:%d:%s (%s)\n", user_data, current_value, file, line, funcname, tag);
- fclose(refo);
- }
- return ret;
-}
-
-#endif
-
-int ao2_ref(void *user_data, const int delta)
-{
- int current_value;
- int ret;
- struct astobj2 *obj = INTERNAL_OBJ(user_data);
-
- if (obj == NULL)
- return -1;
-
- /* if delta is 0, just return the refcount */
- if (delta == 0)
- return (obj->priv_data.ref_counter);
-
- /* we modify with an atomic operation the reference counter */
- ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta);
- current_value = ret + delta;
-
-#ifdef AO2_DEBUG
- ast_atomic_fetchadd_int(&ao2.total_refs, delta);
-#endif
-
- /* this case must never happen */
- if (current_value < 0)
- ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, user_data);
-
- if (current_value <= 0) { /* last reference, destroy the object */
- if (obj->priv_data.destructor_fn != NULL)
- obj->priv_data.destructor_fn(user_data);
-
- ast_mutex_destroy(&obj->priv_data.lock);
-#ifdef AO2_DEBUG
- ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
- ast_atomic_fetchadd_int(&ao2.total_objects, -1);
-#endif
- /* for safety, zero-out the astobj2 header and also the
- * first word of the user-data, which we make sure is always
- * allocated. */
- bzero(obj, sizeof(struct astobj2 *) + sizeof(void *) );
- free(obj);
}
return ret;
@@ -270,12 +247,10 @@
* We always alloc at least the size of a void *,
* for debugging purposes.
*/
-#ifdef REF_DEBUG
-void *ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, char *tag, char *file, int line, const char *funcname)
+static void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn)
{
/* allocation */
struct astobj2 *obj;
- FILE *refo = fopen(REF_FILE,"a");
if (data_size < sizeof(void *))
data_size = sizeof(void *);
@@ -284,9 +259,6 @@
if (obj == NULL)
return NULL;
-
- fprintf(refo, "%p =1 %s:%d:%s (%s)\n", EXTERNAL_OBJ(obj), file, line, funcname, tag);
- fclose(refo);
ast_mutex_init(&obj->priv_data.lock);
obj->priv_data.magic = AO2_MAGIC;
@@ -303,36 +275,32 @@
/* return a pointer to the user data */
return EXTERNAL_OBJ(obj);
}
-#endif
+
+void *ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, char *tag, char *file, int line, const char *funcname)
+{
+ /* allocation */
+ void *obj;
+ FILE *refo = fopen(REF_FILE,"a");
+
+ obj = __ao2_alloc(data_size, destructor_fn);
+
+ if (obj == NULL)
+ return NULL;
+
+ if (refo) {
+ fprintf(refo, "%p =1 %s:%d:%s (%s)\n", obj, file, line, funcname, tag);
+ fclose(refo);
+ }
+
+ /* return a pointer to the user data */
+ return obj;
+}
void *ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn)
{
- /* allocation */
- struct astobj2 *obj;
-
- if (data_size < sizeof(void *))
- data_size = sizeof(void *);
-
- obj = ast_calloc(1, sizeof(*obj) + data_size);
-
- if (obj == NULL)
- return NULL;
-
- ast_mutex_init(&obj->priv_data.lock);
- obj->priv_data.magic = AO2_MAGIC;
- obj->priv_data.data_size = data_size;
- obj->priv_data.ref_counter = 1;
- obj->priv_data.destructor_fn = destructor_fn; /* can be NULL */
-
-#ifdef AO2_DEBUG
- ast_atomic_fetchadd_int(&ao2.total_objects, 1);
- ast_atomic_fetchadd_int(&ao2.total_mem, data_size);
- ast_atomic_fetchadd_int(&ao2.total_refs, 1);
-#endif
-
- /* return a pointer to the user data */
- return EXTERNAL_OBJ(obj);
-}
+ return __ao2_alloc(data_size, destructor_fn);
+}
+
/* internal callback to destroy a container. */
static void container_destruct(void *c);
@@ -394,30 +362,37 @@
/*
* A container is just an object, after all!
*/
-#ifdef REF_DEBUG
-struct ao2_container *
-ao2_container_alloc_debug(const uint n_buckets, ao2_hash_fn *hash_fn,
+static struct ao2_container *__ao2_container_alloc(struct ao2_container *c, const uint n_buckets, ao2_hash_fn *hash_fn,
+ ao2_callback_fn *cmp_fn)
+{
+ /* XXX maybe consistency check on arguments ? */
+ /* compute the container size */
+
+ if (!c)
+ return NULL;
+
+ c->version = 1; /* 0 is a reserved value here */
+ c->n_buckets = n_buckets;
+ c->hash_fn = hash_fn ? hash_fn : hash_zero;
+ c->cmp_fn = cmp_fn;
+
+#ifdef AO2_DEBUG
+ ast_atomic_fetchadd_int(&ao2.total_containers, 1);
+#endif
+
+ return c;
+}
+
+struct ao2_container *ao2_container_alloc_debug(const uint n_buckets, ao2_hash_fn *hash_fn,
ao2_callback_fn *cmp_fn, char *tag, char *file, int line, const char *funcname)
{
/* XXX maybe consistency check on arguments ? */
/* compute the container size */
size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket);
struct ao2_container *c = ao2_alloc_debug(container_size, container_destruct_debug, tag, file, line, funcname);
- if (!c)
- return NULL;
-
- c->version = 1; /* 0 is a reserved value here */
- c->n_buckets = n_buckets;
- c->hash_fn = hash_fn ? hash_fn : hash_zero;
- c->cmp_fn = cmp_fn;
-
-#ifdef AO2_DEBUG
- ast_atomic_fetchadd_int(&ao2.total_containers, 1);
-#endif
-
- return c;
-}
-#endif
+
+ return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
+}
struct ao2_container *
ao2_container_alloc(const uint n_buckets, ao2_hash_fn *hash_fn,
@@ -425,21 +400,11 @@
{
/* XXX maybe consistency check on arguments ? */
/* compute the container size */
+
size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket);
struct ao2_container *c = ao2_alloc(container_size, container_destruct);
- if (!c)
- return NULL;
-
- c->version = 1; /* 0 is a reserved value here */
- c->n_buckets = n_buckets;
- c->hash_fn = hash_fn ? hash_fn : hash_zero;
- c->cmp_fn = cmp_fn;
-
-#ifdef AO2_DEBUG
- ast_atomic_fetchadd_int(&ao2.total_containers, 1);
-#endif
-
- return c;
+
+ return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
}
/*!
@@ -461,11 +426,11 @@
struct astobj2 *astobj; /* pointer to internal data */
};
-#ifdef REF_DEBUG
/*
* link an object to a container
*/
-void *ao2_link_debug(struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
+
+static struct bucket_list *__ao2_link(struct ao2_container *c, void *user_data)
{
int i;
/* create a new list entry */
@@ -490,44 +455,30 @@
p->version = ast_atomic_fetchadd_int(&c->version, 1);
AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
ast_atomic_fetchadd_int(&c->elements, 1);
- ao2_ref_debug(user_data, +1, tag, file, line, funcname);
- ao2_unlock(c);
-
+
+ /* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */
return p;
}
-#endif
-
-/*
- * link an object to a container
- */
+
+void *ao2_link_debug(struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
+{
+ struct bucket_list *p = __ao2_link(c, user_data);
+
+ if (p) {
+ ao2_ref_debug(user_data, +1, tag, file, line, funcname);
+ ao2_unlock(c);
+ }
+ return p;
+}
+
void *ao2_link(struct ao2_container *c, void *user_data)
{
- int i;
- /* create a new list entry */
- struct bucket_list *p;
- struct astobj2 *obj = INTERNAL_OBJ(user_data);
-
- if (!obj)
- return NULL;
-
- if (INTERNAL_OBJ(c) == NULL)
- return NULL;
-
- p = ast_calloc(1, sizeof(*p));
- if (!p)
- return NULL;
-
- i = c->hash_fn(user_data, OBJ_POINTER);
-
- ao2_lock(c);
- i %= c->n_buckets;
- p->astobj = obj;
- p->version = ast_atomic_fetchadd_int(&c->version, 1);
- AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
- ast_atomic_fetchadd_int(&c->elements, 1);
- ao2_ref(user_data, +1);
- ao2_unlock(c);
-
+ struct bucket_list *p = __ao2_link(c, user_data);
+
+ if (p) {
+ ao2_ref(user_data, +1);
+ ao2_unlock(c);
+ }
return p;
}
@@ -543,7 +494,6 @@
* Unlink an object from the container
* and destroy the associated * ao2_bucket_list structure.
*/
-#ifdef REF_DEBUG
void *ao2_unlink_debug(struct ao2_container *c, void *user_data, char *tag,
char *file, int line, const char *funcname)
{
@@ -554,7 +504,6 @@
return NULL;
}
-#endif
void *ao2_unlink(struct ao2_container *c, void *user_data)
{
@@ -579,12 +528,13 @@
* Browse the container using different stategies accoding the flags.
* \return Is a pointer to an object or to a list of object if OBJ_MULTIPLE is
* specified.
- */
-#ifdef REF_DEBUG
-void *ao2_callback_debug(struct ao2_container *c,
- const enum search_flags flags,
- ao2_callback_fn *cb_fn, void *arg,
- char *tag, char *file, int line, const char *funcname)
+ * Luckily, for debug purposes, the added args (tag, file, line, funcname)
+ * aren't an excessive load to the system, as the callback should not be
+ * called as often as, say, the ao2_ref func is called.
+ */
+static void *__ao2_callback(struct ao2_container *c,
+ const enum search_flags flags, ao2_callback_fn *cb_fn, void *arg,
+ char *tag, char *file, int line, const char *funcname)
{
int i, last; /* search boundaries */
void *ret = NULL;
@@ -639,7 +589,10 @@
if (!(flags & OBJ_NODATA)) { /* if must return the object, record the value */
/* it is important to handle this case before the unlink */
ret = EXTERNAL_OBJ(cur->astobj);
- ao2_ref_debug(ret, 1, tag, file, line, funcname);
+ if (tag)
+ ao2_ref_debug(ret, 1, tag, file, line, funcname);
+ else
+ ao2_ref(ret, 1);
}
if (flags & OBJ_UNLINK) { /* must unlink */
@@ -650,7 +603,10 @@
AST_LIST_REMOVE_CURRENT(entry);
/* update number of elements and version */
ast_atomic_fetchadd_int(&c->elements, -1);
- ao2_ref_debug(EXTERNAL_OBJ(x->astobj), -1, tag, file, line, funcname);
+ if (tag)
+ ao2_ref_debug(EXTERNAL_OBJ(x->astobj), -1, tag, file, line, funcname);
+ else
+ ao2_ref(EXTERNAL_OBJ(x->astobj), -1);
free(x); /* free the link record */
}
@@ -673,109 +629,29 @@
ao2_unlock(c);
return ret;
}
-#endif
+
+void *ao2_callback_debug(struct ao2_container *c,
+ const enum search_flags flags,
+ ao2_callback_fn *cb_fn, void *arg,
+ char *tag, char *file, int line, const char *funcname)
+{
+ return __ao2_callback(c,flags, cb_fn, arg, tag, file, line, funcname);
+}
void *ao2_callback(struct ao2_container *c,
const enum search_flags flags,
ao2_callback_fn *cb_fn, void *arg)
{
- int i, last; /* search boundaries */
- void *ret = NULL;
-
- if (INTERNAL_OBJ(c) == NULL) /* safety check on the argument */
- return NULL;
-
- if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) {
- ast_log(LOG_WARNING, "multiple data return not implemented yet (flags %x)\n", flags);
- return NULL;
- }
-
- /* override the match function if necessary */
- if (cb_fn == NULL) /* if NULL, match everything */
- cb_fn = cb_true;
- /*
- * XXX this can be optimized.
- * If we have a hash function and lookup by pointer,
- * run the hash function. Otherwise, scan the whole container
- * (this only for the time being. We need to optimize this.)
- */
- if ((flags & OBJ_POINTER)) /* we know hash can handle this case */
- i = c->hash_fn(arg, flags & OBJ_POINTER) % c->n_buckets;
- else /* don't know, let's scan all buckets */
- i = -1; /* XXX this must be fixed later. */
-
- /* determine the search boundaries: i..last-1 */
- if (i < 0) {
- i = 0;
- last = c->n_buckets;
- } else {
- last = i + 1;
- }
-
- ao2_lock(c); /* avoid modifications to the content */
-
- for (; i < last ; i++) {
- /* scan the list with prev-cur pointers */
- struct bucket_list *cur;
-
- AST_LIST_TRAVERSE_SAFE_BEGIN(&c->buckets[i], cur, entry) {
- int match = cb_fn(EXTERNAL_OBJ(cur->astobj), arg, flags) & (CMP_MATCH | CMP_STOP);
-
- /* we found the object, performing operations according flags */
- if (match == 0) { /* no match, no stop, continue */
- continue;
- } else if (match == CMP_STOP) { /* no match but stop, we are done */
- i = last;
- break;
- }
- /* we have a match (CMP_MATCH) here */
- if (!(flags & OBJ_NODATA)) { /* if must return the object, record the value */
- /* it is important to handle this case before the unlink */
- ret = EXTERNAL_OBJ(cur->astobj);
- ao2_ref(ret, 1);
- }
-
- if (flags & OBJ_UNLINK) { /* must unlink */
- struct bucket_list *x = cur;
-
- /* we are going to modify the container, so update version */
- ast_atomic_fetchadd_int(&c->version, 1);
- AST_LIST_REMOVE_CURRENT(entry);
- /* update number of elements and version */
- ast_atomic_fetchadd_int(&c->elements, -1);
- ao2_ref(EXTERNAL_OBJ(x->astobj), -1);
- free(x); /* free the link record */
- }
-
- if ((match & CMP_STOP) || (flags & OBJ_MULTIPLE) == 0) {
- /* We found the only match we need */
- i = last; /* force exit from outer loop */
- break;
- }
- if (!(flags & OBJ_NODATA)) {
-#if 0 /* XXX to be completed */
- /*
- * This is the multiple-return case. We need to link
- * the object in a list. The refcount is already increased.
- */
-#endif
- }
- }
- AST_LIST_TRAVERSE_SAFE_END;
- }
- ao2_unlock(c);
- return ret;
+ return __ao2_callback(c,flags, cb_fn, arg, NULL, NULL, 0, NULL);
}
/*!
* the find function just invokes the default callback with some reasonable flags.
*/
-#ifdef REF_DEBUG
void *ao2_find_debug(struct ao2_container *c, void *arg, enum search_flags flags, char *tag, char *file, int line, const char *funcname)
{
return ao2_callback_debug(c, flags, c->cmp_fn, arg, tag, file, line, funcname);
}
-#endif
void *ao2_find(struct ao2_container *c, void *arg, enum search_flags flags)
{
@@ -798,13 +674,14 @@
/*
* move to the next element in the container.
*/
-#ifdef REF_DEBUG
-void * ao2_iterator_next_debug(struct ao2_iterator *a, char *tag, char *file, int line, const char *funcname)
+static void * __ao2_iterator_next(struct ao2_iterator *a, struct bucket_list **q)
{
int lim;
struct bucket_list *p = NULL;
void *ret = NULL;
+ *q = NULL;
+
if (INTERNAL_OBJ(a->c) == NULL)
return NULL;
@@ -846,6 +723,21 @@
a->c_version = a->c->version;
ret = EXTERNAL_OBJ(p->astobj);
/* inc refcount of returned object */
+ *q = p;
+ }
+
+ return ret;
+}
+
+void * ao2_iterator_next_debug(struct ao2_iterator *a, char *tag, char *file, int line, const char *funcname)
+{
+ struct bucket_list *p;
+ void *ret = NULL;
+
+ ret = __ao2_iterator_next(a, &p);
+
+ if (p) {
+ /* inc refcount of returned object */
ao2_ref_debug(ret, 1, tag, file, line, funcname);
}
@@ -854,54 +746,15 @@
return ret;
}
-#endif
void * ao2_iterator_next(struct ao2_iterator *a)
{
- int lim;
struct bucket_list *p = NULL;
void *ret = NULL;
- if (INTERNAL_OBJ(a->c) == NULL)
- return NULL;
-
- if (!(a->flags & F_AO2I_DONTLOCK))
- ao2_lock(a->c);
-
- /* optimization. If the container is unchanged and
- * we have a pointer, try follow it
- */
- if (a->c->version == a->c_version && (p = a->obj) ) {
- if ( (p = AST_LIST_NEXT(p, entry)) )
- goto found;
- /* nope, start from the next bucket */
- a->bucket++;
- a->version = 0;
- a->obj = NULL;
- }
-
- lim = a->c->n_buckets;
-
- /* Browse the buckets array, moving to the next
- * buckets if we don't find the entry in the current one.
- * Stop when we find an element with version number greater
- * than the current one (we reset the version to 0 when we
- * switch buckets).
- */
- for (; a->bucket < lim; a->bucket++, a->version = 0) {
- /* scan the current bucket */
- AST_LIST_TRAVERSE(&a->c->buckets[a->bucket], p, entry) {
- if (p->version > a->version)
- goto found;
- }
- }
-
-found:
+ ret = __ao2_iterator_next(a, &p);
+
if (p) {
- a->version = p->version;
- a->obj = p;
- a->c_version = a->c->version;
- ret = EXTERNAL_OBJ(p->astobj);
/* inc refcount of returned object */
ao2_ref(ret, 1);
}
Modified: team/murf/bug11210/utils/refcounter.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug11210/utils/refcounter.c?view=diff&rev=103829&r1=103828&r2=103829
==============================================================================
--- team/murf/bug11210/utils/refcounter.c (original)
+++ team/murf/bug11210/utils/refcounter.c Tue Feb 19 16:15:12 2008
@@ -229,6 +229,13 @@
}
+#undef ast_mark
+
+int64_t ast_mark(int x, int start1_stop0)
+{
+ return 0;
+}
+
void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
{
va_list vars;
More information about the asterisk-commits
mailing list