diff options
Diffstat (limited to 'main/channel.c')
-rw-r--r-- | main/channel.c | 336 |
1 files changed, 20 insertions, 316 deletions
diff --git a/main/channel.c b/main/channel.c index 15c7fa406..31f363938 100644 --- a/main/channel.c +++ b/main/channel.c @@ -78,21 +78,12 @@ /*** DOCUMENTATION ***/ -#ifdef HAVE_EPOLL -#include <sys/epoll.h> -#endif - #if defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED) #if defined(HAVE_PRI) #include "libpri.h" #endif /* defined(HAVE_PRI) */ #endif /* defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED) */ -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 @@ -850,10 +841,6 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char ast_channel_internal_alertpipe_clear(tmp); ast_channel_internal_fd_clear_all(tmp); -#ifdef HAVE_EPOLL - ast_channel_epfd_set(tmp, epoll_create(25)); -#endif - if (!(schedctx = ast_sched_context_create())) { ast_log(LOG_WARNING, "Channel allocation failed: Unable to create schedule context\n"); /* See earlier channel creation abort comment above. */ @@ -1058,9 +1045,6 @@ struct ast_channel *__ast_dummy_channel_alloc(const char *file, int line, const ast_channel_timingfd_set(tmp, -1); ast_channel_internal_alertpipe_clear(tmp); ast_channel_internal_fd_clear_all(tmp); -#ifdef HAVE_EPOLL - ast_channel_epfd_set(tmp, -1); -#endif ast_channel_hold_state_set(tmp, AST_CONTROL_UNHOLD); @@ -2223,9 +2207,6 @@ void ast_party_redirecting_free(struct ast_party_redirecting *doomed) static void ast_channel_destructor(void *obj) { struct ast_channel *chan = obj; -#ifdef HAVE_EPOLL - int i; -#endif struct ast_var_t *vardata; struct ast_frame *f; struct varshead *headp; @@ -2323,14 +2304,6 @@ static void ast_channel_destructor(void *obj) ast_timer_close(ast_channel_timer(chan)); ast_channel_timer_set(chan, NULL); } -#ifdef HAVE_EPOLL - for (i = 0; i < AST_MAX_FDS; i++) { - if (ast_channel_internal_epfd_data(chan, i)) { - ast_free(ast_channel_internal_epfd_data(chan, i)); - } - } - close(ast_channel_epfd(chan)); -#endif while ((f = AST_LIST_REMOVE_HEAD(ast_channel_readq(chan), frame_list))) ast_frfree(f); @@ -2481,82 +2454,10 @@ struct ast_datastore *ast_channel_datastore_find(struct ast_channel *chan, const /*! 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 (ast_channel_fd_isset(chan, which)) { - epoll_ctl(ast_channel_epfd(chan), EPOLL_CTL_DEL, ast_channel_fd(chan, which), &ev); - aed = ast_channel_internal_epfd_data(chan, which); - } - - /* If this new fd is valid, add it to the epoll */ - if (fd > -1) { - if (!aed && (!(aed = ast_calloc(1, sizeof(*aed))))) - return; - - ast_channel_internal_epfd_data_set(chan, which, aed); - aed->chan = chan; - aed->which = which; - - ev.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP; - ev.data.ptr = aed; - epoll_ctl(ast_channel_epfd(chan), EPOLL_CTL_ADD, fd, &ev); - } else if (aed) { - /* We don't have to keep around this epoll data structure now */ - ast_free(aed); - ast_channel_epfd_data_set(chan, which, NULL); - } -#endif ast_channel_internal_fd_set(chan, 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 (ast_channel_epfd(chan0) == -1) - return; - - /* Iterate through the file descriptors on chan1, adding them to chan0 */ - for (i = 0; i < AST_MAX_FDS; i++) { - if (!ast_channel_fd_isset(chan1, i)) { - continue; - } - ev.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP; - ev.data.ptr = ast_channel_internal_epfd_data(chan1, i); - epoll_ctl(ast_channel_epfd(chan0), EPOLL_CTL_ADD, ast_channel_fd(chan1, 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 (ast_channel_epfd(chan0) == -1) - return; - - for (i = 0; i < AST_MAX_FDS; i++) { - if (!ast_channel_fd_isset(chan1, i)) { - continue; - } - epoll_ctl(ast_channel_epfd(chan0), EPOLL_CTL_DEL, ast_channel_fd(chan1, i), &ev); - } - -#endif - return; -} - void ast_channel_clear_softhangup(struct ast_channel *chan, int flag) { ast_channel_lock(chan); @@ -3061,20 +2962,15 @@ 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) -#endif { struct timeval start = { 0 , 0 }; struct pollfd *pfds = NULL; int res; long rms; int x, y, max; - int sz; + int sz = nfds; struct timeval now = { 0, 0 }; struct timeval whentohangup = { 0, 0 }, diff; struct ast_channel *winner = NULL; @@ -3090,14 +2986,6 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, *exception = 0; } - if ((sz = n * AST_MAX_FDS + nfds)) { - pfds = ast_alloca(sizeof(*pfds) * sz); - fdmap = ast_alloca(sizeof(*fdmap) * sz); - } else { - /* nothing to allocate and no FDs to check */ - return NULL; - } - for (x = 0; x < n; x++) { ast_channel_lock(c[x]); if (!ast_tvzero(*ast_channel_whentohangup(c[x]))) { @@ -3114,8 +3002,17 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, if (ast_tvzero(whentohangup) || ast_tvcmp(diff, whentohangup) < 0) whentohangup = diff; } + sz += ast_channel_fd_count(c[x]); ast_channel_unlock(c[x]); } + + if (!sz) { + return NULL; + } + + pfds = ast_alloca(sizeof(*pfds) * sz); + fdmap = ast_alloca(sizeof(*fdmap) * sz); + /* Wait full interval */ rms = *ms; /* INT_MAX, not LONG_MAX, because it matters on 64-bit */ @@ -3135,12 +3032,12 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, */ max = 0; for (x = 0; x < n; x++) { - for (y = 0; y < AST_MAX_FDS; y++) { + ast_channel_lock(c[x]); + for (y = 0; y < ast_channel_fd_count(c[x]); 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], ast_channel_fd(c[x], y)); } - ast_channel_lock(c[x]); CHECK_BLOCKING(c[x]); ast_channel_unlock(c[x]); } @@ -3234,205 +3131,6 @@ 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 diff, rms = *ms; - struct ast_channel *winner = NULL; - struct ast_epoll_data *aed = NULL; - - ast_channel_lock(chan); - /* Figure out their timeout */ - if (!ast_tvzero(*ast_channel_whentohangup(chan))) { - if ((diff = ast_tvdiff_ms(*ast_channel_whentohangup(chan), ast_tvnow())) < 0) { - /* They should already be hungup! */ - ast_channel_softhangup_internal_flag_add(chan, AST_SOFTHANGUP_TIMEOUT); - ast_channel_unlock(chan); - return NULL; - } - /* If this value is smaller then the current one... make it priority */ - if (rms > diff) { - rms = diff; - } - } - - 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(ast_channel_epfd(chan), ev, 1, rms); - - /* Stop blocking */ - ast_clear_flag(ast_channel_flags(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 (!ast_tvzero(*ast_channel_whentohangup(chan))) { - if (ast_tvdiff_ms(ast_tvnow(), *ast_channel_whentohangup(chan)) >= 0) { - ast_channel_softhangup_internal_flag_add(chan, 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; - ast_channel_fdno_set(chan, aed->which); - if (ev[0].events & EPOLLPRI) { - ast_set_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION); - } else { - ast_clear_flag(ast_channel_flags(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, } }; - struct timeval now = { 0, 0 }; - long whentohangup = 0, diff = 0, rms = *ms; - struct ast_channel *winner = NULL; - - for (i = 0; i < n; i++) { - ast_channel_lock(c[i]); - if (!ast_tvzero(*ast_channel_whentohangup(c[i]))) { - if (whentohangup == 0) { - now = ast_tvnow(); - } - if ((diff = ast_tvdiff_ms(*ast_channel_whentohangup(c[i]), now)) < 0) { - ast_channel_softhangup_internal_flag_add(c[i], AST_SOFTHANGUP_TIMEOUT); - ast_channel_unlock(c[i]); - return c[i]; - } - if (!whentohangup || whentohangup > diff) { - whentohangup = diff; - } - } - ast_channel_unlock(c[i]); - CHECK_BLOCKING(c[i]); - } - - rms = *ms; - if (whentohangup) { - rms = whentohangup; - if (*ms >= 0 && *ms < rms) { - rms = *ms; - } - } - - if (*ms > 0) { - start = ast_tvnow(); - } - - res = epoll_wait(ast_channel_epfd(c[0]), ev, 25, rms); - - for (i = 0; i < n; i++) { - ast_clear_flag(ast_channel_flags(c[i]), AST_FLAG_BLOCKING); - } - - if (res < 0) { - if (errno != EINTR) { - *ms = -1; - } - return NULL; - } - - if (whentohangup) { - now = ast_tvnow(); - for (i = 0; i < n; i++) { - if (!ast_tvzero(*ast_channel_whentohangup(c[i])) && ast_tvdiff_ms(now, *ast_channel_whentohangup(c[i])) >= 0) { - ast_channel_softhangup_internal_flag_add(c[i], AST_SOFTHANGUP_TIMEOUT); - if (!winner) { - winner = c[i]; - } - } - } - } - - if (!res) { - *ms = 0; - return winner; - } - - for (i = 0; i < res; 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(ast_channel_flags(winner), AST_FLAG_EXCEPTION); - } else { - ast_clear_flag(ast_channel_flags(winner), AST_FLAG_EXCEPTION); - } - ast_channel_fdno_set(winner, 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) -{ - /* Clear all provided values in one place. */ - if (outfd) { - *outfd = -99999; - } - if (exception) { - *exception = 0; - } - - /* If no epoll file descriptor is available resort to classic nandfds */ - if (!n || nfds || ast_channel_epfd(c[0]) == -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); @@ -6852,6 +6550,7 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann int origstate; unsigned int orig_disablestatecache; unsigned int clone_disablestatecache; + int generator_fd; int visible_indication; int clone_hold_state; int moh_is_playing; @@ -7042,8 +6741,13 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann /* Keep the same parkinglot. */ ast_channel_parkinglot_set(original, ast_channel_parkinglot(clonechan)); - /* Copy the FD's other than the generator fd */ - for (x = 0; x < AST_MAX_FDS; x++) { + /* Clear all existing file descriptors but retain the generator */ + generator_fd = ast_channel_fd(original, AST_GENERATOR_FD); + ast_channel_internal_fd_clear_all(original); + ast_channel_set_fd(original, AST_GENERATOR_FD, generator_fd); + + /* Copy all file descriptors present on clonechan to original, skipping generator */ + for (x = 0; x < ast_channel_fd_count(clonechan); x++) { if (x != AST_GENERATOR_FD) ast_channel_set_fd(original, x, ast_channel_fd(clonechan, x)); } |