Skip to content

Commit

Permalink
Merge Rizzo's waitfor update (bug #4584)
Browse files Browse the repository at this point in the history
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@8877 65c4cc65-6c06-0410-ace0-fbb531ad65f3
  • Loading branch information
Mark Spencer committed Jan 30, 2006
1 parent f8b6a4d commit 37815b2
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 166 deletions.
262 changes: 109 additions & 153 deletions channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,10 @@ struct ast_channel *ast_channel_alloc(int needqueue)
return NULL;
}

for (x=0; x<AST_MAX_FDS - 1; x++)
/* Don't bother initializing the last two FD here, because they
will *always* be set just a few lines down (AST_TIMING_FD,
AST_ALERT_FD). */
for (x=0; x<AST_MAX_FDS - 2; x++)
tmp->fds[x] = -1;

#ifdef ZAPTEL_OPTIMIZATIONS
Expand Down Expand Up @@ -636,9 +639,9 @@ struct ast_channel *ast_channel_alloc(int needqueue)
tmp->alertpipe[0] = tmp->alertpipe[1] = -1;

/* Always watch the alertpipe */
tmp->fds[AST_MAX_FDS-1] = tmp->alertpipe[0];
tmp->fds[AST_ALERT_FD] = tmp->alertpipe[0];
/* And timing pipe */
tmp->fds[AST_MAX_FDS-2] = tmp->timingfd;
tmp->fds[AST_TIMING_FD] = tmp->timingfd;
strcpy(tmp->name, "**Unknown**");
/* Initial state */
tmp->_state = AST_STATE_DOWN;
Expand Down Expand Up @@ -1414,6 +1417,7 @@ void ast_deactivate_generator(struct ast_channel *chan)
chan->generator->release(chan, chan->generatordata);
chan->generatordata = NULL;
chan->generator = NULL;
chan->fds[AST_GENERATOR_FD] = -1;
ast_clear_flag(chan, AST_FLAG_WRITE_INT);
ast_settimeout(chan, 0, NULL, NULL);
}
Expand Down Expand Up @@ -1470,56 +1474,8 @@ int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen,
/*! \brief Wait for x amount of time on a file descriptor to have input. */
int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
{
struct timeval start = { 0 , 0 };
int res;
int x, y;
int winner = -1;
int spoint;
struct pollfd *pfds;

pfds = alloca(sizeof(struct pollfd) * n);
if (!pfds) {
ast_log(LOG_ERROR, "Out of memory\n");
return -1;
}
if (*ms > 0)
start = ast_tvnow();
y = 0;
for (x=0; x < n; x++) {
if (fds[x] > -1) {
pfds[y].fd = fds[x];
pfds[y].events = POLLIN | POLLPRI;
y++;
}
}
res = poll(pfds, y, *ms);
if (res < 0) {
/* Simulate a timeout if we were interrupted */
if (errno != EINTR)
*ms = -1;
else
*ms = 0;
return -1;
}
spoint = 0;
for (x=0; x < n; x++) {
if (fds[x] > -1) {
if ((res = ast_fdisset(pfds, fds[x], y, &spoint))) {
winner = fds[x];
if (exception) {
if (res & POLLPRI)
*exception = -1;
else
*exception = 0;
}
}
}
}
if (*ms > 0) {
*ms -= ast_tvdiff_ms(ast_tvnow(), start);
if (*ms < 0)
*ms = 0;
}
ast_waitfor_nandfds(NULL, 0, fds, n, exception, &winner, ms);
return winner;
}

Expand All @@ -1532,13 +1488,19 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
int res;
long rms;
int x, y, max;
int spoint;
int sz;
time_t now = 0;
long whentohangup = 0, havewhen = 0, diff;
long whentohangup = 0, diff;
struct ast_channel *winner = NULL;

pfds = alloca(sizeof(struct pollfd) * (n * AST_MAX_FDS + nfds));
if (!pfds) {
struct fdmap {
int chan;
int fdno;
} *fdmap;

sz = n * AST_MAX_FDS + nfds;
pfds = alloca(sizeof(struct pollfd) * sz);
fdmap = alloca(sizeof(struct fdmap) * sz);
if (!pfds || !fdmap) {
ast_log(LOG_ERROR, "Out of memory\n");
*outfd = -1;
return NULL;
Expand All @@ -1552,15 +1514,6 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
/* Perform any pending masquerades */
for (x=0; x < n; x++) {
ast_mutex_lock(&c[x]->lock);
if (c[x]->whentohangup) {
if (!havewhen)
time(&now);
diff = c[x]->whentohangup - now;
if (!havewhen || (diff < whentohangup)) {
havewhen++;
whentohangup = diff;
}
}
if (c[x]->masq) {
if (ast_do_masquerade(c[x])) {
ast_log(LOG_WARNING, "Masquerade failed\n");
Expand All @@ -1569,40 +1522,52 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
return NULL;
}
}
if (c[x]->whentohangup) {
if (!whentohangup)
time(&now);
diff = c[x]->whentohangup - now;
if (diff < 1) {
/* Should already be hungup */
c[x]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
ast_mutex_unlock(&c[x]->lock);
return c[x];
}
if (!whentohangup || (diff < whentohangup))
whentohangup = diff;
}
ast_mutex_unlock(&c[x]->lock);
}

/* Wait full interval */
rms = *ms;

if (havewhen) {
if ((*ms < 0) || (whentohangup * 1000 < *ms)) {
rms = whentohangup * 1000;
}
if (whentohangup) {
rms = (whentohangup - now) * 1000; /* timeout in milliseconds */
if (*ms >= 0 && *ms < rms) /* original *ms still smaller */
rms = *ms;
}
/*
* Build the pollfd array, putting the channels' fds first,
* followed by individual fds. Order is important because
* individual fd's must have priority over channel fds.
*/
max = 0;
for (x=0; x < n; x++) {
for (y=0; y< AST_MAX_FDS; y++) {
if (c[x]->fds[y] > -1) {
pfds[max].fd = c[x]->fds[y];
pfds[max].events = POLLIN | POLLPRI;
pfds[max].revents = 0;
max++;
}
for (x=0; x<n; x++) {
for (y=0; y<AST_MAX_FDS; y++) {
fdmap[max].fdno = y; /* fd y is linked to this pfds */
fdmap[max].chan = x; /* channel x is linked to this pfds */
max += ast_add_fd(&pfds[max], c[x]->fds[y]);
}
CHECK_BLOCKING(c[x]);
}
for (x=0; x < nfds; x++) {
if (fds[x] > -1) {
pfds[max].fd = fds[x];
pfds[max].events = POLLIN | POLLPRI;
pfds[max].revents = 0;
max++;
}
/* Add the individual fds */
for (x=0; x<nfds; x++) {
fdmap[max].chan = -1;
max += ast_add_fd(&pfds[max], fds[x]);
}

if (*ms > 0)
start = ast_tvnow();

if (sizeof(int) == 4) {
if (sizeof(int) == 4) { /* XXX fix timeout > 600000 on linux x86-32 */
do {
int kbrms = rms;
if (kbrms > 600000)
Expand All @@ -1614,65 +1579,49 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
} else {
res = poll(pfds, max, rms);
}

if (res < 0) {
for (x=0; x < n; x++)
ast_clear_flag(c[x], AST_FLAG_BLOCKING);
/* Simulate a timeout if we were interrupted */
if (errno != EINTR)
*ms = -1;
else {
/* Just an interrupt */
#if 0
*ms = 0;
#endif
}
for (x=0; x<n; x++)
ast_clear_flag(c[x], AST_FLAG_BLOCKING);
if (res < 0) { /* Simulate a timeout if we were interrupted */
*ms = (errno != EINTR) ? -1 : 0;
return NULL;
} else {
/* If no fds signalled, then timeout. So set ms = 0
since we may not have an exact timeout.
*/
if (res == 0)
*ms = 0;
}

if (havewhen)
if (whentohangup) { /* if we have a timeout, check who expired */
time(&now);
spoint = 0;
for (x=0; x < n; x++) {
ast_clear_flag(c[x], AST_FLAG_BLOCKING);
if (havewhen && c[x]->whentohangup && (now > c[x]->whentohangup)) {
c[x]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
if (!winner)
winner = c[x];
}
for (y=0; y < AST_MAX_FDS; y++) {
if (c[x]->fds[y] > -1) {
if ((res = ast_fdisset(pfds, c[x]->fds[y], max, &spoint))) {
if (res & POLLPRI)
ast_set_flag(c[x], AST_FLAG_EXCEPTION);
else
ast_clear_flag(c[x], AST_FLAG_EXCEPTION);
c[x]->fdno = y;
for (x=0; x<n; x++) {
if (c[x]->whentohangup && now >= c[x]->whentohangup) {
c[x]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
if (winner == NULL)
winner = c[x];
}
}
}
}
for (x=0; x < nfds; x++) {
if (fds[x] > -1) {
if ((res = ast_fdisset(pfds, fds[x], max, &spoint))) {
if (outfd)
*outfd = fds[x];
if (exception) {
if (res & POLLPRI)
*exception = -1;
else
*exception = 0;
}
winner = NULL;
}
}
if (res == 0) { /* no fd ready, reset timeout and done */
*ms = 0; /* XXX use 0 since we may not have an exact timeout. */
return winner;
}
/*
* Then check if any channel or fd has a pending event.
* Remember to check channels first and fds last, as they
* must have priority on setting 'winner'
*/
for (x = 0; x < max; x++) {
res = pfds[x].revents;
if (res == 0)
continue;
if (fdmap[x].chan >= 0) { /* this is a channel */
winner = c[fdmap[x].chan]; /* override previous winners */
if (res & POLLPRI)
ast_set_flag(winner, AST_FLAG_EXCEPTION);
else
ast_clear_flag(winner, AST_FLAG_EXCEPTION);
winner->fdno = fdmap[x].fdno;
} else { /* this is an fd */
if (outfd)
*outfd = pfds[x].fd;
if (exception)
*exception = (res & POLLPRI) ? -1 : 0;
winner = NULL;
}
}
if (*ms > 0) {
*ms -= ast_tvdiff_ms(ast_tvnow(), start);
Expand All @@ -1689,16 +1638,11 @@ struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)

int ast_waitfor(struct ast_channel *c, int ms)
{
struct ast_channel *chan;
int oldms = ms;

chan = ast_waitfor_n(&c, 1, &ms);
if (ms < 0) {
if (oldms < 0)
return 0;
else
return -1;
}
ast_waitfor_nandfds(&c, 1, NULL, 0, NULL, NULL, &ms);
if ((ms < 0) && (oldms < 0))
ms = 0;
return ms;
}

Expand Down Expand Up @@ -1856,7 +1800,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
read(chan->alertpipe[0], &blah, sizeof(blah));
}
#ifdef ZAPTEL_OPTIMIZATIONS
if ((chan->timingfd > -1) && (chan->fdno == AST_MAX_FDS - 2) && ast_test_flag(chan, AST_FLAG_EXCEPTION)) {
if (chan->timingfd > -1 && chan->fdno == AST_TIMING_FD && ast_test_flag(chan, AST_FLAG_EXCEPTION)) {
ast_clear_flag(chan, AST_FLAG_EXCEPTION);
blah = -1;
/* IF we can't get event, assume it's an expired as-per the old interface */
Expand Down Expand Up @@ -1898,8 +1842,19 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
return f;
} else
ast_log(LOG_NOTICE, "No/unknown event '%d' on timer for '%s'?\n", blah, chan->name);
}
} else
#endif
/* Check for AST_GENERATOR_FD if not null. If so, call generator with -1
arguments now so it can do whatever it needs to. */
if (chan->fds[AST_GENERATOR_FD] > -1 && chan->fdno == AST_GENERATOR_FD) {
void *tmp = chan->generatordata;
chan->generatordata = NULL; /* reset to let ast_write get through */
chan->generator->generate(chan, tmp, -1, -1);
chan->generatordata = tmp;
f = &null_frame;
return f;
}

/* Check for pending read queue */
if (chan->readq) {
f = chan->readq;
Expand Down Expand Up @@ -3088,9 +3043,10 @@ int ast_do_masquerade(struct ast_channel *original)

/* Keep the same language. */
ast_copy_string(original->language, clone->language, sizeof(original->language));
/* Copy the FD's */
/* Copy the FD's other than the generator fd */
for (x = 0; x < AST_MAX_FDS; x++) {
original->fds[x] = clone->fds[x];
if (x != AST_GENERATOR_FD)
original->fds[x] = clone->fds[x];
}
clone_variables(original, clone);
AST_LIST_HEAD_INIT_NOLOCK(&clone->varshead);
Expand All @@ -3114,7 +3070,7 @@ int ast_do_masquerade(struct ast_channel *original)
clone->cid = tmpcid;

/* Restore original timing file descriptor */
original->fds[AST_MAX_FDS - 2] = original->timingfd;
original->fds[AST_TIMING_FD] = original->timingfd;

/* Our native formats are different now */
original->nativeformats = clone->nativeformats;
Expand Down

0 comments on commit 37815b2

Please sign in to comment.