aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2006-01-30 03:13:33 +0000
committermarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2006-01-30 03:13:33 +0000
commitdf81c56d1365a5d81d8c46aa4235ae7737d2dcc1 (patch)
treecca132b8be25dadbe207b7752c6b7b16bc379435
parent666c469664803f6b58e7e2e4e785b71119206c74 (diff)
Merge Rizzo's waitfor update (bug #4584)
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@8877 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--channel.c262
-rw-r--r--channels/chan_agent.c9
-rw-r--r--channels/chan_features.c4
-rw-r--r--include/asterisk/channel.h33
4 files changed, 142 insertions, 166 deletions
diff --git a/channel.c b/channel.c
index 501baa821..ee80b7d4a 100644
--- a/channel.c
+++ b/channel.c
@@ -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
@@ -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;
@@ -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);
}
@@ -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;
}
@@ -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;
@@ -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");
@@ -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)
@@ -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);
@@ -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;
}
@@ -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 */
@@ -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;
@@ -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);
@@ -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;
diff --git a/channels/chan_agent.c b/channels/chan_agent.c
index 89e21ef43..3299aa02e 100644
--- a/channels/chan_agent.c
+++ b/channels/chan_agent.c
@@ -233,10 +233,10 @@ static AST_LIST_HEAD_STATIC(agents, agent_pvt); /**< Holds the list of agents (l
int x; \
if (p->chan) { \
for (x=0;x<AST_MAX_FDS;x++) {\
- if (x != AST_MAX_FDS - 2) \
+ if (x != AST_TIMING_FD) \
ast->fds[x] = p->chan->fds[x]; \
} \
- ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
+ ast->fds[AST_AGENT_FD] = p->chan->fds[AST_TIMING_FD]; \
} \
} while(0)
@@ -445,10 +445,7 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
CHECK_FORMATS(ast, p);
if (p->chan) {
ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
- if (ast->fdno == AST_MAX_FDS - 3)
- p->chan->fdno = AST_MAX_FDS - 2;
- else
- p->chan->fdno = ast->fdno;
+ p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;
f = ast_read(p->chan);
} else
f = &null_frame;
diff --git a/channels/chan_features.c b/channels/chan_features.c
index dc2b70a10..7eef2e990 100644
--- a/channels/chan_features.c
+++ b/channels/chan_features.c
@@ -170,8 +170,8 @@ static void restore_channel(struct feature_pvt *p, int index)
p->subs[index].owner->timingfd = p->subs[index].timingfdbackup;
p->subs[index].owner->alertpipe[0] = p->subs[index].alertpipebackup[0];
p->subs[index].owner->alertpipe[1] = p->subs[index].alertpipebackup[1];
- p->subs[index].owner->fds[AST_MAX_FDS-1] = p->subs[index].alertpipebackup[0];
- p->subs[index].owner->fds[AST_MAX_FDS-2] = p->subs[index].timingfdbackup;
+ p->subs[index].owner->fds[AST_ALERT_FD] = p->subs[index].alertpipebackup[0];
+ p->subs[index].owner->fds[AST_TIMING_FD] = p->subs[index].timingfdbackup;
}
static void update_features(struct feature_pvt *p, int index)
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 4b120d8cf..f07265fa4 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -119,6 +119,14 @@ extern "C" {
#define MAX_MUSICCLASS 20
#define AST_MAX_FDS 8
+/*
+ * We have AST_MAX_FDS file descriptors in a channel.
+ * Some of them have a fixed use:
+ */
+#define AST_ALERT_FD (AST_MAX_FDS-1) /* used for alertpipe */
+#define AST_TIMING_FD (AST_MAX_FDS-2) /* used for timingfd */
+#define AST_AGENT_FD (AST_MAX_FDS-3) /* used by agents for pass thru */
+#define AST_GENERATOR_FD (AST_MAX_FDS-4) /* used by generator */
enum ast_bridge_result {
AST_BRIDGE_COMPLETE = 0,
@@ -1124,16 +1132,31 @@ void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_sil
/* Misc. functions below */
+/* if fd is a valid descriptor, set *pfd with the descriptor
+ * Return 1 (not -1!) if added, 0 otherwise (so we can add the
+ * return value to the index into the array)
+ */
+static inline int ast_add_fd(struct pollfd *pfd, int fd)
+{
+ pfd->fd = fd;
+ pfd->events = POLLIN | POLLPRI;
+ return fd >= 0;
+}
+
/* Helper function for migrating select to poll */
static inline int ast_fdisset(struct pollfd *pfds, int fd, int max, int *start)
{
int x;
- for (x=start ? *start : 0;x<max;x++)
+ int dummy=0;
+
+ if (fd < 0)
+ return 0;
+ if (!start)
+ start = &dummy;
+ for (x = *start; x<max; x++)
if (pfds[x].fd == fd) {
- if (start) {
- if (x==*start)
- (*start)++;
- }
+ if (x == *start)
+ (*start)++;
return pfds[x].revents;
}
return 0;