aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/app_dial.c14
-rw-r--r--channels/chan_agent.c4
-rw-r--r--channels/chan_alsa.c2
-rw-r--r--channels/chan_features.c8
-rw-r--r--channels/chan_gtalk.c8
-rw-r--r--channels/chan_h323.c18
-rw-r--r--channels/chan_jingle.c8
-rw-r--r--channels/chan_mgcp.c4
-rw-r--r--channels/chan_misdn.c2
-rw-r--r--channels/chan_nbs.c2
-rw-r--r--channels/chan_oss.c4
-rw-r--r--channels/chan_phone.c2
-rw-r--r--channels/chan_sip.c12
-rw-r--r--channels/chan_skinny.c10
-rw-r--r--channels/chan_zap.c10
-rwxr-xr-xconfigure56
-rw-r--r--configure.ac8
-rw-r--r--include/asterisk/autoconfig.h.in3
-rw-r--r--include/asterisk/channel.h16
-rw-r--r--main/channel.c351
-rw-r--r--main/rtp.c12
21 files changed, 482 insertions, 72 deletions
diff --git a/apps/app_dial.c b/apps/app_dial.c
index 758426f6d..f118b7cb2 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -560,6 +560,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
struct ast_channel *peer = NULL;
/* single is set if only one destination is enabled */
int single = outgoing && !outgoing->next && !ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
+#ifdef HAVE_EPOLL
+ struct chanlist *epollo;
+#endif
if (single) {
/* Turn off hold music, etc */
@@ -567,7 +570,11 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
/* If we are calling a single channel, make them compatible for in-band tone purpose */
ast_channel_make_compatible(outgoing->chan, in);
}
-
+
+#ifdef HAVE_EPOLL
+ for (epollo = outgoing; epollo; epollo = epollo->next)
+ ast_poll_channel_add(in, epollo->chan);
+#endif
while (*to && !peer) {
struct chanlist *o;
@@ -814,6 +821,11 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
}
+#ifdef HAVE_EPOLL
+ for (epollo = outgoing; epollo; epollo = epollo->next)
+ ast_poll_channel_del(in, epollo->chan);
+#endif
+
return peer;
}
diff --git a/channels/chan_agent.c b/channels/chan_agent.c
index 21b82b8de..880501ac9 100644
--- a/channels/chan_agent.c
+++ b/channels/chan_agent.c
@@ -207,9 +207,9 @@ static AST_LIST_HEAD_STATIC(agents, agent_pvt); /*!< Holds the list of agents (l
if (p->chan) { \
for (x=0;x<AST_MAX_FDS;x++) {\
if (x != AST_TIMING_FD) \
- ast->fds[x] = p->chan->fds[x]; \
+ ast_channel_set_fd(ast, x, p->chan->fds[x]); \
} \
- ast->fds[AST_AGENT_FD] = p->chan->fds[AST_TIMING_FD]; \
+ ast_channel_set_fd(ast, AST_AGENT_FD, p->chan->fds[AST_TIMING_FD]); \
} \
} while(0)
diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c
index d3decea05..a2a10e85f 100644
--- a/channels/chan_alsa.c
+++ b/channels/chan_alsa.c
@@ -789,7 +789,7 @@ static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state)
return NULL;
tmp->tech = &alsa_tech;
- tmp->fds[0] = readdev;
+ ast_channel_set_fd(tmp, 0, readdev);
tmp->nativeformats = AST_FORMAT_SLINEAR;
tmp->readformat = AST_FORMAT_SLINEAR;
tmp->writeformat = AST_FORMAT_SLINEAR;
diff --git a/channels/chan_features.c b/channels/chan_features.c
index 3d199c36f..aa893de38 100644
--- a/channels/chan_features.c
+++ b/channels/chan_features.c
@@ -171,8 +171,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_ALERT_FD] = p->subs[index].alertpipebackup[0];
- p->subs[index].owner->fds[AST_TIMING_FD] = p->subs[index].timingfdbackup;
+ ast_channel_set_fd(p->subs[index].owner, AST_ALERT_FD, p->subs[index].alertpipebackup[0]);
+ ast_channel_set_fd(p->subs[index].owner, AST_TIMING_FD, p->subs[index].timingfdbackup);
}
static void update_features(struct feature_pvt *p, int index)
@@ -181,9 +181,9 @@ static void update_features(struct feature_pvt *p, int index)
if (p->subs[index].owner) {
for (x=0; x<AST_MAX_FDS; x++) {
if (index)
- p->subs[index].owner->fds[x] = -1;
+ ast_channel_set_fd(p->subs[index].owner, x, -1);
else
- p->subs[index].owner->fds[x] = p->subchan->fds[x];
+ ast_channel_set_fd(p->subs[index].owner, x, p->subchan->fds[x]);
}
if (!index) {
/* Copy timings from master channel */
diff --git a/channels/chan_gtalk.c b/channels/chan_gtalk.c
index bd53d7ae0..cbdaa076f 100644
--- a/channels/chan_gtalk.c
+++ b/channels/chan_gtalk.c
@@ -934,13 +934,13 @@ static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i,
if (i->rtp) {
ast_rtp_setstun(i->rtp, 1);
- tmp->fds[0] = ast_rtp_fd(i->rtp);
- tmp->fds[1] = ast_rtcp_fd(i->rtp);
+ ast_channel_set_fd(tmp, 0, ast_rtp_fd(i->rtp));
+ ast_channel_set_fd(tmp, 1, ast_rtcp_fd(i->rtp));
}
if (i->vrtp) {
ast_rtp_setstun(i->rtp, 1);
- tmp->fds[2] = ast_rtp_fd(i->vrtp);
- tmp->fds[3] = ast_rtcp_fd(i->vrtp);
+ ast_channel_set_fd(tmp, 2, ast_rtp_fd(i->vrtp));
+ ast_channel_set_fd(tmp, 3, ast_rtcp_fd(i->vrtp));
}
if (state == AST_STATE_RING)
tmp->rings = 1;
diff --git a/channels/chan_h323.c b/channels/chan_h323.c
index 4e38a4eb5..434d210d2 100644
--- a/channels/chan_h323.c
+++ b/channels/chan_h323.c
@@ -396,8 +396,8 @@ static void __oh323_update_info(struct ast_channel *c, struct oh323_pvt *pvt)
if (pvt->update_rtp_info > 0) {
if (pvt->rtp) {
ast_jb_configure(c, &global_jbconf);
- c->fds[0] = ast_rtp_fd(pvt->rtp);
- c->fds[1] = ast_rtcp_fd(pvt->rtp);
+ ast_channel_set_fd(c, 0, ast_rtp_fd(pvt->rtp));
+ ast_channel_set_fd(c, 1, ast_rtcp_fd(pvt->rtp));
ast_queue_frame(pvt->owner, &ast_null_frame); /* Tell Asterisk to apply changes */
}
pvt->update_rtp_info = -1;
@@ -995,8 +995,8 @@ static int __oh323_rtp_create(struct oh323_pvt *pvt)
if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
ast_jb_configure(pvt->owner, &global_jbconf);
- pvt->owner->fds[0] = ast_rtp_fd(pvt->rtp);
- pvt->owner->fds[1] = ast_rtcp_fd(pvt->rtp);
+ ast_channel_set_fd(pvt->owner, 0, ast_rtp_fd(pvt->rtp));
+ ast_channel_set_fd(pvt->owner, 1, ast_rtcp_fd(pvt->rtp));
ast_queue_frame(pvt->owner, &ast_null_frame); /* Tell Asterisk to apply changes */
ast_channel_unlock(pvt->owner);
} else
@@ -1040,18 +1040,18 @@ static struct ast_channel *__oh323_new(struct oh323_pvt *pvt, int state, const c
ch->readformat = fmt;
ch->rawreadformat = fmt;
#if 0
- ch->fds[0] = ast_rtp_fd(pvt->rtp);
- ch->fds[1] = ast_rtcp_fd(pvt->rtp);
+ ast_channel_set_fd(ch, 0, ast_rtp_fd(pvt->rtp));
+ ast_channel_set_fd(ch, 1, ast_rtcp_fd(pvt->rtp));
#endif
#ifdef VIDEO_SUPPORT
if (pvt->vrtp) {
- ch->fds[2] = ast_rtp_fd(pvt->vrtp);
- ch->fds[3] = ast_rtcp_fd(pvt->vrtp);
+ ast_channel_set_fd(ch, 2, ast_rtp_fd(pvt->vrtp));
+ ast_channel_set_fd(ch, 3, ast_rtcp_fd(pvt->vrtp));
}
#endif
#ifdef T38_SUPPORT
if (pvt->udptl) {
- ch->fds[4] = ast_udptl_fd(pvt->udptl);
+ ast_channel_set_fd(ch, 4, ast_udptl_fd(pvt->udptl));
}
#endif
if (state == AST_STATE_RING) {
diff --git a/channels/chan_jingle.c b/channels/chan_jingle.c
index 089797315..e45724f04 100644
--- a/channels/chan_jingle.c
+++ b/channels/chan_jingle.c
@@ -795,12 +795,12 @@ static struct ast_channel *jingle_new(struct jingle *client, struct jingle_pvt *
fmt = ast_best_codec(tmp->nativeformats);
if (i->rtp) {
- tmp->fds[0] = ast_rtp_fd(i->rtp);
- tmp->fds[1] = ast_rtcp_fd(i->rtp);
+ ast_channel_set_fd(tmp, 0, ast_rtp_fd(i->rtp));
+ ast_channel_set_fd(tmp, 1, ast_rtcp_fd(i->rtp));
}
if (i->vrtp) {
- tmp->fds[2] = ast_rtp_fd(i->vrtp);
- tmp->fds[3] = ast_rtcp_fd(i->vrtp);
+ ast_channel_set_fd(tmp, 2, ast_rtp_fd(i->vrtp));
+ ast_channel_set_fd(tmp, 3, ast_rtcp_fd(i->vrtp));
}
if (state == AST_STATE_RING)
tmp->rings = 1;
diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c
index ddb811ed3..198c964ad 100644
--- a/channels/chan_mgcp.c
+++ b/channels/chan_mgcp.c
@@ -1456,7 +1456,7 @@ static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state)
fmt = ast_best_codec(tmp->nativeformats);
ast_string_field_build(tmp, name, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
if (sub->rtp)
- tmp->fds[0] = ast_rtp_fd(sub->rtp);
+ ast_channel_set_fd(tmp, 0, ast_rtp_fd(sub->rtp));
if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
i->dsp = ast_dsp_new();
ast_dsp_set_features(i->dsp,DSP_FEATURE_DTMF_DETECT);
@@ -2588,7 +2588,7 @@ static void start_rtp(struct mgcp_subchannel *sub)
/* Allocate the RTP now */
sub->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
if (sub->rtp && sub->owner)
- sub->owner->fds[0] = ast_rtp_fd(sub->rtp);
+ ast_channel_set_fd(sub->owner, 0, ast_rtp_fd(sub->rtp));
if (sub->rtp)
ast_rtp_setnat(sub->rtp, sub->nat);
#if 0
diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c
index 61a4198b1..ad4d5a5a9 100644
--- a/channels/chan_misdn.c
+++ b/channels/chan_misdn.c
@@ -3220,7 +3220,7 @@ static struct ast_channel *misdn_new(struct chan_list *chlist, int state, char
if (pipe(chlist->pipe) < 0)
ast_log(LOG_ERROR, "Pipe failed\n");
- tmp->fds[0] = chlist->pipe[0];
+ ast_channel_set_fd(tmp, 0, chlist->pipe[0]);
if (state == AST_STATE_RING)
tmp->rings = 1;
diff --git a/channels/chan_nbs.c b/channels/chan_nbs.c
index 1c342c6fd..d2718b3de 100644
--- a/channels/chan_nbs.c
+++ b/channels/chan_nbs.c
@@ -232,7 +232,7 @@ static struct ast_channel *nbs_new(struct nbs_pvt *i, int state)
tmp = ast_channel_alloc(1, state, 0, 0, "", "s", context, 0, "NBS/%s", i->stream);
if (tmp) {
tmp->tech = &nbs_tech;
- tmp->fds[0] = nbs_fd(i->nbs);
+ ast_channel_set_fd(tmp, 0, nbs_fd(i->nbs));
tmp->nativeformats = prefformat;
tmp->rawreadformat = prefformat;
tmp->rawwriteformat = prefformat;
diff --git a/channels/chan_oss.c b/channels/chan_oss.c
index 9dc2fca86..317873759 100644
--- a/channels/chan_oss.c
+++ b/channels/chan_oss.c
@@ -692,7 +692,7 @@ static int setformat(struct chan_oss_pvt *o, int mode)
return -1;
}
if (o->owner)
- o->owner->fds[0] = fd;
+ ast_channel_set_fd(o->owner, 0, fd);
#if __BYTE_ORDER == __LITTLE_ENDIAN
fmt = AFMT_S16_LE;
@@ -1026,7 +1026,7 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx,
c->tech = &oss_tech;
if (o->sounddev < 0)
setformat(o, O_RDWR);
- c->fds[0] = o->sounddev; /* -1 if device closed, override later */
+ ast_channel_set_fd(c, 0, o->sounddev); /* -1 if device closed, override later */
c->nativeformats = AST_FORMAT_SLINEAR;
c->readformat = AST_FORMAT_SLINEAR;
c->writeformat = AST_FORMAT_SLINEAR;
diff --git a/channels/chan_phone.c b/channels/chan_phone.c
index a3f82bb5b..6a51b6dd6 100644
--- a/channels/chan_phone.c
+++ b/channels/chan_phone.c
@@ -855,7 +855,7 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *conte
tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "", i->ext, i->context, 0, "Phone/%s", i->dev + 5);
if (tmp) {
tmp->tech = cur_tech;
- tmp->fds[0] = i->fd;
+ ast_channel_set_fd(tmp, 0, i->fd);
/* XXX Switching formats silently causes kernel panics XXX */
if (i->mode == MODE_FXS &&
ioctl(i->fd, PHONE_QUERY_CODEC, &codec) == 0) {
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index f6681709e..8800a60ba 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -4553,18 +4553,18 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
ast_dsp_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
}
if (i->rtp) {
- tmp->fds[0] = ast_rtp_fd(i->rtp);
- tmp->fds[1] = ast_rtcp_fd(i->rtp);
+ ast_channel_set_fd(tmp, 0, ast_rtp_fd(i->rtp));
+ ast_channel_set_fd(tmp, 1, ast_rtcp_fd(i->rtp));
}
if (needvideo && i->vrtp) {
- tmp->fds[2] = ast_rtp_fd(i->vrtp);
- tmp->fds[3] = ast_rtcp_fd(i->vrtp);
+ ast_channel_set_fd(tmp, 2, ast_rtp_fd(i->vrtp));
+ ast_channel_set_fd(tmp, 3, ast_rtcp_fd(i->vrtp));
}
if (needtext && i->trtp) {
- tmp->fds[4] = ast_rtp_fd(i->trtp);
+ ast_channel_set_fd(tmp, 4, ast_rtp_fd(i->trtp));
}
if (i->udptl) {
- tmp->fds[5] = ast_udptl_fd(i->udptl);
+ ast_channel_set_fd(tmp, 5, ast_udptl_fd(i->udptl));
}
if (state == AST_STATE_RING)
tmp->rings = 1;
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index bc1e73322..c11643805 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -2515,12 +2515,12 @@ static void start_rtp(struct skinny_subchannel *sub)
sub->vrtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
if (sub->rtp && sub->owner) {
- sub->owner->fds[0] = ast_rtp_fd(sub->rtp);
- sub->owner->fds[1] = ast_rtcp_fd(sub->rtp);
+ ast_channel_set_fd(sub->owner, 0, ast_rtp_fd(sub->rtp));
+ ast_channel_set_fd(sub->owner, 1, ast_rtcp_fd(sub->rtp));
}
if (hasvideo && sub->vrtp && sub->owner) {
- sub->owner->fds[2] = ast_rtp_fd(sub->vrtp);
- sub->owner->fds[3] = ast_rtcp_fd(sub->vrtp);
+ ast_channel_set_fd(sub->owner, 2, ast_rtp_fd(sub->vrtp));
+ ast_channel_set_fd(sub->owner, 3, ast_rtcp_fd(sub->vrtp));
}
if (sub->rtp) {
ast_rtp_setnat(sub->rtp, l->nat);
@@ -3070,7 +3070,7 @@ static struct ast_channel *skinny_new(struct skinny_line *l, int state)
if (skinnydebug)
ast_verbose("skinny_new: tmp->nativeformats=%d fmt=%d\n", tmp->nativeformats, fmt);
if (sub->rtp) {
- tmp->fds[0] = ast_rtp_fd(sub->rtp);
+ ast_channel_set_fd(tmp, 0, ast_rtp_fd(sub->rtp));
}
if (state == AST_STATE_RING) {
tmp->rings = 1;
diff --git a/channels/chan_zap.c b/channels/chan_zap.c
index fbad1ac90..1426f456a 100644
--- a/channels/chan_zap.c
+++ b/channels/chan_zap.c
@@ -1013,9 +1013,9 @@ static void swap_subs(struct zt_pvt *p, int a, int b)
p->subs[b].inthreeway = tinthreeway;
if (p->subs[a].owner)
- p->subs[a].owner->fds[0] = p->subs[a].zfd;
+ ast_channel_set_fd(p->subs[a].owner, 0, p->subs[a].zfd);
if (p->subs[b].owner)
- p->subs[b].owner->fds[0] = p->subs[b].zfd;
+ ast_channel_set_fd(p->subs[b].owner, 0, p->subs[b].zfd);
wakeup_sub(p, a, NULL);
wakeup_sub(p, b, NULL);
}
@@ -2595,7 +2595,7 @@ static int pri_assign_bearer(struct zt_pvt *crv, struct zt_pri *pri, struct zt_p
bearer->realcall = crv;
crv->subs[SUB_REAL].zfd = bearer->subs[SUB_REAL].zfd;
if (crv->subs[SUB_REAL].owner)
- crv->subs[SUB_REAL].owner->fds[0] = crv->subs[SUB_REAL].zfd;
+ ast_channel_set_fd(crv->subs[SUB_REAL].owner, 0, crv->subs[SUB_REAL].zfd);
crv->bearer = bearer;
crv->call = bearer->call;
crv->pri = pri;
@@ -5515,7 +5515,7 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
else
deflaw = AST_FORMAT_ULAW;
}
- tmp->fds[0] = i->subs[index].zfd;
+ ast_channel_set_fd(tmp, 0, i->subs[index].zfd);
tmp->nativeformats = AST_FORMAT_SLINEAR | deflaw;
/* Start out assuming ulaw since it's smaller :) */
tmp->rawreadformat = deflaw;
@@ -8977,7 +8977,7 @@ static int pri_fixup_principle(struct zt_pri *pri, int principle, q931_call *c)
"Zap/%d:%d-%d", pri->trunkgroup,
pri->pvts[principle]->channel, 1);
pri->pvts[principle]->owner->tech_pvt = pri->pvts[principle];
- pri->pvts[principle]->owner->fds[0] = pri->pvts[principle]->subs[SUB_REAL].zfd;
+ ast_channel_set_fd(pri->pvts[principle]->owner, 0, pri->pvts[principle]->subs[SUB_REAL].zfd);
pri->pvts[principle]->subs[SUB_REAL].owner = pri->pvts[x]->subs[SUB_REAL].owner;
} else
ast_log(LOG_WARNING, "Whoa, there's no owner, and we're having to fix up channel %d to channel %d\n", pri->pvts[x]->channel, pri->pvts[principle]->channel);
diff --git a/configure b/configure
index 2a6cf3a59..41c9ec77d 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
#! /bin/sh
-# From configure.ac Revision: 77878 .
+# From configure.ac Revision: 60612 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.61.
#
@@ -15624,6 +15624,60 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
+{ echo "$as_me:$LINENO: checking for working epoll support" >&5
+echo $ECHO_N "checking for working epoll support... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/epoll.h>
+int
+main ()
+{
+epoll_create(10);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_EPOLL 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+
{ echo "$as_me:$LINENO: checking for compiler atomic operations" >&5
echo $ECHO_N "checking for compiler atomic operations... $ECHO_C" >&6; }
cat >conftest.$ac_ext <<_ACEOF
diff --git a/configure.ac b/configure.ac
index c4093ff56..40ee8c11f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -332,6 +332,14 @@ fi
AST_C_DEFINE_CHECK([PTHREAD_RWLOCK_INITIALIZER], [PTHREAD_RWLOCK_INITIALIZER], [pthread.h])
AST_C_DEFINE_CHECK([PTHREAD_RWLOCK_PREFER_WRITER_NP], [PTHREAD_RWLOCK_PREFER_WRITER_NP], [pthread.h])
+AC_MSG_CHECKING(for working epoll support)
+AC_LINK_IFELSE(
+AC_LANG_PROGRAM([#include <sys/epoll.h>], [epoll_create(10);]),
+AC_MSG_RESULT(yes)
+AC_DEFINE([HAVE_EPOLL], 1, [Define to 1 if your system has working epoll support.]),
+AC_MSG_RESULT(no)
+)
+
AC_MSG_CHECKING(for compiler atomic operations)
AC_LINK_IFELSE(
AC_LANG_PROGRAM([], [int foo1; int foo2 = __sync_fetch_and_add(&foo1, 1);]),
diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in
index 1031ee8ab..0facfe2be 100644
--- a/include/asterisk/autoconfig.h.in
+++ b/include/asterisk/autoconfig.h.in
@@ -114,6 +114,9 @@
/* Define to 1 if you have the `endpwent' function. */
#undef HAVE_ENDPWENT
+/* Define to 1 if your system has working epoll support. */
+#undef HAVE_EPOLL
+
/* Define this to indicate the ${EXP10_DESCRIP} library */
#undef HAVE_EXP10
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 39f2c636d..b58880853 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -316,6 +316,8 @@ struct ast_channel_tech {
int (* func_channel_write)(struct ast_channel *chan, const char *function, char *data, const char *value);
};
+struct ast_epoll_data;
+
/*!
* The high bit of the frame count is used as a debug marker, so
* increments of the counters must be done with care.
@@ -490,6 +492,11 @@ struct ast_channel {
/*! \brief Data stores on the channel */
AST_LIST_HEAD_NOLOCK(datastores, ast_datastore) datastores;
+
+#ifdef HAVE_EPOLL
+ int epfd;
+ struct ast_epoll_data *epfd_data[AST_MAX_FDS];
+#endif
};
/*! \brief ast_channel_tech Properties */
@@ -1184,6 +1191,15 @@ void ast_deactivate_generator(struct ast_channel *chan);
void ast_set_callerid(struct ast_channel *chan, const char *cidnum, const char *cidname, const char *ani);
+/*! Set the file descriptor on the channel */
+void ast_channel_set_fd(struct ast_channel *chan, int which, int fd);
+
+/*! Add a channel to an optimized waitfor */
+void ast_poll_channel_add(struct ast_channel *chan0, struct ast_channel *chan1);
+
+/*! Delete a channel from an optimized waitfor */
+void ast_poll_channel_del(struct ast_channel *chan0, struct ast_channel *chan1);
+
/*! Start a tone going */
int ast_tonepair_start(struct ast_channel *chan, int freq1, int freq2, int duration, int vol);
/*! Stop a tone from playing */
diff --git a/main/channel.c b/main/channel.c
index 3f3ce9466..26f9da5f7 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -67,6 +67,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/slinfactory.h"
#include "asterisk/audiohook.h"
+#ifdef HAVE_EPOLL
+#include <sys/epoll.h>
+#endif
+
+struct ast_epoll_data {
+ struct ast_channel *chan;
+ int which;
+};
+
/* uncomment if you have problems with 'monitoring' synchronized files */
#if 0
#define MONITOR_CONSTANT_DELAY
@@ -631,11 +640,16 @@ struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_
return NULL;
}
- /* 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++)
+#ifdef HAVE_EPOLL
+ tmp->epfd = epoll_create(25);
+#endif
+
+ for (x = 0; x < AST_MAX_FDS; x++) {
tmp->fds[x] = -1;
+#ifdef HAVE_EPOLL
+ tmp->epfd_data[x] = NULL;
+#endif
+ }
#ifdef HAVE_ZAPTEL
tmp->timingfd = open("/dev/zap/timer", O_RDWR);
@@ -666,9 +680,9 @@ struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_
tmp->alertpipe[0] = tmp->alertpipe[1] = -1;
/* Always watch the alertpipe */
- tmp->fds[AST_ALERT_FD] = tmp->alertpipe[0];
+ ast_channel_set_fd(tmp, AST_ALERT_FD, tmp->alertpipe[0]);
/* And timing pipe */
- tmp->fds[AST_TIMING_FD] = tmp->timingfd;
+ ast_channel_set_fd(tmp, AST_TIMING_FD, tmp->timingfd);
ast_string_field_set(tmp, name, "**Unknown**");
/* Initial state */
@@ -1065,6 +1079,9 @@ static void free_cid(struct ast_callerid *cid)
void ast_channel_free(struct ast_channel *chan)
{
int fd;
+#ifdef HAVE_EPOLL
+ int i;
+#endif
struct ast_var_t *vardata;
struct ast_frame *f;
struct varshead *headp;
@@ -1116,6 +1133,13 @@ void ast_channel_free(struct ast_channel *chan)
close(fd);
if ((fd = chan->timingfd) > -1)
close(fd);
+#ifdef HAVE_EPOLL
+ for (i = 0; i < AST_MAX_FDS; i++) {
+ if (chan->epfd_data[i])
+ free(chan->epfd_data[i]);
+ }
+ close(chan->epfd);
+#endif
while ((f = AST_LIST_REMOVE_HEAD(&chan->readq, frame_list)))
ast_frfree(f);
@@ -1256,6 +1280,83 @@ struct ast_datastore *ast_channel_datastore_find(struct ast_channel *chan, const
return datastore;
}
+/*! Set the file descriptor on the channel */
+void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
+{
+#ifdef HAVE_EPOLL
+ struct epoll_event ev;
+ struct ast_epoll_data *aed = NULL;
+
+ if (chan->fds[which] > -1) {
+ epoll_ctl(chan->epfd, EPOLL_CTL_DEL, chan->fds[which], &ev);
+ aed = chan->epfd_data[which];
+ }
+
+ /* If this new fd is valid, add it to the epoll */
+ if (fd > -1) {
+ if (!aed && (!(aed = ast_calloc(1, sizeof(*aed)))))
+ return;
+
+ chan->epfd_data[which] = aed;
+ aed->chan = chan;
+ aed->which = which;
+
+ ev.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
+ ev.data.ptr = aed;
+ epoll_ctl(chan->epfd, EPOLL_CTL_ADD, fd, &ev);
+ } else if (aed) {
+ /* We don't have to keep around this epoll data structure now */
+ free(aed);
+ chan->epfd_data[which] = NULL;
+ }
+#endif
+ chan->fds[which] = fd;
+ return;
+}
+
+/*! Add a channel to an optimized waitfor */
+void ast_poll_channel_add(struct ast_channel *chan0, struct ast_channel *chan1)
+{
+#ifdef HAVE_EPOLL
+ struct epoll_event ev;
+ int i = 0;
+
+ if (chan0->epfd == -1)
+ return;
+
+ /* Iterate through the file descriptors on chan1, adding them to chan0 */
+ for (i = 0; i < AST_MAX_FDS; i++) {
+ if (chan1->fds[i] == -1)
+ continue;
+ ev.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
+ ev.data.ptr = chan1->epfd_data[i];
+ epoll_ctl(chan0->epfd, EPOLL_CTL_ADD, chan1->fds[i], &ev);
+ }
+
+#endif
+ return;
+}
+
+/*! Delete a channel from an optimized waitfor */
+void ast_poll_channel_del(struct ast_channel *chan0, struct ast_channel *chan1)
+{
+#ifdef HAVE_EPOLL
+ struct epoll_event ev;
+ int i = 0;
+
+ if (chan0->epfd == -1)
+ return;
+
+ for (i = 0; i < AST_MAX_FDS; i++) {
+ if (chan1->fds[i] == -1)
+ continue;
+ epoll_ctl(chan0->epfd, EPOLL_CTL_DEL, chan1->fds[i], &ev);
+ }
+
+#endif
+ return;
+}
+
/*! \brief Softly hangup a channel, don't lock */
int ast_softhangup_nolock(struct ast_channel *chan, int cause)
{
@@ -1437,7 +1538,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_channel_set_fd(chan, AST_GENERATOR_FD, -1);
ast_clear_flag(chan, AST_FLAG_WRITE_INT);
ast_settimeout(chan, 0, NULL, NULL);
}
@@ -1499,8 +1600,13 @@ int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
}
/*! \brief Wait for x amount of time on a file descriptor to have input. */
+#ifdef HAVE_EPOLL
+static struct ast_channel *ast_waitfor_nandfds_classic(struct ast_channel **c, int n, int *fds, int nfds,
+ int *exception, int *outfd, int *ms)
+#else
struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds,
- int *exception, int *outfd, int *ms)
+ int *exception, int *outfd, int *ms)
+#endif
{
struct timeval start = { 0 , 0 };
struct pollfd *pfds;
@@ -1526,15 +1632,13 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
*exception = 0;
/* Perform any pending masquerades */
- for (x=0; x < n; x++) {
+ for (x = 0; x < n; x++) {
ast_channel_lock(c[x]);
- if (c[x]->masq) {
- if (ast_do_masquerade(c[x])) {
- ast_log(LOG_WARNING, "Masquerade failed\n");
- *ms = -1;
- ast_channel_unlock(c[x]);
- return NULL;
- }
+ if (c[x]->masq && ast_do_masquerade(c[x])) {
+ ast_log(LOG_WARNING, "Masquerade failed\n");
+ *ms = -1;
+ ast_channel_unlock(c[x]);
+ return NULL;
}
if (c[x]->whentohangup) {
if (!whentohangup)
@@ -1564,8 +1668,8 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
* 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++) {
+ 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]);
@@ -1573,7 +1677,7 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
CHECK_BLOCKING(c[x]);
}
/* Add the individual fds */
- for (x=0; x<nfds; x++) {
+ for (x = 0; x < nfds; x++) {
fdmap[max].chan = -1;
max += ast_add_fd(&pfds[max], fds[x]);
}
@@ -1593,7 +1697,7 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
} else {
res = poll(pfds, max, rms);
}
- for (x=0; x<n; x++)
+ for (x = 0; x < n; x++)
ast_clear_flag(c[x], AST_FLAG_BLOCKING);
if (res < 0) { /* Simulate a timeout if we were interrupted */
if (errno != EINTR)
@@ -1602,7 +1706,7 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
}
if (whentohangup) { /* if we have a timeout, check who expired */
time(&now);
- for (x=0; x<n; x++) {
+ for (x = 0; x < n; x++) {
if (c[x]->whentohangup && now >= c[x]->whentohangup) {
c[x]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
if (winner == NULL)
@@ -1646,6 +1750,200 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
return winner;
}
+#ifdef HAVE_EPOLL
+static struct ast_channel *ast_waitfor_nandfds_simple(struct ast_channel *chan, int *ms)
+{
+ struct timeval start = { 0 , 0 };
+ int res = 0;
+ struct epoll_event ev[1];
+ long whentohangup = 0, rms = *ms;
+ time_t now;
+ struct ast_channel *winner = NULL;
+ struct ast_epoll_data *aed = NULL;
+
+ ast_channel_lock(chan);
+
+ /* See if this channel needs to be masqueraded */
+ if (chan->masq && ast_do_masquerade(chan)) {
+ ast_log(LOG_WARNING, "Failed to perform masquerade on %s\n", chan->name);
+ *ms = -1;
+ ast_channel_unlock(chan);
+ return NULL;
+ }
+
+ /* Figure out their timeout */
+ if (chan->whentohangup) {
+ time(&now);
+ if ((whentohangup = chan->whentohangup - now) < 1) {
+ /* They should already be hungup! */
+ chan->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
+ ast_channel_unlock(chan);
+ return NULL;
+ }
+ /* If this value is smaller then the current one... make it priority */
+ whentohangup *= 1000;
+ if (rms > whentohangup)
+ rms = whentohangup;
+ }
+
+ ast_channel_unlock(chan);
+
+ /* Time to make this channel block... */
+ CHECK_BLOCKING(chan);
+
+ if (*ms > 0)
+ start = ast_tvnow();
+
+ /* We don't have to add any file descriptors... they are already added, we just have to wait! */
+ res = epoll_wait(chan->epfd, ev, 1, rms);
+
+ /* Stop blocking */
+ ast_clear_flag(chan, AST_FLAG_BLOCKING);
+
+ /* Simulate a timeout if we were interrupted */
+ if (res < 0) {
+ if (errno != EINTR)
+ *ms = -1;
+ return NULL;
+ }
+
+ /* If this channel has a timeout see if it expired */
+ if (chan->whentohangup) {
+ time(&now);
+ if (now >= chan->whentohangup) {
+ chan->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
+ winner = chan;
+ }
+ }
+
+ /* No fd ready, reset timeout and be done for now */
+ if (!res) {
+ *ms = 0;
+ return winner;
+ }
+
+ /* See what events are pending */
+ aed = ev[0].data.ptr;
+ chan->fdno = aed->which;
+ if (ev[0].events & EPOLLPRI)
+ ast_set_flag(chan, AST_FLAG_EXCEPTION);
+ else
+ ast_clear_flag(chan, AST_FLAG_EXCEPTION);
+
+ if (*ms > 0) {
+ *ms -= ast_tvdiff_ms(ast_tvnow(), start);
+ if (*ms < 0)
+ *ms = 0;
+ }
+
+ return chan;
+}
+
+static struct ast_channel *ast_waitfor_nandfds_complex(struct ast_channel **c, int n, int *ms)
+{
+ struct timeval start = { 0 , 0 };
+ int res = 0, i;
+ struct epoll_event ev[25] = { { 0, } };
+ long whentohangup = 0, diff, rms = *ms;
+ time_t now;
+ struct ast_channel *winner = NULL;
+
+ for (i = 0; i < n; i++) {
+ ast_channel_lock(c[i]);
+ if (c[i]->masq && ast_do_masquerade(c[i])) {
+ ast_log(LOG_WARNING, "Masquerade failed\n");
+ *ms = -1;
+ ast_channel_unlock(c[i]);
+ return NULL;
+ }
+ if (c[i]->whentohangup) {
+ if (!whentohangup)
+ time(&now);
+ if ((diff = c[i]->whentohangup - now) < 1) {
+ c[i]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
+ ast_channel_unlock(c[i]);
+ return c[i];
+ }
+ if (!whentohangup || (diff < whentohangup))
+ whentohangup = diff;
+ }
+ ast_channel_unlock(c[i]);
+ CHECK_BLOCKING(c[i]);
+ }
+
+ rms = *ms;
+ if (whentohangup) {
+ rms = whentohangup * 1000;
+ if (*ms >= 0 && *ms < rms)
+ rms = *ms;
+ }
+
+ if (*ms > 0)
+ start = ast_tvnow();
+
+ res = epoll_wait(c[0]->epfd, ev, 25, rms);
+
+ for (i = 0; i < n; i++)
+ ast_clear_flag(c[i], AST_FLAG_BLOCKING);
+
+ if (res < 0) {
+ if (errno != EINTR)
+ *ms = -1;
+ return NULL;
+ }
+
+ if (whentohangup) {
+ time(&now);
+ for (i = 0; i < n; i++) {
+ if (c[i]->whentohangup && now >= c[i]->whentohangup) {
+ c[i]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
+ if (!winner)
+ winner = c[i];
+ }
+ }
+ }
+
+ if (!res) {
+ *ms = 0;
+ return winner;
+ }
+
+ for (i = 0; i < 25; i++) {
+ struct ast_epoll_data *aed = ev[i].data.ptr;
+
+ if (!ev[i].events || !aed)
+ continue;
+
+ winner = aed->chan;
+ if (ev[i].events & EPOLLPRI)
+ ast_set_flag(winner, AST_FLAG_EXCEPTION);
+ else
+ ast_clear_flag(winner, AST_FLAG_EXCEPTION);
+ winner->fdno = aed->which;
+ }
+
+ if (*ms > 0) {
+ *ms -= ast_tvdiff_ms(ast_tvnow(), start);
+ if (*ms < 0)
+ *ms = 0;
+ }
+
+ return winner;
+}
+
+struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds,
+ int *exception, int *outfd, int *ms)
+{
+ /* If no epoll file descriptor is available resort to classic nandfds */
+ if (!n || nfds || c[0]->epfd == -1)
+ return ast_waitfor_nandfds_classic(c, n, fds, nfds, exception, outfd, ms);
+ else if (!nfds && n == 1)
+ return ast_waitfor_nandfds_simple(c[0], ms);
+ else
+ return ast_waitfor_nandfds_complex(c, n, ms);
+}
+#endif
+
struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
{
return ast_waitfor_nandfds(c, n, NULL, 0, NULL, NULL, ms);
@@ -3259,7 +3557,7 @@ int ast_do_masquerade(struct ast_channel *original)
/* Copy the FD's other than the generator fd */
for (x = 0; x < AST_MAX_FDS; x++) {
if (x != AST_GENERATOR_FD)
- original->fds[x] = clone->fds[x];
+ ast_channel_set_fd(original, x, clone->fds[x]);
}
ast_app_group_update(clone, original);
@@ -3290,7 +3588,7 @@ int ast_do_masquerade(struct ast_channel *original)
clone->cid = tmpcid;
/* Restore original timing file descriptor */
- original->fds[AST_TIMING_FD] = original->timingfd;
+ ast_channel_set_fd(original, AST_TIMING_FD, original->timingfd);
/* Our native formats are different now */
original->nativeformats = clone->nativeformats;
@@ -3487,6 +3785,8 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
/* Check the need of a jitterbuffer for each channel */
jb_in_use = ast_jb_do_usecheck(c0, c1);
+ ast_poll_channel_add(c0, c1);
+
for (;;) {
struct ast_channel *who, *other;
@@ -3591,11 +3891,16 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
/* XXX do we want to pass on also frames not matched above ? */
ast_frfree(f);
+#ifndef HAVE_EPOLL
/* Swap who gets priority */
cs[2] = cs[0];
cs[0] = cs[1];
cs[1] = cs[2];
+#endif
}
+
+ ast_poll_channel_del(c0, c1);
+
return res;
}
diff --git a/main/rtp.c b/main/rtp.c
index d8d99012f..465755afe 100644
--- a/main/rtp.c
+++ b/main/rtp.c
@@ -3212,6 +3212,8 @@ static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct
ast_channel_unlock(c0);
ast_channel_unlock(c1);
+ ast_poll_channel_add(c0, c1);
+
/* Throw our channels into the structure and enter the loop */
cs[0] = c0;
cs[1] = c1;
@@ -3228,6 +3230,7 @@ static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct
if (c1->tech_pvt == pvt1)
if (pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0, 0))
ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
+ ast_poll_channel_del(c0, c1);
return AST_BRIDGE_RETRY;
}
@@ -3313,6 +3316,7 @@ static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct
if (c1->tech_pvt == pvt1)
if (pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0, 0))
ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
+ ast_poll_channel_del(c0, c1);
return AST_BRIDGE_COMPLETE;
} else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
if ((fr->subclass == AST_CONTROL_HOLD) ||
@@ -3353,11 +3357,15 @@ static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct
ast_frfree(fr);
}
/* Swap priority */
+#ifndef HAVE_EPOLL
cs[2] = cs[0];
cs[0] = cs[1];
cs[1] = cs[2];
+#endif
}
+ ast_poll_channel_del(c0, c1);
+
if (pr0->set_rtp_peer(c0, NULL, NULL, NULL, 0, 0))
ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
if (pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0, 0))
@@ -3488,6 +3496,8 @@ static enum ast_bridge_result bridge_p2p_loop(struct ast_channel *c0, struct ast
ast_channel_unlock(c0);
ast_channel_unlock(c1);
+ ast_poll_channel_add(c0, c1);
+
/* Go into a loop forwarding frames until we don't need to anymore */
cs[0] = c0;
cs[1] = c1;
@@ -3591,6 +3601,8 @@ static enum ast_bridge_result bridge_p2p_loop(struct ast_channel *c0, struct ast
p2p_set_bridge(p0, NULL);
p2p_set_bridge(p1, NULL);
+ ast_poll_channel_del(c0, c1);
+
return res;
}