Add some more of kpflemings optimizations (bugs #3092, #3094)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4492 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Mark Spencer 2004-12-19 21:44:24 +00:00
parent 0570c6305f
commit ed2d0a0eb2
1 changed files with 59 additions and 72 deletions

View File

@ -154,6 +154,21 @@ static const char *pm_family = "/Queue/PersistentMembers";
/* queues.conf [general] option */
static int queue_persistent_members = 0;
#define QUEUE_FLAG_RINGBACKONLY (1 << 0)
#define QUEUE_FLAG_MUSICONHOLD (1 << 1)
#define QUEUE_FLAG_DATAQUALITY (1 << 2)
#define QUEUE_FLAG_REDIR_IN (1 << 3)
#define QUEUE_FLAG_REDIR_OUT (1 << 4)
#define QUEUE_FLAG_DISCON_IN (1 << 5)
#define QUEUE_FLAG_DISCON_OUT (1 << 6)
#define QUEUE_FLAG_MONJOIN (1 << 7) /* Should we join the two files when we are done with the call */
#define QUEUE_FLAG_DEAD (1 << 8) /* Whether the queue is dead or not */
#define QUEUE_FLAG_JOINEMPTY (1 << 9) /* Do we care if the queue has no members? */
#define QUEUE_FLAG_EVENTWHENCALLED (1 << 10) /* Generate an event when the agent is called (before pickup) */
#define QUEUE_FLAG_LEAVEWHENEMPTY (1 << 11) /* If all agents leave the queue, remove callers from the queue */
#define QUEUE_FLAG_REPORTHOLDTIME (1 << 12) /* Should we report caller hold time to answering member? */
#define QUEUE_FLAG_WRAPPED (1 << 13) /* Round Robin - wrapped around? */
/* We define a customer "local user" structure because we
use it not only for keeping track of what is in use but
also for keeping track of who we're dialing. */
@ -164,13 +179,7 @@ struct localuser {
int stillgoing;
int metric;
int oldstatus;
int allowredirect_in;
int allowredirect_out;
int ringbackonly;
int musiconhold;
int dataquality;
int allowdisconnect_in;
int allowdisconnect_out;
int flags; /* flag bits */
time_t lastcall;
struct member *member;
struct localuser *next;
@ -211,6 +220,7 @@ struct ast_call_queue {
char moh[80]; /* Name of musiconhold to be used */
char announce[80]; /* Announcement to play when call is answered */
char context[80]; /* Context for this queue */
int flags; /* flag bits */
int strategy; /* Queueing strategy */
int announcefrequency; /* How often to announce their position */
int roundingseconds; /* How many seconds do we round to? */
@ -221,7 +231,6 @@ struct ast_call_queue {
int servicelevel; /* seconds setting for servicelevel*/
int callscompletedinsl; /* Number of queue calls answererd with servicelevel*/
char monfmt[8]; /* Format to use when recording calls */
int monjoin; /* Should we join the two files when we are done with the call */
char sound_next[80]; /* Sound file: "Your call is now first in line" (def. queue-youarenext) */
char sound_thereare[80]; /* Sound file: "There are currently" (def. queue-thereare) */
char sound_calls[80]; /* Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
@ -236,18 +245,12 @@ struct ast_call_queue {
int maxlen; /* Max number of entries in queue */
int wrapuptime; /* Wrapup Time */
int dead; /* Whether this queue is dead or not */
int retry; /* Retry calling everyone after this amount of time */
int timeout; /* How long to wait for an answer */
/* Queue strategy things */
int rrpos; /* Round Robin - position */
int wrapped; /* Round Robin - wrapped around? */
int joinempty; /* Do we care if the queue has no members? */
int eventwhencalled; /* Generate an event when the agent is called (before pickup) */
int leavewhenempty; /* If all agents leave the queue, remove callers from the queue */
int reportholdtime; /* Should we report caller hold time to member? */
int memberdelay; /* Seconds to delay connecting member to caller */
struct member *members; /* Member channels to be tried */
@ -405,7 +408,7 @@ static int join_queue(char *queuename, struct queue_ent *qe)
if (!strcasecmp(q->name, queuename)) {
/* This is our one */
ast_mutex_lock(&q->lock);
if ((!has_no_members(q) || q->joinempty) && (!q->maxlen || (q->count < q->maxlen))) {
if ((!has_no_members(q) || ast_test_flag(q, QUEUE_FLAG_JOINEMPTY)) && (!q->maxlen || (q->count < q->maxlen))) {
/* There's space for us, put us at the right position inside
* the queue.
* Take into account the priority of the calling user */
@ -643,7 +646,7 @@ ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name
cur = cur->next;
}
ast_mutex_unlock(&q->lock);
if (q->dead && !q->count) {
if (ast_test_flag(q, QUEUE_FLAG_DEAD) && !q->count) {
/* It's dead and nobody is in it, so kill it */
destroy_queue(q);
}
@ -773,7 +776,7 @@ static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
tmp->stillgoing = 0;
return 0;
} else {
if (qe->parent->eventwhencalled) {
if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) {
manager_event(EVENT_FLAG_AGENT, "AgentCalled",
"AgentCalled: %s\r\n"
"ChannelCalling: %s\r\n"
@ -859,7 +862,7 @@ static int store_next(struct queue_ent *qe, struct localuser *outgoing)
qe->parent->rrpos = best->metric % 1000;
} else {
/* Just increment rrpos */
if (!qe->parent->wrapped) {
if (!ast_test_flag(qe->parent, QUEUE_FLAG_WRAPPED)) {
/* No more channels, start over */
qe->parent->rrpos = 0;
} else {
@ -867,7 +870,7 @@ static int store_next(struct queue_ent *qe, struct localuser *outgoing)
qe->parent->rrpos++;
}
}
qe->parent->wrapped = 0;
ast_clear_flag(qe->parent, QUEUE_FLAG_WRAPPED);
return 0;
}
@ -889,7 +892,7 @@ static int valid_exit(struct queue_ent *qe, char digit)
#define AST_MAX_WATCHERS 256
static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect_in, int *allowdisconnect_out, char *digit)
static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, struct localuser *flags, char *digit)
{
char *queue = qe->parent->name;
struct localuser *o;
@ -939,10 +942,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
peer = o;
*allowredir_in = o->allowredirect_in;
*allowredir_out = o->allowredirect_out;
*allowdisconnect_in = o->allowdisconnect_in;
*allowdisconnect_out = o->allowdisconnect_out;
ast_copy_flags(flags, o, QUEUE_FLAG_REDIR_IN & QUEUE_FLAG_REDIR_OUT & QUEUE_FLAG_DISCON_IN & QUEUE_FLAG_DISCON_OUT);
}
} else if (o->chan && (o->chan == winner)) {
if (!ast_strlen_zero(o->chan->call_forward)) {
@ -1028,10 +1028,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
peer = o;
*allowredir_in = o->allowredirect_in;
*allowredir_out = o->allowredirect_out;
*allowdisconnect_in = o->allowdisconnect_out;
*allowdisconnect_out = o->allowdisconnect_out;
ast_copy_flags(flags, o, QUEUE_FLAG_REDIR_IN & QUEUE_FLAG_REDIR_OUT & QUEUE_FLAG_DISCON_IN & QUEUE_FLAG_DISCON_OUT);
}
break;
case AST_CONTROL_BUSY:
@ -1099,7 +1096,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
*to=-1;
return NULL;
}
if (f && (f->frametype == AST_FRAME_DTMF) && allowdisconnect_out && (f->subclass == '*')) {
if (f && (f->frametype == AST_FRAME_DTMF) && ast_test_flag(flags, QUEUE_FLAG_DISCON_OUT) && (f->subclass == '*')) {
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
*to=0;
@ -1148,22 +1145,15 @@ static int wait_our_turn(struct queue_ent *qe, int ringing)
/* This is the holding pen for callers 2 through maxlen */
for (;;) {
/* Atomically read the parent head -- does not need a lock */
ch = qe->parent->head;
/* If we are now at the top of the head, break out */
if (ch == qe) {
if (option_debug)
ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
if (is_our_turn(qe))
break;
}
/* If we have timed out, break out */
if (qe->expire && (time(NULL) > qe->expire))
break;
/* leave the queue if no agents, if enabled */
if (has_no_members(qe->parent) && qe->parent->leavewhenempty) {
if (ast_test_flag(qe->parent, QUEUE_FLAG_LEAVEWHENEMPTY) && has_no_members(qe->parent)) {
leave_queue(qe);
break;
}
@ -1209,14 +1199,14 @@ static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, st
break;
case QUEUE_STRATEGY_ROUNDROBIN:
if (!pos) {
if (!q->wrapped) {
if (!ast_test_flag(q, QUEUE_FLAG_WRAPPED)) {
/* No more channels, start over */
q->rrpos = 0;
} else {
/* Prioritize next entry */
q->rrpos++;
}
q->wrapped = 0;
ast_clear_flag(q, QUEUE_FLAG_WRAPPED);
}
/* Fall through */
case QUEUE_STRATEGY_RRMEMORY:
@ -1225,7 +1215,7 @@ static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, st
} else {
if (pos > q->rrpos) {
/* Indicate there is another priority */
q->wrapped = 1;
ast_set_flag(q, QUEUE_FLAG_WRAPPED);
}
tmp->metric = pos;
}
@ -1258,10 +1248,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
struct member *cur;
struct localuser *outgoing=NULL, *tmp = NULL;
int to;
int allowredir_in=0;
int allowredir_out=0;
int allowdisconnect_in=0;
int allowdisconnect_out=0;
struct localuser flags_dummy;
char restofit[AST_MAX_EXTENSION];
char oldexten[AST_MAX_EXTENSION]="";
char oldcontext[AST_MAX_EXTENSION]="";
@ -1303,19 +1290,19 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
tmp->stillgoing = -1;
if (options) {
if (strchr(options, 't'))
tmp->allowredirect_in = 1;
ast_set_flag(tmp, QUEUE_FLAG_REDIR_IN);
if (strchr(options, 'T'))
tmp->allowredirect_out = 1;
ast_set_flag(tmp, QUEUE_FLAG_REDIR_OUT);
if (strchr(options, 'r'))
tmp->ringbackonly = 1;
ast_set_flag(tmp, QUEUE_FLAG_RINGBACKONLY);
if (strchr(options, 'm'))
tmp->musiconhold = 1;
ast_set_flag(tmp, QUEUE_FLAG_MUSICONHOLD);
if (strchr(options, 'd'))
tmp->dataquality = 1;
ast_set_flag(tmp, QUEUE_FLAG_DATAQUALITY);
if (strchr(options, 'h'))
tmp->allowdisconnect_in = 1;
ast_set_flag(tmp, QUEUE_FLAG_DISCON_IN);
if (strchr(options, 'H'))
tmp->allowdisconnect_out = 1;
ast_set_flag(tmp, QUEUE_FLAG_DISCON_OUT);
if ((strchr(options, 'n')) && (now - qe->start >= qe->parent->timeout))
*go_on = 1;
}
@ -1358,7 +1345,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
to = -1;
ring_one(qe, outgoing);
ast_mutex_unlock(&qe->parent->lock);
lpeer = wait_for_answer(qe, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect_in, &allowdisconnect_out, &digit);
lpeer = wait_for_answer(qe, outgoing, &to, &flags_dummy, &digit);
ast_mutex_lock(&qe->parent->lock);
if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
store_next(qe, outgoing);
@ -1390,11 +1377,11 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
conversation. */
qe->handled++;
if (!strcmp(qe->chan->type,"Zap")) {
if (tmp->dataquality) zapx = 0;
zapx = !ast_test_flag(tmp, QUEUE_FLAG_DATAQUALITY);
ast_channel_setoption(qe->chan,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
}
if (!strcmp(peer->type,"Zap")) {
if (tmp->dataquality) zapx = 0;
zapx = !ast_test_flag(tmp, QUEUE_FLAG_DATAQUALITY);
ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
}
/* Update parameters for the queue */
@ -1402,7 +1389,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
member = lpeer->member;
hanguptree(outgoing, peer);
outgoing = NULL;
if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
if (announce || ast_test_flag(qe->parent, QUEUE_FLAG_REPORTHOLDTIME) || qe->parent->memberdelay) {
int res2;
res2 = ast_autoservice_start(qe->chan);
if (!res2) {
@ -1414,7 +1401,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
if (play_file(peer, announce))
ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
}
if (!res2 && qe->parent->reportholdtime) {
if (!res2 && ast_test_flag(qe->parent, QUEUE_FLAG_REPORTHOLDTIME)) {
if (!play_file(peer, qe->parent->sound_reporthold)) {
int holdtime;
time_t now;
@ -1460,7 +1447,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
} else {
ast_monitor_start( peer, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
}
if(qe->parent->monjoin) {
if(ast_test_flag(qe->parent, QUEUE_FLAG_MONJOIN)) {
ast_monitor_setjoinfiles( peer, 1);
}
}
@ -1477,11 +1464,11 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
time(&callstart);
memset(&config,0,sizeof(struct ast_bridge_config));
config.allowredirect_in = allowredir_in;
config.allowredirect_out = allowredir_out;
config.allowdisconnect_in = allowdisconnect_in;
config.allowdisconnect_out = allowdisconnect_out;
bridge = ast_bridge_call(qe->chan,peer,&config);
config.allowredirect_in = ast_test_flag(&flags_dummy, QUEUE_FLAG_REDIR_IN);
config.allowredirect_out = ast_test_flag(&flags_dummy, QUEUE_FLAG_REDIR_OUT);
config.allowdisconnect_in = ast_test_flag(&flags_dummy, QUEUE_FLAG_DISCON_IN);
config.allowdisconnect_out = ast_test_flag(&flags_dummy, QUEUE_FLAG_DISCON_OUT);
bridge = ast_bridge_call(qe->chan,peer,&config);
if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
@ -2037,7 +2024,7 @@ check_turns:
}
/* leave the queue if no agents, if enabled */
if (has_no_members(qe.parent) && (qe.parent->leavewhenempty)) {
if (ast_test_flag(qe.parent, QUEUE_FLAG_LEAVEWHENEMPTY) && has_no_members(qe.parent)) {
res = 0;
break;
}
@ -2121,7 +2108,7 @@ static void reload_queues(void)
/* Mark all queues as dead for the moment */
q = queues;
while(q) {
q->dead = 1;
ast_set_flag(q, QUEUE_FLAG_DEAD);
q = q->next;
}
/* Chug through config file */
@ -2151,7 +2138,7 @@ static void reload_queues(void)
if (!new)
ast_mutex_lock(&q->lock);
/* Re-initialize the queue */
q->dead = 0;
ast_clear_flag(q, QUEUE_FLAG_DEAD);
q->retry = 0;
q->timeout = -1;
q->maxlen = 0;
@ -2216,7 +2203,7 @@ static void reload_queues(void)
} else if (!strcasecmp(var->name, "timeout")) {
q->timeout = atoi(var->value);
} else if (!strcasecmp(var->name, "monitor-join")) {
q->monjoin = ast_true(var->value);
ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_MONJOIN);
} else if (!strcasecmp(var->name, "monitor-format")) {
strncpy(q->monfmt, var->value, sizeof(q->monfmt) - 1);
} else if (!strcasecmp(var->name, "queue-youarenext")) {
@ -2262,13 +2249,13 @@ static void reload_queues(void)
q->strategy = 0;
}
} else if (!strcasecmp(var->name, "joinempty")) {
q->joinempty = ast_true(var->value);
ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_JOINEMPTY);
} else if (!strcasecmp(var->name, "leavewhenempty")) {
q->leavewhenempty = ast_true(var->value);
ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_LEAVEWHENEMPTY);
} else if (!strcasecmp(var->name, "eventwhencalled")) {
q->eventwhencalled = ast_true(var->value);
ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_EVENTWHENCALLED);
} else if (!strcasecmp(var->name, "reportholdtime")) {
q->reportholdtime = ast_true(var->value);
ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_REPORTHOLDTIME);
} else if (!strcasecmp(var->name, "memberdelay")) {
q->memberdelay = atoi(var->value);
} else {
@ -2302,7 +2289,7 @@ static void reload_queues(void)
ql = NULL;
while(q) {
qn = q->next;
if (q->dead) {
if (ast_test_flag(q, QUEUE_FLAG_DEAD)) {
if (ql)
ql->next = q->next;
else