--- /home/sjoerd/app_queue.c 2011-02-16 00:34:03.000000000 +0100 +++ apps/app_queue.c 2011-03-17 13:31:18.000000000 +0100 @@ -918,6 +918,7 @@ /*! \brief queues.conf per-queue weight option */ static int use_weight = 0; +static int use_auto_weight = 0; /*! \brief queues.conf [general] option */ static int autofill_default = 1; @@ -2937,6 +2938,62 @@ return found; } +static int get_longest_waiting_caller( struct call_queue *q ) +{ +/* SB, 8-5-2007. Gets the maximum holdtime of the callers to specified queue. returns 0 if no caller */ + time_t now; + + time( &now ); + + if (!q->head) //No callers? + return 0; + else + return (long)(now - q->head->start); //first caller is the longest waiting. + } + + +/* traverse all defined queues which have calls waiting and contain this member + return 0 if no other queue has precedence (higher weight) or 1 if found */ +static int compare_holdtime(struct call_queue *rq, struct member *member) +{ + struct call_queue *q; + struct member *mem; + int found = 0; + struct ao2_iterator queue_iter; + + /* q's lock and rq's lock already set by try_calling() + * to solve deadlock */ + 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 */ + queue_t_unref(q, "Done with iterator"); + continue; + } + ao2_lock(q); + if (q->count && q->members) { + if ((mem = ao2_find(q->members, member, OBJ_POINTER))) { + ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name); + int longest_wait_q = get_longest_waiting_caller(q); + int longest_wait_rq = get_longest_waiting_caller(rq); + + if ( longest_wait_q > longest_wait_rq && q->count >= num_available_members(q)) { + ast_debug(1, "Queue '%s' (holdtime %d, calls %d) is preferred over '%s' (holdtime %d, calls %d)\n", q->name, longest_wait_q, q->count, rq->name, longest_wait_rq, rq->count); + found = 1; + } + ao2_ref(mem, -1); + } + } + ao2_unlock(q); + queue_t_unref(q, "Done with iterator"); + if (found) { + break; + } + } + ao2_iterator_destroy(&queue_iter); + return found; +} + + /*! \brief common hangup actions */ static void do_hang(struct callattempt *o) { @@ -3032,7 +3089,7 @@ tmp->stillgoing = 0; return 0; } - if (use_weight && compare_weight(qe->parent,tmp->member)) { + if (use_weight && !use_auto_weight && compare_weight(qe->parent,tmp->member)) { ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); if (qe->chan->cdr) ast_cdr_busy(qe->chan->cdr); @@ -3040,6 +3097,16 @@ (*busies)++; return 0; } + if (use_weight && use_auto_weight && compare_holdtime(qe->parent,tmp->member)) { + ast_log(LOG_NOTICE, "Priority queue delaying call to %s. %s is needed for other queue (autoweight)\n", qe->parent->name, tmp->interface); + if (qe->chan->cdr) + ast_cdr_busy(qe->chan->cdr); + tmp->stillgoing = 0; + (*busies)++; + return 0; + } + + ast_copy_string(tech, tmp->interface, sizeof(tech)); if ((location = strchr(tech, '/'))) @@ -6522,6 +6589,17 @@ shared_lastcall = 0; if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) shared_lastcall = ast_true(general_val); + use_auto_weight = 0; + if ((general_val = ast_variable_retrieve(cfg, "general", "autoweight"))) + { + ast_log(LOG_WARNING, "found autoweight config var\n"); + if (ast_true(general_val)) + { + use_auto_weight = 1; + use_weight = 1; + ast_log(LOG_WARNING, "Using autoweight\n"); + } + } } /*! \brief reload information pertaining to a single member