[asterisk-commits] murf: branch murf/bug11210 r103660 - in /team/murf/bug11210: channels/ utils/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Feb 13 13:08:13 CST 2008


Author: murf
Date: Wed Feb 13 13:08:13 2008
New Revision: 103660

URL: http://svn.digium.com/view/asterisk?view=rev&rev=103660
Log:
Another checkpoint. Found the problem with the undestroyed dialogs. Thought I found the last fix, but when I did a grep of the object history, there were 2 objects not destroyed. So I wrote the refcounter utility to scan the log and report the problem-- two peer objects (out of 4700) were not destroyed. Working on that now.

Added:
    team/murf/bug11210/utils/refcounter.c   (with props)
Modified:
    team/murf/bug11210/channels/chan_sip.c

Modified: team/murf/bug11210/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug11210/channels/chan_sip.c?view=diff&rev=103660&r1=103659&r2=103660
==============================================================================
--- team/murf/bug11210/channels/chan_sip.c (original)
+++ team/murf/bug11210/channels/chan_sip.c Wed Feb 13 13:08:13 2008
@@ -2430,7 +2430,7 @@
 
 	AST_SCHED_DEL_UNREF(sched, dialog->initid, dialog_unref(dialog, "when you delete the initid sched, you should dec the refcount for the stored dialog ptr"));
 	
-	if (dialog->autokillid != -1)
+	if (dialog->autokillid > -1)
 		AST_SCHED_DEL_UNREF(sched, dialog->autokillid, dialog_unref(dialog, "when you delete the autokillid sched, you should dec the refcount for the stored dialog ptr"));
 
 	dialog_unref(dialog, "Let's unbump the count in the unlink so the poor pvt can disappear if it is time");
@@ -3051,20 +3051,19 @@
 	if (p->autokillid != -1) {
 		/* a SCHED_DEL(_UNREF) was done here... which makes no sense... it's ALWAYS removed from the queue
 		   before the callback is called... */
-		p->autokillid = -1; /* but, it is a really good idea to unset the autokillid field if we aren't going to resched */
+		
+		p->autokillid = -1; /* but, it is a really good idea to unset the autokillid field if its truly bogus now */
 		append_history(p, "CancelDestroy", "");
 	}
 
 	if (p->owner) {
 		ast_log(LOG_WARNING, "Autodestruct on dialog '%s' with owner in place (Method: %s)\n", p->callid, sip_methods[p->method].text);
 		ast_queue_hangup(p->owner);
-		dialog_unref(p, "unref dialog when owner is set");
 	} else if (p->refer) {
 		ast_debug(3, "Finally hanging up channel after transfer: %s\n", p->callid);
 		transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
 		append_history(p, "ReferBYE", "Sending BYE on transferer call leg %s", p->callid);
 		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-		dialog_unref(p, "unref dialog when refer is set");
 	} else {
 		append_history(p, "AutoDestroy", "%s", p->callid);
 		ast_debug(3, "Auto destroying SIP dialog '%s'\n", p->callid);
@@ -3073,6 +3072,7 @@
 		/* sip_destroy(p); */		/* Go ahead and destroy dialog. All attempts to recover is done */
 		/* sip_destroy also absorbs the reference */
 	}
+	dialog_unref(p, "The ref to a dialog passed to this sched callback is going out of scope; unref it.");
 	dialog_unref(p, "UNBump counter in autodestruct to ALLOW  destructio of dialog");
 	return 0;
 }
@@ -3107,15 +3107,17 @@
 static int sip_cancel_destroy(struct sip_pvt *p)
 {
 	int res = 0;
+	ast_log(LOG_NOTICE,"sip_cancel_destroy called for dialog %p, with autokillid=%d\n", 
+			p, p->autokillid);
+	
 	if (p->autokillid > -1) {
 		int res3;
 		
 		if (!(res3 = ast_sched_del(sched, p->autokillid))) {
 			append_history(p, "CancelDestroy", "");
 			p->autokillid = -1;
-		}
-		if (!res3)
 			dialog_unref(p, "dialog unrefd because autokillid is de-sched'd");
+		}
 	}
 	return res;
 }
@@ -12332,7 +12334,9 @@
 		sip_pvt_unlock(dialog);
 		/* no, the unlink should handle this: dialog_unref(dialog, "needdestroy: one more refcount decrement to allow dialog to be destroyed"); */
 		/* the CMP_MATCH will unlink this dialog from the dialog hash table */
-		return CMP_MATCH;
+		dialog_unlink_all(dialog, TRUE, FALSE);
+		
+		return 0; /* the unlink_all should unlink this from the table, so.... no need to return a match */
 	}
 	sip_pvt_unlock(dialog);
 	return 0;
@@ -19277,7 +19281,7 @@
 			/* there is no address, it's unavailable */
 			res = AST_DEVICE_UNAVAILABLE;
 		}
-		unref_peer(p, "unref_peer, from sip_devicestate");
+		unref_peer(p, "unref_peer, from sip_devicestate, release ref from find_peer");
 	} else {
 		res = AST_DEVICE_UNKNOWN;
 	}
@@ -22414,7 +22418,7 @@
 	/* Destroy all the dialogs and free their memory */
 	i = ao2_iterator_init(dialogs, 0);
 	while ((p = ao2_t_iterator_next(&i, "iterate thru dialogs"))) {
-		ao2_t_unlink(dialogs, p, "unlink from dialogs");
+		dialog_unlink_all(p, TRUE, TRUE);
 		ao2_t_ref(p, -1, "throw away iterator result"); 
 	}
 

Added: team/murf/bug11210/utils/refcounter.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug11210/utils/refcounter.c?view=auto&rev=103660
==============================================================================
--- team/murf/bug11210/utils/refcounter.c (added)
+++ team/murf/bug11210/utils/refcounter.c Wed Feb 13 13:08:13 2008
@@ -1,0 +1,251 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2008, Steve Murphy
+ *
+ * Steve Murphy <murf at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+/*! \file
+ *
+ *  \brief A program to thoroughly thrash a hash table, testing
+ *         out locking safety, and making sure all functionality
+ *         is functioning. Run with 5 or more threads to get that
+ *         fully intense firestorm of activity. If your
+ *         hash tables don't crash, lock up, or go weird, it must
+ *         be good code! Even features some global counters
+ *         that will get slightly behind because they aren't lock-protected.
+ *
+ *  \author Steve Murphy <murf at digium.com>
+ */
+
+#include "asterisk.h"
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <pthread.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <errno.h>
+#include "asterisk/lock.h"
+#include "asterisk/hashtab.h"
+#include "asterisk/channel.h"
+#include "asterisk/utils.h"
+#include "asterisk/module.h"
+
+struct rc_hist
+{
+	char *desc;
+	struct rc_hist *next;
+};
+
+struct rc_obj /* short for refcounted object */
+{
+	unsigned int addr;
+	unsigned int count;  /* this plus addr makes each entry unique, starts at 1 */
+	int last_count; /* count 1 objects will record how many other objects had the same addr */
+	int destroy_count;
+	int total_refcount;
+	struct rc_hist *hist;
+	struct rc_hist *last;
+};
+
+static unsigned int hashtab_hash_rc(const void *obj)
+{
+	const struct rc_obj *rc = obj;
+	return rc->addr + rc->count; /* it's addr will make a FINE hash */
+}
+
+static int hashtab_compare_rc(const void *a, const void *b)
+{
+	const struct rc_obj *rca = a;
+	const struct rc_obj *rcb = b;
+	if (rca->addr == rcb->addr && rca->count == rcb->count)
+		return 0;
+	else
+		return 1;
+}
+
+
+static struct rc_obj *alloc_obj(unsigned int addr, unsigned int count)
+{
+	struct rc_obj *x = calloc(1,sizeof(struct rc_obj));
+	x->addr = addr;
+	x->count = count;
+	x->last_count = 1;
+	x->total_refcount = 1;
+	return x;
+}
+
+static void add_to_hist(char *buffer, struct rc_obj *obj)
+{
+	struct rc_hist *y = calloc(1,sizeof(struct rc_hist));
+	y->desc = strdup(buffer);
+	if (obj->last) {
+		obj->last->next = y;
+		obj->last = y;
+	} else {
+		obj->hist = obj->last = y;
+	}
+}
+
+
+
+main(int argc,char **argv)
+{
+	char linebuffer[300];
+	FILE *ifile = fopen("/tmp/refs", "r");
+	char *t;
+	unsigned int un;
+	int curcount;
+	struct rc_obj *curr_obj, *count1_obj;
+	struct rc_obj lookup;
+	struct ast_hashtab_iter *it;
+	
+	if (!ifile) {
+		printf("Sorry, Cannot open /tmp/refs!\n");
+		exit(10);
+	}
+	
+	struct ast_hashtab *objhash = ast_hashtab_create(9000, hashtab_compare_rc, ast_hashtab_resize_java, ast_hashtab_newsize_java, hashtab_hash_rc, 1);
+	
+	while (fgets(linebuffer, sizeof(linebuffer), ifile)) {
+		/* collect data about the entry */
+		un = strtoul(linebuffer, &t, 16);
+		lookup.addr = un;
+		lookup.count = 1;
+
+		count1_obj = ast_hashtab_lookup(objhash, &lookup);
+		
+		if (count1_obj) {
+			/* there IS a count1 obj, so let's see which one we REALLY want */
+			if (*(t+1) == '=') {
+				/* start a new object! */
+				curr_obj = alloc_obj(un, ++count1_obj->last_count);
+				/* put it in the hashtable */
+				ast_hashtab_insert_safe(objhash, curr_obj);
+			} else {
+				if (count1_obj->last_count > 1) {
+					lookup.count = count1_obj->last_count;
+					curr_obj = ast_hashtab_lookup(objhash, &lookup);
+				} else {
+					curr_obj = count1_obj;
+				}
+				
+			}
+
+		} else {
+			/* NO obj at ALL? -- better make one! */
+			if (*(t+1) != '=') {
+				printf("BAD: object %x appears without previous allocation marker!\n");
+			}
+			curr_obj = count1_obj = alloc_obj(un, 1);
+			/* put it in the hashtable */
+			ast_hashtab_insert_safe(objhash, curr_obj);
+			
+		}
+		
+		if (*(t+1) == '+' || *(t+1) == '-' ) {
+			curr_obj->total_refcount += strtol(t+1, NULL, 10);
+		} else if (*(t+1) == '*') {
+			curr_obj->destroy_count++;
+		}
+		
+		add_to_hist(linebuffer, curr_obj);
+	}
+	fclose(ifile);
+	
+	/* traverse the objects and check for problems */
+	it = ast_hashtab_start_traversal(objhash);
+	while (curr_obj = ast_hashtab_next(it)) {
+		if (curr_obj->total_refcount != 0 || curr_obj->destroy_count != 1) {
+			struct rc_hist *h;
+			if (curr_obj->total_refcount != 0)
+				printf("Problem: net Refcount not zero for object %x\n", curr_obj->addr);
+			if (curr_obj->destroy_count > 1 )
+				printf("Problem: Object %x destroyed more than once!\n", curr_obj->addr);
+			printf("Object %x history:\n", curr_obj->addr);
+			for(h=curr_obj->hist;h;h=h->next)
+			{
+				printf("   %s", h->desc);
+				
+			}
+			printf("==============\n");
+		}
+	}
+	ast_hashtab_end_traversal(it);
+}
+
+
+/* stub routines to satisfy linking with asterisk subcomponents */
+
+int  ast_add_profile(const char *x, uint64_t scale)
+{
+	return 0;
+}
+
+int ast_loader_register(int (*updater)(void))
+{
+	return 1;
+}
+
+int ast_loader_unregister(int (*updater)(void))
+{
+	return 1;
+}
+void ast_module_register(const struct ast_module_info *x)
+{
+}
+
+void ast_module_unregister(const struct ast_module_info *x)
+{
+}
+
+
+void ast_register_file_version(const char *file, const char *version)
+{
+}
+
+void ast_unregister_file_version(const char *file)
+{
+
+}
+
+void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
+{
+	va_list vars;
+	va_start(vars,fmt);
+	printf("LOG: lev:%d file:%s  line:%d func: %s  ",
+		   level, file, line, function);
+	vprintf(fmt, vars);
+	fflush(stdout);
+	va_end(vars);
+}
+
+void ast_verbose(const char *fmt, ...)
+{
+        va_list vars;
+        va_start(vars,fmt);
+
+        printf("VERBOSE: ");
+        vprintf(fmt, vars);
+        fflush(stdout);
+        va_end(vars);
+}
+
+void ast_register_thread(char *name)
+{
+
+}
+
+void ast_unregister_thread(void *id)
+{
+}

Propchange: team/murf/bug11210/utils/refcounter.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/murf/bug11210/utils/refcounter.c
------------------------------------------------------------------------------
    svn:keywords = Author Id Date Revision

Propchange: team/murf/bug11210/utils/refcounter.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the asterisk-commits mailing list