Index: apps/app_queue.c
===================================================================
--- apps/app_queue.c	(revision 229742)
+++ apps/app_queue.c	(working copy)
@@ -454,8 +454,8 @@
 static AST_LIST_HEAD_STATIC(queues, call_queue);
 
 static int set_member_paused(const char *queuename, const char *interface, int paused);
-
 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan); 
+static void free_members(struct call_queue *q, int all);
 
 static void rr_dep_warning(void)
 {
@@ -512,6 +512,35 @@
 	return -1;
 }
 
+/*!
+ * \brief removes a call_queue from the list of call_queues
+ */
+static void remove_queue(struct call_queue *q)
+{
+	struct call_queue *cur = NULL;
+
+	AST_LIST_LOCK(&queues);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, cur, list) {
+		if (cur == q) {
+			AST_LIST_REMOVE_CURRENT(&queues, list);
+			ao2_ref(q, -1);
+			break;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+	AST_LIST_UNLOCK(&queues);
+}
+
+static void destroy_queue(void *obj)
+{
+	struct call_queue *q = obj;
+	ast_mutex_destroy(&q->lock);
+	if (q->members) {
+		free_members(q, 1);
+		ao2_ref(q->members, -1);
+	}
+}
+
 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
 {
@@ -527,6 +556,11 @@
 		q->head = new;
 	}
 	new->next = cur;
+
+	/* every queue_ent must have a reference to it's parent call_queue, this
+	 * reference does not go away until the end of the queue_ent's life, meaning
+	 * that even when the queue_ent leaves the call_queue this ref must remain. */
+	ao2_ref(q, +1);
 	new->parent = q;
 	new->pos = ++(*pos);
 	new->opos = *pos;
@@ -785,7 +819,7 @@
 {
 	struct call_queue *q;
 
-	if ((q = ast_calloc(1, sizeof(*q)))) {
+	if ((q = ao2_alloc(sizeof(*q), destroy_queue))) {
 		ast_mutex_init(&q->lock);
 		ast_copy_string(q->name, queuename, sizeof(q->name));
 	}
@@ -1187,14 +1221,6 @@
 	ao2_iterator_destroy(&mem_iter);
 }
 
-static void destroy_queue(struct call_queue *q)
-{
-	free_members(q, 1);
-	ast_mutex_destroy(&q->lock);
-	ao2_ref(q->members, -1);
-	free(q);
-}
-
 /*!\brief Reload a single queue via realtime.
    \return Return the queue, or NULL if it doesn't exist.
    \note Should be called with the global qlock locked. */
@@ -1244,9 +1270,8 @@
 			/* Delete if unused (else will be deleted when last caller leaves). */
 			if (!q->count) {
 				/* Delete. */
-				AST_LIST_REMOVE(&queues, q, list);
 				ast_mutex_unlock(&q->lock);
-				destroy_queue(q);
+				remove_queue(q);
 			} else
 				ast_mutex_unlock(&q->lock);
 		}
@@ -1721,10 +1746,7 @@
 
 	if (q->dead && !q->count) {	
 		/* It's dead and nobody is in it, so kill it */
-		AST_LIST_LOCK(&queues);
-		AST_LIST_REMOVE(&queues, q, list);
-		AST_LIST_UNLOCK(&queues);
-		destroy_queue(q);
+		remove_queue(q);
 	}
 }
 
@@ -3216,8 +3238,10 @@
 
 			}
 		}
+
+
 		/* Drop out of the queue at this point, to prepare for next caller */
-		leave_queue(qe);			
+		leave_queue(qe);
 		if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
 			if (option_debug)
 				ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
@@ -3972,7 +3996,7 @@
 		AST_APP_ARG(agi);
 	);
 	/* Our queue entry */
-	struct queue_ent qe;
+	struct queue_ent qe = { 0 };
 	
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n");
@@ -4213,6 +4237,12 @@
 		set_queue_result(chan, reason);
 		res = 0;
 	}
+	if (qe.parent) {
+		/* every queue_ent is given a reference to it's parent call_queue when it joins the queue.
+		 * This ref must be taken away right before the queue_ent is destroyed.  In this case
+		 * the queue_ent is about to be returned on the stack */
+		ao2_ref(qe.parent, -1);
+	}
 	ast_module_user_remove(lu);
 
 	return res;
@@ -4572,10 +4602,7 @@
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) {
 		if (q->dead) {
 			AST_LIST_REMOVE_CURRENT(&queues, list);
-			if (!q->count)
-				destroy_queue(q);
-			else
-				ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n");
+			ao2_ref(q, -1);
 		} else {
 			ast_mutex_lock(&q->lock);
 			mem_iter = ao2_iterator_init(q->members, 0);
