[asterisk-commits] irroot: branch irroot/distrotech-customers-1.8 r348047 - /team/irroot/distrot...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Dec 12 15:27:41 CST 2011


Author: irroot
Date: Mon Dec 12 15:27:37 2011
New Revision: 348047

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=348047
Log:
Merge changes from quack queue

Modified:
    team/irroot/distrotech-customers-1.8/apps/app_queue.c

Modified: team/irroot/distrotech-customers-1.8/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/irroot/distrotech-customers-1.8/apps/app_queue.c?view=diff&rev=348047&r1=348046&r2=348047
==============================================================================
--- team/irroot/distrotech-customers-1.8/apps/app_queue.c (original)
+++ team/irroot/distrotech-customers-1.8/apps/app_queue.c Mon Dec 12 15:27:37 2011
@@ -25,17 +25,18 @@
  * \arg Config in \ref Config_qu queues.conf
  *
  * \par Development notes
- * \note 2011-11-01: Made application more thread safe
+ * \note 2011-11-01: Reworked to seperate structures make more thread safe
  *		Distrotech PTY (LTD) (www.distrotech.co.za)
  *		Gregory Nietsky (irroot) <gregory at distrotech.co.za>
  *
  *		Split away from locking queues/queue to having locks per
- *		Queue/Member/Device.
+ *		Queue Data/Member/Device.
  *		Added device state struct to mange device states shared
  *		for multiple members sharing same device.
+ *		Added queue data struct to mange queue data.
  *
  *		Made all functions work with realtime/dynamic/static members.
- *		Added missing CLI/AMI functions for handling callinuse.
+ *		Added missing CLI/AMI functions for handling callinuse (ignorebusy).
  *
  * \note 2004-11-25: Persistent Dynamic Members added by:
  *             NetNation Communications (www.netnation.com)
@@ -117,25 +118,22 @@
  * \par Please read before modifying this file.
  * There are locks which are regularly used
  * throughout this file, the lock
- * for each individual queue, the individual member lock ,
+ * for each individual queue, queue data, the individual member lock ,
  * and the device state lock.
  * there are container locks for the queues list, the member
- * list on each queue and the devices container.
+ * list on each queue the devices container and rules container.
+ * in the queue data struct there is linked lists for the entries in queue.
  * Please be extra careful to always lock in the following order
  *
- * 1) queues container lock (ao2 functions that lock the container)
- * 2) queue lock
- * 3) queue member lock
- * 4) member lock
- * 5) devices container lock
- * 6) member device lock
+ * 1) container lock first
+ * 2) container element
+ *
+ * Never call a function on a container while a element is locked
+ *
  * This order has sort of "evolved" over the lifetime of this
  * application, but it is now in place this way, so please adhere
  * to this order!
  *
- * the only elements that do not require a read lock (ie will not change)
- * the queue name and members container, the member interface and
- * device state_interface as they are never altered after been linked.
  */
 
 /*** DOCUMENTATION
@@ -270,7 +268,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -312,7 +309,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -349,7 +345,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -393,7 +388,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -434,7 +428,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -465,7 +458,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -519,7 +511,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -575,34 +566,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
-			<ref type="function">QUEUE_EXISTS</ref>
-			<ref type="function">QUEUE_WAITING_COUNT</ref>
-			<ref type="function">QUEUE_MEMBER_LIST</ref>
-			<ref type="function">QUEUE_MEMBER_PENALTY</ref>
-		</see-also>
-	</function>
-	<function name="QUEUE_MEMBER_COUNT" language="en_US">
-		<synopsis>
-			Count number of members answering a queue.
-		</synopsis>
-		<syntax>
-			<parameter name="queuename" required="true" />
-		</syntax>
-		<description>
-			<para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
-			<warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
-		</description>
-		<see-also>
-			<ref type="application">Queue</ref>
-			<ref type="application">QueueLog</ref>
-			<ref type="application">AddQueueMember</ref>
-			<ref type="application">RemoveQueueMember</ref>
-			<ref type="application">PauseQueueMember</ref>
-			<ref type="application">UnpauseQueueMember</ref>
-			<ref type="function">QUEUE_VARIABLES</ref>
-			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -949,22 +912,20 @@
                                                      The default value of 15 provides backwards compatibility */
 #define MAX_QUEUE_BUCKETS 53
 
-#define	RES_OKAY	0		/*!< Action completed */
-#define	RES_EXISTS	(-1)		/*!< Entry already exists */
-#define	RES_OUTOFMEMORY	(-2)		/*!< Out of memory */
-#define	RES_NOSUCHQUEUE	(-3)		/*!< No such queue */
-#define RES_NOT_DYNAMIC (-4)		/*!< Member is not dynamic */
-#define RES_ERROR	(-5)		/*!< Member is mis configured */
+enum member_result {
+	RES_OKAY = 0,			/*!< Action completed */
+	RES_EXISTS = -1,		/*!< Entry already exists */
+	RES_OUTOFMEMORY	= -2,		/*!< Out of memory */
+	RES_NOSUCHQUEUE	= -3,		/*!< No such queue */
+	RES_NOT_DYNAMIC = -4,		/*!< Member is not dynamic */
+	RES_ERROR = -5,			/*!< Member is mis configured */
+};
+
 static char *app = "Queue";
-
 static char *app_aqm = "AddQueueMember" ;
-
 static char *app_rqm = "RemoveQueueMember" ;
-
 static char *app_pqm = "PauseQueueMember" ;
-
 static char *app_upqm = "UnpauseQueueMember" ;
-
 static char *app_ql = "QueueLog" ;
 
 /*! \brief Persistent Members astdb family */
@@ -1037,14 +998,15 @@
 
 struct callattempt {
 	struct ast_channel *chan;                  /*! Channel called */
-	int stillgoing;                            /*! This attempt is valid and active */
 	int metric;                                /*! Metric calculated according to strategy */
 	struct member *member;                     /*! Member assosiated with this attempt */
 	struct ast_party_connected_line connected; /*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
+	unsigned int stillgoing:1;                 /*! This attempt is valid and active */
 	unsigned int reserved:1;                   /*! Is this attempt been attempted*/
 	unsigned int active:1;                     /*! Is this attempt active in a call*/
 	unsigned int pending_connected_update:1;   /*! TRUE if caller id is not available for connected line*/
 	unsigned int dial_callerid_absent:1;       /*! TRUE if caller id is not available for connected line */
+	unsigned int watching:1;                   /*! TRUE if callattempt is been watched */
 	struct ast_aoc_decoded *aoc_s_rate_list;
 };
 
@@ -1188,7 +1150,6 @@
 	int strategy:4;
 	unsigned int maskmemberstatus:1;
 	unsigned int realtime:1;
-	unsigned int found:1;
 	unsigned int relativeperiodicannounce:1;
 	unsigned int autopausebusy:1;
 	unsigned int autopauseunavail:1;
@@ -1249,7 +1210,6 @@
 static char *queue_refshow(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 static struct member *interface_exists(struct call_queue *q, const char *interface);
 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
-
 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
 
 /*! \brief sets the QUEUESTATUS channel variable */
@@ -1331,9 +1291,13 @@
 static int queue_cmp_cb(void *obj, void *arg, int flags)
 {
 	const struct call_queue *q = obj, *q2 = arg;
-	const char *name = (flags & OBJ_POINTER) ? q2->name : arg;
-
-	return !strcasecmp(q->name, name) ? CMP_MATCH | CMP_STOP : 0;
+	const char *name = (arg && (flags & OBJ_POINTER)) ? q2->name : arg;
+
+	if (!ast_strlen_zero(name) && !strcasecmp(q->name, name)) {
+		return CMP_MATCH | CMP_STOP;
+	} else {
+		return 0;
+	}
 }
 
 /*!
@@ -1356,9 +1320,14 @@
 {
 	const struct queue_data *d = obj, *d2 = arg;
 	const char *name = arg;
-	int qhash = (flags & OBJ_POINTER) ? d2->qhash : ast_str_case_hash(name);
-
-	return  (d->qhash == qhash) ? CMP_MATCH | CMP_STOP : 0;
+	int nhash = (ast_strlen_zero(name)) ? 0 : ast_str_case_hash(name);
+	int qhash = (arg && (flags & OBJ_POINTER)) ? d2->qhash : nhash;
+
+	if (qhash && (d->qhash == qhash)) {
+		return CMP_MATCH | CMP_STOP;
+	} else {
+		return 0;
+	}
 }
 
 /*! \brief Set channel variables of queue */
@@ -1416,7 +1385,6 @@
 			/* if im active and may not place calls when INUSE im actually BUSY */
 			if ((s->reserved || s->active) && !m->callinuse) {
 				ret = AST_DEVICE_BUSY;
-				break;
 			}
 			break;
 		case AST_DEVICE_NOT_INUSE:
@@ -1444,8 +1412,6 @@
 	struct member *member;
 	struct ao2_iterator mem_iter;
 	struct call_queue *q = qe->parent;
-	int max_penalty = qe->max_penalty;
-	int min_penalty = qe->min_penalty;
 	enum empty_conditions conditions;
 
 	conditions = (join) ? q->joinempty : q->leavewhenempty;
@@ -1457,9 +1423,9 @@
 	mem_iter = ao2_iterator_init(q->data->members, 0);
 	while((member = ao2_iterator_next(&mem_iter))) {
 		ao2_lock(member);
-		if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) {
+		if ((qe->max_penalty && (member->penalty > qe->max_penalty)) || (qe->min_penalty && (member->penalty < qe->min_penalty))) {
 			if (conditions & QUEUE_EMPTY_PENALTY) {
-				ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
+				ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, qe->min_penalty, qe->max_penalty);
 				ao2_unlock(member);
 				ao2_ref(member, -1);
 				continue;
@@ -1778,9 +1744,13 @@
 {
 	const struct member *mem1 = obj1;
 	const struct member *mem2 = obj2;
-	const char *arg = (flags & OBJ_POINTER) ? mem2->interface : obj2;
-
-	return strcasecmp(mem1->interface, arg) ? 0 : CMP_MATCH | CMP_STOP;
+	const char *iface = (obj2 && (flags & OBJ_POINTER)) ? mem2->interface : obj2;
+
+	if (!ast_strlen_zero(iface) && !strcasecmp(mem1->interface, iface)) {
+		return CMP_MATCH | CMP_STOP;
+	} else {
+		return 0;
+	}
 }
 
 /*!
@@ -1790,9 +1760,9 @@
 {
 	const struct member *mem1 = obj1;
 	const struct member *mem2 = arg;
-	const char *uniqueid = (flags & OBJ_POINTER) ? mem2->rt_uniqueid : arg;
-
-	if (mem1->realtime && !mem1->dead &&
+	const char *uniqueid = (arg && (flags & OBJ_POINTER)) ? mem2->rt_uniqueid : arg;
+
+	if (mem1->realtime && !mem1->dead && !ast_strlen_zero(uniqueid) &&
 	    !strcasecmp(mem1->rt_uniqueid, uniqueid)) {
 		return CMP_MATCH | CMP_STOP;
 	}
@@ -1823,13 +1793,13 @@
 	const struct call_queue *q = data;
 
 	if (m->realtime && m->dead) {
-		ao2_lock(m);
-		if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
+		if (!log_membername_as_agent) {
 			ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
 		} else {
+			ao2_lock(m);
 			ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
-		}
-		ao2_unlock(m);
+			ao2_unlock(m);
+		}
 		return CMP_MATCH;
 	}
 	return 0;
@@ -1868,9 +1838,13 @@
 {
 	const struct mem_state *d = obj;
 	const struct mem_state *d2 = arg;
-	const char *iface = (flags & OBJ_POINTER) ? d2->state_interface : arg;
-
-	return !strcasecmp(d->state_interface, iface) ? CMP_MATCH | CMP_STOP : 0;
+	const char *iface = (arg && (flags & OBJ_POINTER)) ? d2->state_interface : arg;
+
+	if (!ast_strlen_zero(iface) && !strcasecmp(d->state_interface, iface)) {
+		return CMP_MATCH | CMP_STOP;
+	} else {
+		return 0;
+	}
 }
 
 /*!
@@ -1921,9 +1895,13 @@
 {
 	const struct rule_list *rl = obj;
 	const struct rule_list *rl2 = arg;
-	const char *name = (flags & OBJ_POINTER) ? rl2->name : arg;
-
-	return !strcasecmp(rl->name, name) ? CMP_MATCH | CMP_STOP : 0;
+	const char *name = (arg && (flags & OBJ_POINTER)) ? rl2->name : arg;
+
+	if (!ast_strlen_zero(name) && !strcasecmp(rl->name, name)) {
+		return CMP_MATCH | CMP_STOP;
+	} else {
+		return 0;
+	}
 }
 
 /*!
@@ -1938,6 +1916,21 @@
 	return ast_str_case_hash(interface);
 }
 
+/*!
+ * \brief ao2 callback to find callattempt been watched
+ */
+static int callattempt_watched_cb(void *obj, void *arg, const int flags)
+{
+	const struct callattempt *c = obj;
+	const struct callattempt *c1 = arg;
+	const struct member *mem = (arg) ? c1->member : NULL;
+	const char *interface = (arg && (flags & OBJ_POINTER)) ? mem->interface : arg;
+
+	if (!arg || ast_strlen_zero(interface) || !strcasecmp(interface, c->member->interface)) {
+		return (c->stillgoing && c->chan) ? CMP_MATCH : 0;
+	}
+	return 0;
+}
 
 /*!
  * \brief ao2 callback to obtain the callattempt with best metric
@@ -2001,7 +1994,6 @@
 	q->autopause = QUEUE_AUTOPAUSE_OFF;
 	q->timeoutpriority = TIMEOUT_PRIORITY_APP;
 	q->autopausedelay = 0;
-	q->found = 1;
 
 	ast_string_field_set(q, sound_next, "queue-youarenext");
 	ast_string_field_set(q, sound_thereare, "queue-thereare");
@@ -2375,6 +2367,11 @@
 	char *rt_uniqueid = NULL, *st_dev = NULL;
 	int dead = 0;
 
+	if (ast_strlen_zero(interface)) {
+		ast_log(AST_LOG_ERROR, "Interface was not specified !!\n");
+		return RES_ERROR;
+	}
+
 	if (!(m = ao2_find(q->data->members, (char *)interface, 0))) {
 		if (!(m = ao2_alloc(sizeof(*m), remove_queue_member))) {
 			return RES_OUTOFMEMORY;
@@ -2472,7 +2469,7 @@
 		}
 	}
 
-	if (!dead && !m->device && (!(m->device = create_member_state(st_dev)))) {
+	if (!dead && !m->device && !(m->device = create_member_state(st_dev))) {
 		dead = 1;
 	}
 
@@ -2481,7 +2478,7 @@
 	}
 
 	/*check the uniqueness of the RT uniqueid */
-	if (link && (memtype & QUEUE_ADD_MEMBER_REALTIME) && !dead) {
+	if (!dead && link && (memtype & QUEUE_ADD_MEMBER_REALTIME)) {
 		if (ast_strlen_zero(rt_uniqueid)) {
 			ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(m->membername, interface));
 			dead = 1;
@@ -2502,10 +2499,10 @@
 		int status = get_device_status(m);
 
 		/* i have just been born */
-		if ((ast_strlen_zero(m->membername) || !log_membername_as_agent)) {
-			ast_queue_log(q->name, source, m->interface, "ADDMEMBER", "%s", "");
+		if (!log_membername_as_agent) {
+			ast_queue_log(q->name, source, m->interface, "ADDMEMBER", "%s", m->paused ? "PAUSED" : "");
 		} else {
-			ast_queue_log(q->name, source, m->membername, "ADDMEMBER", "%s", "");
+			ast_queue_log(q->name, source, m->membername, "ADDMEMBER", "%s", m->paused ? "PAUSED" : "");
 		}
 		manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
 			"Queue: %s\r\n"
@@ -2532,7 +2529,7 @@
 		}
 		if (!link) {
 			/* thee was a config error remove this member from container now*/
-			if ((ast_strlen_zero(m->membername) || !log_membername_as_agent)) {
+			if (!log_membername_as_agent) {
 				ast_queue_log(q->name, source, m->interface, "REMOVEMEMBER", "%s", "");
 			} else {
 				ast_queue_log(q->name, source, m->membername, "REMOVEMEMBER", "%s", "");
@@ -2646,83 +2643,41 @@
 
 	ast_string_field_set(q, name, queuename);
 	q->realtime = rt;
-	q->weight = 0;
-	q->found = 0;
+
+	/* Ensure defaults for all parameters not set explicitly. */
+	init_queue(q);
 
 	return q;
 }
 
-/*!
- * \brief Reload a single queue via realtime.
+/*
  *
- * Check for statically defined queue first, check if deleted RT queue,
- * check for new RT queue, if queue vars are not defined init them with defaults.
- * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
- * \retval the queue,
- * \retval NULL if it doesn't exist.
-*/
-static struct call_queue *load_realtime_queue(const char *queuename, struct ast_flags *mask)
-{
+ */
+static struct call_queue *config_call_queue(struct call_queue *oldq, struct ast_variable *queue_vars, const char *queuename, int reload_members)
+{
+	int prev_weight = 0;
 	struct ast_variable *v;
+	char *tmp;
 	const char *tmp_name;
-	char *tmp;
 	char tmpbuf[64];	/* Must be longer than the longest queue param name. */
-	int prev_weight = 0;
-	struct ast_variable *queue_vars;
-	struct call_queue *q, *oldq;
-	int found;
-	int reload_queue = (mask) ? ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS) : 0;
-	int reload_members = (mask) ? ast_test_flag(mask, QUEUE_RELOAD_MEMBER) : 0;
-	int reload_realtime = (mask) ? ast_test_flag(mask, QUEUE_RELOAD_REALTIME) : 0;
-
-	if ((q = ao2_t_find(queues, (char *)queuename, 0, "Look for queue in memory first")) &&
-	    (!q->realtime || !reload_queue)) {
-		if (reload_members) {
-			rt_load_member_config(q);
-		}
-		return q;
-	}
-
-	if (!reload_realtime && q && !ast_tvzero(q->reload) && ast_tvdiff_sec(ast_tvnow(), q->reload)) {
-		ast_log(AST_LOG_WARNING, "Not reloading queue for next %ld Seconds\n", (long)ast_tvdiff_sec(q->reload, ast_tvnow()));
-		return q;
-	}
-
-	/*! \note The queue is recreated and the existing queue will not change and any
-		users holding a ref to the queue will have no changes applied. */
-
-	/* Check if queue is defined in realtime. */
-	if (!(queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL))) {
-		/* Delete queue from in-core list if it has been deleted in realtime. */
-		if (q) {
-			/*! \note Hmm, can't seem to distinguish a DB failure from a not
-			   found condition... So we might delete an in-core queue
-			   in case of DB failure. */
-			ast_debug(1, "Queue %s not found in realtime.\n", queuename);
-			ao2_t_unlink(queues, q, "Unused; removing from container");
-			ao2_t_ref(q, -1, "Queue is dead; can't return it");
-		}
-		return NULL;
-	}
+	struct call_queue *q;
 
 	/* Create a new queue if an in-core entry does not exist yet. */
-	if (!q && (!(q = alloc_queue(queuename, 1)))) {
+	if (!oldq && !(q = alloc_queue(queuename, 1))) {
 		ast_variables_destroy(queue_vars);
 		return NULL;
-	} else {
-		found = q->found;
-		prev_weight = q->weight ? 1 : 0;
-
-		oldq = q;
+	} else if (oldq) {
+		prev_weight = oldq->weight ? 1 : 0;
+		/*! \note The queue is recreated and the existing queue will not change and any
+		 *users holding a ref to the queue will have no changes applied.
+		 */
 		if (!(q = alloc_queue(queuename, 1))) {
 			/* i could not allocate new structure return the old one*/
 			ast_log(AST_LOG_WARNING, "Failed to assign new queue object returning unchanged object\n");
 			ast_variables_destroy(queue_vars);
-			return oldq;
-		}
-	}
-
-	init_queue(q);		/* Ensure defaults for all parameters not set explicitly. */
+			return NULL;
+		}
+	}
 
 	memset(tmpbuf, 0, sizeof(tmpbuf));
 	for (v = queue_vars; v; v = v->next) {
@@ -2752,7 +2707,6 @@
 	}
 
 	/* update the use_weight value if the queue's has gained or lost a weight */
-	/* Other cases will end up with the proper value for use_weight */
 	if (!q->weight && prev_weight) {
 		ast_atomic_fetchadd_int(&use_weight, -1);
 	} else if (q->weight && !prev_weight) {
@@ -2760,7 +2714,7 @@
 	}
 
 	/* add persistent members to new queue*/
-	if (!found && queue_persistent_members) {
+	if (!oldq && queue_persistent_members) {
 		pm_load_member_config(q);
 	}
 
@@ -2778,7 +2732,61 @@
 	} else {
 		ao2_link(queues, q);
 	}
+
 	return q;
+}
+
+/*!
+ * \brief Reload a single queue via realtime.
+ *
+ * Check for statically defined queue first, check if deleted RT queue,
+ * check for new RT queue, if queue vars are not defined init them with defaults.
+ * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
+ * \retval the queue,
+ * \retval NULL if it doesn't exist.
+*/
+static struct call_queue *load_realtime_queue(const char *queuename, struct ast_flags *mask)
+{
+	struct ast_variable *queue_vars;
+	struct call_queue *oldq;
+
+	int reload_queue = (mask) ? ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS) : 0;
+	int reload_members = (mask) ? ast_test_flag(mask, QUEUE_RELOAD_MEMBER) : 0;
+	int reload_realtime = (mask) ? ast_test_flag(mask, QUEUE_RELOAD_REALTIME) : 0;
+
+	/* return if im not realtime or not reloading the queue possibly checking members */
+	if ((oldq = ao2_t_find(queues, (char *)queuename, 0, "Look for queue in memory first")) &&
+	    (!oldq->realtime || !(reload_queue || reload_realtime))) {
+		if (reload_members) {
+			rt_load_member_config(oldq);
+		}
+		return oldq;
+	} else if (!oldq && !(reload_queue || reload_realtime)) {
+		ast_debug(1, "Not loading queue %s at this time\n",queuename);
+		return NULL;
+	}
+
+	/* if im reloading realtime (CLI/AMI) i ignore cache timer */
+	if (!reload_realtime && oldq && !ast_tvzero(oldq->reload) &&
+	    (ast_tvcmp(ast_tvnow(), oldq->reload) < 0)) {
+		ast_debug(1, "Not reloading queue %s for next %ld Seconds\n", oldq->name, (long)ast_tvdiff_sec(oldq->reload, ast_tvnow()));
+		return oldq;
+	}
+
+	/* Check if queue is defined in realtime if im reloading */
+	if (!(queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL))) {
+		/* Delete queue from in-core list if it has been deleted in realtime.
+		 * ! \note On DB failure the queue will be removed as i cant distinguish a DB failure
+		 */
+		if (oldq) {
+			ast_debug(1, "Queue %s not found in realtime.\n", queuename);
+			ao2_t_unlink(queues, oldq, "Unused; removing from container");
+			ao2_t_ref(oldq, -1, "Queue is dead; can't return it");
+		}
+		return NULL;
+	}
+
+	return config_call_queue(oldq, queue_vars, queuename, reload_members);
 }
 
 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
@@ -2798,18 +2806,23 @@
 
 static void load_all_realtime_queues(struct ast_flags *mask)
 {
-	char *queuename;
+	const char *queuename;
 	struct ast_config *cfg;
 	struct call_queue *queue;
+	struct ast_category *cat;
+	struct ast_variable *var;
 
 	/* load realtime queues. */
 	if ((cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL))) {
 		for (queuename = ast_category_browse(cfg, NULL);
 				!ast_strlen_zero(queuename);
 				queuename = ast_category_browse(cfg, queuename)) {
-			if ((queue = load_realtime_queue(queuename, mask))) {
-				ao2_ref(queue, -1);
-			}
+			cat = ast_category_get(cfg, queuename);
+			var = ast_category_detach_variables(cat);
+			queue = ao2_find(queues, (char *)queuename, 0);
+			queue = config_call_queue(queue, var, queuename, 1);
+			ao2_ref(queue, -1);
+
 		}
 		ast_config_destroy(cfg);
 	}
@@ -2817,36 +2830,34 @@
 
 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
 {
-	struct call_queue *q;
 	struct queue_ent *cur;
 	int res = -1;
 	int pos = 0;
 	int inserted = 0;
 	struct ast_flags qflags = {QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER};
 
-	if (!(q = load_realtime_queue(queuename, &qflags))) {
+	/*obtain a ref for the queue reload realtime settings/members*/
+	if (!(qe->parent = load_realtime_queue(queuename, &qflags))) {
 		return res;
 	}
 
-	qe->parent = q;
-
 	/* This is our one */
-	if ((get_member_status(qe, 1))) {
+	if (get_member_status(qe, 1)) {
 		*reason = QUEUE_JOINEMPTY;
-		ao2_t_ref(q, -1, "Done with realtime queue");
+		ao2_t_ref(qe->parent, -1, "Done with realtime queue");
 		return res;
 	}
 
-	ao2_lock(q->data);
-	if ((*reason == QUEUE_UNKNOWN && q->maxlen && (q->data->count >= q->maxlen)) ||
+	ao2_lock(qe->parent->data);
+	if ((*reason == QUEUE_UNKNOWN && qe->parent->maxlen && (qe->parent->data->count >= qe->parent->maxlen)) ||
 	    (*reason != QUEUE_UNKNOWN)) {
-		ao2_unlock(q->data);
+		ao2_unlock(qe->parent->data);
 		*reason = QUEUE_FULL;
-		ao2_t_ref(q, -1, "Done with realtime queue");
+		ao2_t_ref(qe->parent, -1, "Done with realtime queue");
 
 		return res;
 	}
-	ao2_unlock(q->data);
+	ao2_unlock(qe->parent->data);
 
 
 	/* There's space for us, put us at the right position inside
@@ -2854,12 +2865,12 @@
 	 * Take into account the priority of the calling user */
 	inserted = 0;
 
-	AST_LIST_LOCK(q->data->head);
-	AST_LIST_TRAVERSE_SAFE_BEGIN(q->data->head, cur, next) {
+	AST_LIST_LOCK(qe->parent->data->head);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(qe->parent->data->head, cur, next) {
 		/* We have higher priority than the current user, enter
 		 * before him, after all the other users with priority
 		 * higher or equal to our priority. */
-		if ((!inserted) && qe && (qe->prio > cur->prio)) {
+		if (!inserted && qe && (qe->prio > cur->prio)) {
 			AST_LIST_INSERT_BEFORE_CURRENT(qe, next);
 			insert_entry(qe, &pos);
 			inserted = 1;
@@ -2882,20 +2893,20 @@
 
 	/* No luck, join at the end of the queue */
 	if (!inserted && qe) {
-		AST_LIST_INSERT_TAIL(q->data->head, qe, next);
+		AST_LIST_INSERT_TAIL(qe->parent->data->head, qe, next);
 		insert_entry(qe, &pos);
 	}
-	AST_LIST_UNLOCK(q->data->head);
+	AST_LIST_UNLOCK(qe->parent->data->head);
 
 	/* pass a ref to the queue rules or this queue*/
 	qe->pr = NULL;
-	if ((qe->rules = ao2_find(rules, (char *)q->defaultrule, 0))) {
+	if ((qe->rules = ao2_find(rules, (char *)qe->parent->defaultrule, 0))) {
 		int time = 0;
 		ao2_callback_data(qe->rules->rules, OBJ_NODATA | OBJ_MULTIPLE, get_best_rule_cb, &time, &qe->pr);
 	}
 
 	res = 0;
-	ao2_lock(q->data);
+	ao2_lock(qe->parent->data);
 	ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
 		"Channel: %s\r\n"
 		"CallerIDNum: %s\r\n"
@@ -2911,9 +2922,9 @@
 		S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
 		S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
 		S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
-		q->name, qe->pos, q->data->count, qe->chan->uniqueid );
-	ao2_unlock(q->data);
-	ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
+		qe->parent->name, qe->pos, qe->parent->data->count, qe->chan->uniqueid );
+	ao2_unlock(qe->parent->data);
+	ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", qe->parent->name, qe->chan->name, qe->pos );
 
 	return res;
 }
@@ -3306,43 +3317,35 @@
 {
 	struct call_queue *q;
 	struct member *mem;
-	int found = 0;
 	int count;
-	int rcount;
+	int res = 0;
 	struct ao2_iterator queue_iter;
-
-	ao2_lock(rq->data);
-	rcount = rq->data->count;
-	ao2_unlock(rq->data);
 
 	queue_iter = ao2_iterator_init(queues, 0);
 	while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
-		if (q == rq) { /* don't check myself, could deadlock */
-			ao2_t_ref(q, -1, "Done with iterator");
+		/* don't check myself or queues with  lower weight*/
+		if ((q == rq) || (q->weight <= rq->weight)) {
+			ao2_ref(q, -1);
 			continue;
 		}
-
-		if (count && (mem = interface_exists(q, interface))) {
-			ao2_lock(q->data);
-			count = q->data->count;
-			ao2_unlock(q->data);
-
-			ao2_lock(mem);
-			ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
-			if (q->weight > rq->weight && count >= num_available_members(q)) {
-				ast_debug(1, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, count, rq->name, rq->weight, rcount);
-				found = 1;
-			}
-			ao2_unlock(mem);
+		ao2_lock(q->data);
+		count = q->data->count;
+		ao2_unlock(q->data);
+		if (count && (mem = interface_exists(q, interface)) &&
+		    (count >= num_available_members(q))) {
 			ao2_ref(mem, -1);
+			ast_debug(1, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d)\n",
+					q->name, q->weight, count, rq->name, rq->weight);
+			ao2_ref(q, -1);
+			res = 1;
+			break;
+		} else if (mem) {
+			ao2_ref(mem, -1);
 		}
 		ao2_ref(q, -1);
-		if (found) {
-			break;
-		}
 	}
 	ao2_iterator_destroy(&queue_iter);
-	return found;
+	return res;
 }
 
 /*! \brief common hangup actions */
@@ -3391,15 +3394,15 @@
 	return vars;
 }
 
-/*! 
+/*!
  * \brief Part 2 of ring_one
  *
  * Does error checking before attempting to request a channel and call a member.
  * This function is only called from ring_one().
  * Failure can occur if:
  * - Priority by another queue
+ * - Member is paused
  * - Wrapup time not expired
- * - Member is paused
  * - Member on call / or is not available for a call
  * - Channel cannot be created by driver
  * - Channel cannot be called by driver
@@ -3414,7 +3417,6 @@
 	char tech[256];
 	char *location;
 	const char *macrocontext, *macroexten;
-	struct mem_state *s;
 	int dstat;
 
 	/* we cannot take this call there is a more urgent call we qualify for */
@@ -3429,8 +3431,7 @@
 	}
 
 	ao2_lock(tmp->member);
-	s = tmp->member->device;
-
+	/* im paused i cannot take this call */
 	if (tmp->member->paused) {
 		ao2_unlock(tmp->member);
 		ast_debug(1, "%s paused, can't receive call\n", tmp->member->interface);
@@ -3472,6 +3473,7 @@
 
 	/* mark device and call entry reserved */
 	if (!tmp->reserved) {
+		struct mem_state *s = tmp->member->device;
 		ao2_lock(s);
 		s->reserved++;
 		ao2_unlock(s);
@@ -3487,17 +3489,16 @@
 	}
 
 	/* Request the peer */
-	tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status);
-	if (!tmp->chan) {			/* If we can't, just go on to the next call */
+	if (!(tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status))) {
 		if (qe->chan->cdr) {
 			ast_cdr_busy(qe->chan->cdr);
 		}
 		tmp->stillgoing = 0;
 
 		set_queue_member_status(tmp->member);
-		ao2_lock(qe->parent->data->members);
+		ao2_lock(qe->parent->data);
 		qe->parent->data->rrpos++;
-		ao2_unlock(qe->parent->data->members);
+		ao2_unlock(qe->parent->data);
 		qe->linpos++;
 
 		(*busies)++;
@@ -3837,11 +3838,9 @@
 	ao2_unlock(call->member);
 
 	if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) {
-		if (qe->parent->autopausedelay > 0) {
-			if (!ast_tvzero(call->member->lastcall) &&
-			    (ast_tvdiff_sec(ast_tvnow(), call->member->lastcall) < qe->parent->autopausedelay)) {
-				return;
-			}
+		if ((qe->parent->autopausedelay > 0) && !ast_tvzero(call->member->lastcall) &&
+		    (ast_tvdiff_sec(ast_tvnow(), call->member->lastcall) < qe->parent->autopausedelay)) {
+			return;
 		}
 		if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
 			ao2_lock(call->member);
@@ -3897,8 +3896,7 @@
 	struct ast_channel *in = qe->chan;
 	long starttime = 0;
 	long endtime = 0;
-	struct ao2_iterator aiter;
-	struct ao2_container *calls;
+	struct ao2_iterator aiter, *calls;
 #ifdef HAVE_EPOLL
 	struct callattempt *epollo;
 #endif
@@ -3923,8 +3921,6 @@
 	ao2_iterator_destroy(&aiter);
 #endif
 
-	calls = ao2_container_alloc(MAX_QUEUE_BUCKETS, callattempt_hash_fn, NULL);
-
 	while (*to && !peer) {
 		int numlines, retry, pos = 1;
 		struct ast_channel *watchers[AST_MAX_WATCHERS];
@@ -3936,13 +3932,9 @@
 			while ((o = ao2_iterator_next(&aiter))) {
 				if (o->stillgoing) {	/* Keep track of important channels */
 					stillgoing = 1;
-					if (o->chan) {
-						if (pos < AST_MAX_WATCHERS) {
-							watchers[pos++] = o->chan;
-						}
-						if (!retry) {
-							ao2_link(calls, o);
-						}
+					if (o->chan && !o->watching && (pos < AST_MAX_WATCHERS)) {
+						watchers[pos++] = o->chan;
+						o->watching = 1;
 					}
 				}
 				numlines++;
@@ -3965,8 +3957,6 @@
 				ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
 			}
 			*to = 0;
-			ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-			ao2_ref(calls, -1);
 			return NULL;
 		}
 
@@ -3974,18 +3964,27 @@
 		winner = ast_waitfor_n(watchers, pos, to);
 
 		/* Service all of the outgoing channels */
-		aiter = ao2_iterator_init(calls, 0);
-		while ((o = ao2_iterator_next(&aiter))) {
+		calls = ao2_find(qe->attempts, NULL, OBJ_MULTIPLE);
+		while (calls && (o = ao2_iterator_next(calls))) {
 			/* We go with a static buffer here instead of using ast_strdupa. Using
 			 * ast_strdupa in a loop like this one can cause a stack overflow
 			 */
 			char ochan_name[AST_CHANNEL_NAME];
+
+			/* i need to be re added to the watchers */
+			if (!o->watching) {
+				ao2_ref(o, -1);
+				continue;
+			} else {
+				o->watching = 0;
+			}
+
 			if (o->chan) {
 				ast_channel_lock(o->chan);
 				ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name));
 				ast_channel_unlock(o->chan);
 			}
-			if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
+			if (o->stillgoing && o->chan &&  (o->chan->_state == AST_STATE_UP)) {
 				if (!peer) {
 					ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
 					if (update_connectedline) {
@@ -4058,7 +4057,6 @@
 						struct ast_party_redirecting redirecting;
 
 						ast_channel_lock_both(o->chan, in);
-
 						ast_channel_inherit_variables(in, o->chan);
 						ast_channel_datastore_inherit(in, o->chan);
 
@@ -4266,7 +4264,9 @@
 			}
 			ao2_ref(o, -1);
 		}
-		ao2_iterator_destroy(&aiter);
+		if (calls) {
+			ao2_iterator_destroy(calls);
+		}
 
 		/* If we received an event from the caller, deal with it. */
 		if (winner == in) {
@@ -4280,8 +4280,6 @@
 					}
 					ast_frfree(f);
 				}
-				ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-				ao2_ref(calls, -1);
 				if (peer) {
 					ao2_ref(peer, -1);
 				}
@@ -4291,8 +4289,6 @@
 				ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
 				*to = 0;
 				ast_frfree(f);
-				ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-				ao2_ref(calls, -1);
 				if (peer) {
 					ao2_ref(peer, -1);
 				}
@@ -4303,8 +4299,6 @@
 				*to = 0;
 				*digit = f->subclass.integer;
 				ast_frfree(f);
-				ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-				ao2_ref(calls, -1);
 				if (peer) {
 					ao2_ref(peer, -1);
 				}
@@ -4313,17 +4307,16 @@
 			ast_frfree(f);
 		}
 		if (!*to) {
-			aiter = ao2_iterator_init(calls, AO2_ITERATOR_UNLINK);
-			while ((o = ao2_iterator_next(&aiter))) {
+			calls = ao2_find(qe->attempts, NULL, OBJ_MULTIPLE);
+			while (calls && (o = ao2_iterator_next(calls))) {
 				rna(orig, qe, o, 1);
 				ao2_ref(o, -1);
 			}
-			ao2_iterator_destroy(&aiter);
-		}
-
-		ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-	}
-	ao2_ref(calls, -1);
+			if (calls) {
+				ao2_iterator_destroy(calls);
+			}
+		}
+	}
 
 #ifdef HAVE_EPOLL
 	aiter = ao2_iterator_init(qe->attempts, 0);
@@ -4445,7 +4438,7 @@
 			break;
 		}
 
-		if ((get_member_status(qe, 0))) {
+		if (get_member_status(qe, 0)) {
 			*reason = QUEUE_LEAVEEMPTY;
 			ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)ast_tvdiff_sec(ast_tvnow(), qe->start));
 			leave_queue(qe);
@@ -4508,7 +4501,7 @@
 	int oldtalktime;
 
 	struct member *mem;
-	struct call_queue *qtmp;
+	struct queue_data *qtmp;
 	struct ao2_iterator queue_iter;
 
 	ao2_lock(q->data);
@@ -4522,9 +4515,9 @@
 	ao2_unlock(q->data);
 
 	if (shared_lastcall) {
-		queue_iter = ao2_iterator_init(queues, 0);
+		queue_iter = ao2_iterator_init(qdata, 0);
 		while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
-			if ((mem = ao2_find(qtmp->data->members, member, OBJ_POINTER))) {
+			if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
 				ao2_lock(mem);
 				mem->lastcall = ast_tvnow();
 				mem->calls++;
@@ -4635,8 +4628,9 @@
 		return NULL;
 	}
 
-	tmp->stillgoing = -1;
-	tmp->member = mem;/* Place the reference for cur into callattempt. */
+	tmp->stillgoing = 1;
+	tmp->watching = 0;
+	tmp->member = mem;/* Place the reference for mem into callattempt. */
 	tmp->dial_callerid_absent = 0;
 	tmp->pending_connected_update =0;
 	tmp->metric = metric;
@@ -4818,7 +4812,6 @@
  *    iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
  *    member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
  *    during each iteration, we calculate a metric to determine which members should be rung when.
- *
  * 3. Call ring_one to place a call to the appropriate member(s)
  * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
  * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
@@ -5685,7 +5678,6 @@
 	struct member *mem = NULL;
 	struct ast_config *mcfg;
 	const char *newm = NULL;
-	int found = 0;
 
 	if (q && !(mem = ao2_find(q->data->members, (char *)interface, 0))) {
 		/* if no member is found in core lets load this member from realtime */
@@ -5695,12 +5687,9 @@
 		}
 		while ((newm = ast_category_browse(mcfg, newm))) {
 			handle_member_record(q, newm, mcfg, QUEUE_ADD_MEMBER_REALTIME, "REALTIME");
-			found ++;
+			mem = ao2_find(q->data->members, (char *)interface, 0);
 		}
 		ast_config_destroy(mcfg);
-		if (found) {
-			mem = ao2_find(q->data->members, (char *)interface, 0);
-		}
 	}
 	return mem;
 }
@@ -5782,6 +5771,7 @@
 	} else if (!mem->dynamic) {
 		ao2_unlock(mem);
 		ao2_ref(mem, -1);
+		ao2_ref(q, -1);
 		return RES_NOT_DYNAMIC;
 	} else if (mem->dynamic) {
 		reload = 1;
@@ -5792,7 +5782,7 @@
 		"MemberName: %s\r\n",
 		q->name, mem->interface, mem->membername);
 
-	if (log_membername_as_agent && !ast_strlen_zero(mem->membername)) {
+	if (log_membername_as_agent) {
 		ast_queue_log(q->name, source, mem->membername, "REMOVEMEMBER", "%s", "");
 	} else {
 		ast_queue_log(q->name, source, mem->interface, "REMOVEMEMBER", "%s", "");
@@ -6403,7 +6393,7 @@
 	qe.last_periodic_announce_sound = 0;
 	qe.valid_digits = 0;
 
-	qe.attempts = ao2_container_alloc(MAX_QUEUE_BUCKETS, callattempt_hash_fn, NULL);
+	qe.attempts = ao2_container_alloc(MAX_QUEUE_BUCKETS, callattempt_hash_fn, callattempt_watched_cb);
 

[... 316 lines stripped ...]



More information about the asterisk-commits mailing list