aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authormmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b>2008-02-08 18:48:17 +0000
committermmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b>2008-02-08 18:48:17 +0000
commit8aded204cd453dff3bb6402bdecf2c2f76245c25 (patch)
treeee6e18e893ece13cb098853fe242c30c057a60e6 /apps
parent52bfc9d6f67aff332be439bfe6361b98e4e12cf5 (diff)
Prevent a potential three-thread deadlock. Also added a comment block
to explicitly state the locking order necessary inside app_queue. (closes issue #11862) Reported by: flujan Patches: 11862.patch uploaded by putnopvut (license 60) Tested by: flujan git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@103120 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'apps')
-rw-r--r--apps/app_queue.c29
1 files changed, 22 insertions, 7 deletions
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 3dbb7f0a4..0374575ec 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -99,6 +99,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/astobj2.h"
#include "asterisk/global_datastores.h"
+/* Please read before modifying this file.
+ * There are three locks which are regularly used
+ * throughout this file, the queue list lock, the lock
+ * for each individual queue, and the interface list lock.
+ * Please be extra careful to always lock in the following order
+ * 1) queue list lock
+ * 2) individual queue lock
+ * 3) interface list lock
+ * 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!
+ */
+
+
enum {
QUEUE_STRATEGY_RINGALL = 0,
QUEUE_STRATEGY_ROUNDROBIN,
@@ -889,15 +903,16 @@ static int remove_from_interfaces(const char *interface)
{
struct member_interface *curint;
+ if (interface_exists_global(interface))
+ return 0;
+
AST_LIST_LOCK(&interfaces);
AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
if (!strcasecmp(curint->interface, interface)) {
- if (!interface_exists_global(interface)) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
- AST_LIST_REMOVE_CURRENT(&interfaces, list);
- free(curint);
- }
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
+ AST_LIST_REMOVE_CURRENT(&interfaces, list);
+ free(curint);
break;
}
}
@@ -4248,9 +4263,9 @@ static int reload_queues(void)
continue;
}
- remove_from_interfaces(cur->interface);
q->membercount--;
ao2_unlink(q->members, cur);
+ remove_from_interfaces(cur->interface);
ao2_ref(cur, -1);
}