diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index dba0de514798e6552d5559667dc2d4f3b36eefb0..1a0b4fc18105b8c9dbfc9ec9f48a1e6767d9ea4d 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -300,6 +300,7 @@ static void softmix_bridge_data_destroy(void *obj) if (softmix_data->timer) { ast_timer_close(softmix_data->timer); + softmix_data->timer = NULL; } } @@ -885,7 +886,11 @@ static int softmix_bridge_thread(struct ast_bridge *bridge) softmix_translate_helper_cleanup(&trans_helper); /* Wait for the timing source to tell us to wake up and get things done */ ast_waitfor_n_fd(&timingfd, 1, &timeout, NULL); - ast_timer_ack(timer, 1); + if (ast_timer_ack(timer, 1) < 0) { + ast_log(LOG_ERROR, "Failed to acknowledge timer in softmix bridge\n"); + ao2_lock(bridge); + goto softmix_cleanup; + } ao2_lock(bridge); /* make sure to detect mixing interval changes if they occur. */ diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 602511424e66c077c953a8a33a269ec7c2de84b3..272ad832b4a68999a327c6e3da0b69cf639272e0 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -9253,8 +9253,11 @@ static int timing_read(int *id, int fd, short events, void *cbdata) if (iaxtrunkdebug) ast_verbose("Beginning trunk processing. Trunk queue ceiling is %d bytes per host\n", trunkmaxsize); - if (timer) { - ast_timer_ack(timer, 1); + if (timer) { + if (ast_timer_ack(timer, 1) < 0) { + ast_log(LOG_ERROR, "Timer failed acknowledge\n"); + return 0; + } } /* For each peer that supports trunking... */ @@ -12372,7 +12375,9 @@ static void *network_thread(void *ignore) /* Wake up once a second just in case SIGURG was sent while * we weren't in poll(), to make sure we don't hang when trying * to unload. */ - ast_io_wait(io, 1000); + if (ast_io_wait(io, 1000) <= 0) { + break; + } } return NULL; @@ -14591,6 +14596,7 @@ static int __unload_module(void) ao2_ref(callno_pool_trunk, -1); if (timer) { ast_timer_close(timer); + timer = NULL; } transmit_processor = ast_taskprocessor_unreference(transmit_processor); ast_sched_context_destroy(sched); @@ -14976,6 +14982,7 @@ static int load_module(void) if (set_config(config, 0, 0) == -1) { if (timer) { ast_timer_close(timer); + timer = NULL; } return AST_MODULE_LOAD_DECLINE; } diff --git a/funcs/func_jitterbuffer.c b/funcs/func_jitterbuffer.c index ca3de59e249e9d42c8833d586df9744adb6b05db..066d9d2f626ec9c8b1e6dd0c98409eb11b5a3f7b 100644 --- a/funcs/func_jitterbuffer.c +++ b/funcs/func_jitterbuffer.c @@ -219,7 +219,10 @@ static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_fram } if (ast_channel_fdno(chan) == AST_JITTERBUFFER_FD && framedata->timer) { - ast_timer_ack(framedata->timer, 1); + if (ast_timer_ack(framedata->timer, 1) < 0) { + ast_log(LOG_ERROR, "Failed to acknowledge timer in jitter buffer\n"); + return frame; + } } if (!frame) { diff --git a/include/asterisk/timing.h b/include/asterisk/timing.h index 3f4da48ef0e6032341df059da5d06d433f0cc9b6..9cbb0eba10c0f2831435eca7889859dd60a116af 100644 --- a/include/asterisk/timing.h +++ b/include/asterisk/timing.h @@ -74,7 +74,7 @@ struct ast_timing_interface { int (*timer_open)(void); void (*timer_close)(int handle); int (*timer_set_rate)(int handle, unsigned int rate); - void (*timer_ack)(int handle, unsigned int quantity); + int (*timer_ack)(int handle, unsigned int quantity); int (*timer_enable_continuous)(int handle); int (*timer_disable_continuous)(int handle); enum ast_timer_event (*timer_get_event)(int handle); @@ -163,10 +163,11 @@ int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate); * \note This function should only be called if timer_get_event() * returned AST_TIMING_EVENT_EXPIRED. * - * \return nothing - * \since 1.6.1 + * \retval -1 failure, with errno set + * \retval 0 success + * \since 10.5.2 */ -void ast_timer_ack(const struct ast_timer *handle, unsigned int quantity); +int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity); /*! * \brief Enable continuous mode diff --git a/main/channel.c b/main/channel.c index 861dbf0e234aff1ef9588d1ce18a5c7897e48e9c..b0622fa9c4c6d2ed427d606fe29c41a4186f8a2c 100644 --- a/main/channel.c +++ b/main/channel.c @@ -2431,6 +2431,7 @@ static void ast_channel_destructor(void *obj) ast_channel_internal_alertpipe_close(chan); if (ast_channel_timer(chan)) { ast_timer_close(ast_channel_timer(chan)); + ast_channel_timer_set(chan, NULL); } #ifdef HAVE_EPOLL for (i = 0; i < AST_MAX_FDS; i++) { @@ -3940,7 +3941,10 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) switch (res) { case AST_TIMING_EVENT_EXPIRED: - ast_timer_ack(ast_channel_timer(chan), 1); + if (ast_timer_ack(ast_channel_timer(chan), 1) < 0) { + ast_log(LOG_ERROR, "Failed to acknoweldge timer in ast_read\n"); + goto done; + } if (ast_channel_timingfunc(chan)) { /* save a copy of func/data before unlocking the channel */ diff --git a/main/timing.c b/main/timing.c index c237d0899f7473a2d12938136d7c261ed7423353..f2211d484d7b0faf8a032cff9d7bdefea59865ee 100644 --- a/main/timing.c +++ b/main/timing.c @@ -150,6 +150,7 @@ struct ast_timer *ast_timer_open(void) void ast_timer_close(struct ast_timer *handle) { handle->holder->iface->timer_close(handle->fd); + handle->fd = -1; ast_module_unref(handle->holder->mod); ast_free(handle); } @@ -168,9 +169,13 @@ int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate) return res; } -void ast_timer_ack(const struct ast_timer *handle, unsigned int quantity) +int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity) { - handle->holder->iface->timer_ack(handle->fd, quantity); + int res = -1; + + res = handle->holder->iface->timer_ack(handle->fd, quantity); + + return res; } int ast_timer_enable_continuous(const struct ast_timer *handle) @@ -269,7 +274,11 @@ static char *timing_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args * if (res == 1) { count++; - ast_timer_ack(timer, 1); + if (ast_timer_ack(timer, 1) < 0) { + ast_cli(a->fd, "Timer failed to acknowledge.\n"); + ast_timer_close(timer); + return CLI_FAILURE; + } } else if (!res) { ast_cli(a->fd, "poll() timed out! This is bad.\n"); } else if (errno != EAGAIN && errno != EINTR) { @@ -278,6 +287,7 @@ static char *timing_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args * } ast_timer_close(timer); + timer = NULL; ast_cli(a->fd, "It has been %" PRIi64 " milliseconds, and we got %d timer ticks\n", ast_tvdiff_ms(end, start), count); diff --git a/res/res_fax_spandsp.c b/res/res_fax_spandsp.c index 901ec48c04f570e94404bf27d0dfc1b3a1b61cdb..906f13aa83f2eb1850d7c8c3050c99c463ec4464 100644 --- a/res/res_fax_spandsp.c +++ b/res/res_fax_spandsp.c @@ -181,7 +181,7 @@ static void session_destroy(struct spandsp_pvt *p) p->isdone = 1; ast_timer_close(p->timer); - + p->timer = NULL; fax_release(&p->fax_state); t38_terminal_release(&p->t38_state); @@ -611,7 +611,10 @@ static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s) struct ast_frame *f = &fax_frame; ast_format_set(&fax_frame.subclass.format, AST_FORMAT_SLINEAR, 0); - ast_timer_ack(p->timer, 1); + if (ast_timer_ack(p->timer, 1) < 0) { + ast_log(LOG_ERROR, "Failed to acknowledge timer for FAX session '%d'\n", s->id); + return NULL; + } /* XXX do we need to lock here? */ if (p->isdone) { diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index b71fb9c4350210985086ff4c1c00a7cb40e82397..130618431fbaa0fbd590e5815199f93d210f7b33 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -699,7 +699,10 @@ static void *monmp3thread(void *data) #endif /* Pause some amount of time */ if (ast_poll(&pfd, 1, -1) > 0) { - ast_timer_ack(class->timer, 1); + if (ast_timer_ack(class->timer, 1) < 0) { + ast_log(LOG_ERROR, "Failed to acknowledge timer for mp3player\n"); + return NULL; + } res = 320; } else { ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno)); diff --git a/res/res_timing_dahdi.c b/res/res_timing_dahdi.c index 7aafe796675dbcfeaa85ab01ec09218e86d8fc12..6298253b774695d583c75c975ff112e20468816e 100644 --- a/res/res_timing_dahdi.c +++ b/res/res_timing_dahdi.c @@ -48,7 +48,7 @@ static void *timing_funcs_handle; static int dahdi_timer_open(void); static void dahdi_timer_close(int handle); static int dahdi_timer_set_rate(int handle, unsigned int rate); -static void dahdi_timer_ack(int handle, unsigned int quantity); +static int dahdi_timer_ack(int handle, unsigned int quantity); static int dahdi_timer_enable_continuous(int handle); static int dahdi_timer_disable_continuous(int handle); static enum ast_timer_event dahdi_timer_get_event(int handle); @@ -94,9 +94,9 @@ static int dahdi_timer_set_rate(int handle, unsigned int rate) return 0; } -static void dahdi_timer_ack(int handle, unsigned int quantity) +static int dahdi_timer_ack(int handle, unsigned int quantity) { - ioctl(handle, DAHDI_TIMERACK, &quantity); + return ioctl(handle, DAHDI_TIMERACK, &quantity) ? -1 : 0; } static int dahdi_timer_enable_continuous(int handle) diff --git a/res/res_timing_kqueue.c b/res/res_timing_kqueue.c index 67ab0ba38a4396f3a03bfd16efb7299c15cf2796..b5bc01f3f22ec67fb573d9b375ae46173feeed7c 100644 --- a/res/res_timing_kqueue.c +++ b/res/res_timing_kqueue.c @@ -51,7 +51,7 @@ static void *timing_funcs_handle; static int kqueue_timer_open(void); static void kqueue_timer_close(int handle); static int kqueue_timer_set_rate(int handle, unsigned int rate); -static void kqueue_timer_ack(int handle, unsigned int quantity); +static int kqueue_timer_ack(int handle, unsigned int quantity); static int kqueue_timer_enable_continuous(int handle); static int kqueue_timer_disable_continuous(int handle); static enum ast_timer_event kqueue_timer_get_event(int handle); @@ -197,20 +197,25 @@ static int kqueue_timer_set_rate(int handle, unsigned int rate) return 0; } -static void kqueue_timer_ack(int handle, unsigned int quantity) +static int kqueue_timer_ack(int handle, unsigned int quantity) { struct kqueue_timer *our_timer; if (!(our_timer = lookup_timer(handle))) { - return; + return -1; } if (our_timer->unacked < quantity) { ast_debug(1, "Acking more events than have expired?!!\n"); our_timer->unacked = 0; + ao2_ref(our_timer, -1); + return -1; } else { our_timer->unacked -= quantity; } + + ao2_ref(our_timer, -1); + return 0; } static int kqueue_timer_enable_continuous(int handle) diff --git a/res/res_timing_pthread.c b/res/res_timing_pthread.c index 654f1d082943d0346b0e812041f81faf2c4cb9aa..aa37885e2ec9621603c35d55739d925218e03b7c 100644 --- a/res/res_timing_pthread.c +++ b/res/res_timing_pthread.c @@ -47,7 +47,7 @@ static void *timing_funcs_handle; static int pthread_timer_open(void); static void pthread_timer_close(int handle); static int pthread_timer_set_rate(int handle, unsigned int rate); -static void pthread_timer_ack(int handle, unsigned int quantity); +static int pthread_timer_ack(int handle, unsigned int quantity); static int pthread_timer_enable_continuous(int handle); static int pthread_timer_disable_continuous(int handle); static enum ast_timer_event pthread_timer_get_event(int handle); @@ -97,7 +97,7 @@ struct pthread_timer { static void pthread_timer_destructor(void *obj); static struct pthread_timer *find_timer(int handle, int unlinkobj); static void write_byte(struct pthread_timer *timer); -static void read_pipe(struct pthread_timer *timer, unsigned int num); +static int read_pipe(struct pthread_timer *timer, unsigned int num); /*! * \brief Data for the timing thread @@ -190,21 +190,24 @@ static int pthread_timer_set_rate(int handle, unsigned int rate) return 0; } -static void pthread_timer_ack(int handle, unsigned int quantity) +static int pthread_timer_ack(int handle, unsigned int quantity) { struct pthread_timer *timer; + int res; ast_assert(quantity > 0); if (!(timer = find_timer(handle, 0))) { - return; + return -1; } ao2_lock(timer); - read_pipe(timer, quantity); + res = read_pipe(timer, quantity); ao2_unlock(timer); ao2_ref(timer, -1); + + return res; } static int pthread_timer_enable_continuous(int handle) @@ -240,7 +243,12 @@ static int pthread_timer_disable_continuous(int handle) ao2_lock(timer); if (timer->continuous) { timer->continuous = 0; - read_pipe(timer, 1); + if (read_pipe(timer, 1) != 0) { + /* Let the errno from read_pipe propagate up */ + ao2_unlock(timer); + ao2_ref(timer, -1); + return -1; + } } ao2_unlock(timer); @@ -358,8 +366,10 @@ static int check_timer(struct pthread_timer *timer) /*! * \internal * \pre timer is locked + * \retval 0 if nothing to read or read success + * \retval -1 on error */ -static void read_pipe(struct pthread_timer *timer, unsigned int quantity) +static int read_pipe(struct pthread_timer *timer, unsigned int quantity) { int rd_fd = timer->pipe[PIPE_READ]; int pending_ticks = timer->pending_ticks; @@ -375,7 +385,7 @@ static void read_pipe(struct pthread_timer *timer, unsigned int quantity) } if (!quantity) { - return; + return 0; } do { @@ -389,7 +399,7 @@ static void read_pipe(struct pthread_timer *timer, unsigned int quantity) if (ast_poll(&pfd, 1, 0) != 1) { ast_debug(1, "Reading not available on timing pipe, " "quantity: %u\n", quantity); - break; + return -1; } res = read(rd_fd, buf, @@ -401,12 +411,14 @@ static void read_pipe(struct pthread_timer *timer, unsigned int quantity) } ast_log(LOG_ERROR, "read failed on timing pipe: %s\n", strerror(errno)); - break; + return -1; } quantity -= res; timer->pending_ticks -= res; } while (quantity); + + return 0; } /*! diff --git a/res/res_timing_timerfd.c b/res/res_timing_timerfd.c index 944687459aa068c0fe53ab50b9a61a50d107788a..5c96dd6620b610ef9ef1a9cdb9f72768a14e44aa 100644 --- a/res/res_timing_timerfd.c +++ b/res/res_timing_timerfd.c @@ -44,7 +44,7 @@ static void *timing_funcs_handle; static int timerfd_timer_open(void); static void timerfd_timer_close(int handle); static int timerfd_timer_set_rate(int handle, unsigned int rate); -static void timerfd_timer_ack(int handle, unsigned int quantity); +static int timerfd_timer_ack(int handle, unsigned int quantity); static int timerfd_timer_enable_continuous(int handle); static int timerfd_timer_disable_continuous(int handle); static enum ast_timer_event timerfd_timer_get_event(int handle); @@ -91,6 +91,7 @@ static void timer_destroy(void *obj) { struct timerfd_timer *timer = obj; close(timer->handle); + timer->handle = -1; } static int timerfd_timer_open(void) @@ -121,6 +122,11 @@ static void timerfd_timer_close(int handle) .handle = handle, }; + if (handle == -1) { + ast_log(LOG_ERROR, "Attempting to close timerfd handle -1"); + return; + } + if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) { ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle); return; @@ -137,6 +143,11 @@ static int timerfd_timer_set_rate(int handle, unsigned int rate) }; int res = 0; + if (handle == -1) { + ast_log(LOG_ERROR, "Attempting to set rate on timerfd handle -1"); + return -1; + } + if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) { ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle); return -1; @@ -158,17 +169,23 @@ static int timerfd_timer_set_rate(int handle, unsigned int rate) return res; } -static void timerfd_timer_ack(int handle, unsigned int quantity) +static int timerfd_timer_ack(int handle, unsigned int quantity) { uint64_t expirations; int read_result = 0; + int res = 0; struct timerfd_timer *our_timer, find_helper = { .handle = handle, }; + if (handle == -1) { + ast_log(LOG_ERROR, "Attempting to ack timerfd handle -1"); + return -1; + } + if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) { ast_log(LOG_ERROR, "Couldn't find a timer with handle %d\n", handle); - return; + return -1; } ao2_lock(our_timer); @@ -177,8 +194,9 @@ static void timerfd_timer_ack(int handle, unsigned int quantity) struct itimerspec timer_status; if (timerfd_gettime(handle, &timer_status)) { - ast_log(LOG_ERROR, "Call to timerfd_gettime() error: %s\n", strerror(errno)); + ast_log(LOG_ERROR, "Call to timerfd_gettime() using handle %d error: %s\n", handle, strerror(errno)); expirations = 0; + res = -1; break; } @@ -194,6 +212,7 @@ static void timerfd_timer_ack(int handle, unsigned int quantity) continue; } else { ast_log(LOG_ERROR, "Read error: %s\n", strerror(errno)); + res = -1; break; } } @@ -205,6 +224,7 @@ static void timerfd_timer_ack(int handle, unsigned int quantity) if (expirations != quantity) { ast_debug(2, "Expected to acknowledge %u ticks but got %llu instead\n", quantity, (unsigned long long) expirations); } + return res; } static int timerfd_timer_enable_continuous(int handle) @@ -217,6 +237,11 @@ static int timerfd_timer_enable_continuous(int handle) .handle = handle, }; + if (handle == -1) { + ast_log(LOG_ERROR, "Attempting to enable timerfd handle -1"); + return -1; + } + if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) { ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle); return -1; @@ -246,13 +271,18 @@ static int timerfd_timer_disable_continuous(int handle) .handle = handle, }; + if (handle == -1) { + ast_log(LOG_ERROR, "Attempting to disable timerfd handle -1"); + return -1; + } + if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) { ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle); return -1; } ao2_lock(our_timer); - if(!our_timer->is_continuous) { + if (!our_timer->is_continuous) { /* No reason to do anything if we're not * in continuous mode */ @@ -276,6 +306,11 @@ static enum ast_timer_event timerfd_timer_get_event(int handle) .handle = handle, }; + if (handle == -1) { + ast_log(LOG_ERROR, "Attempting to get event from timerfd handle -1"); + return -1; + } + if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) { ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle); return -1;