Improve timing interface to remember which provider provided a timer

The ability to load/unload timing interfaces is nice, but it means that when a timer is allocated, it may come from provider A, but later provider B becomes the 'preferred' provider. If this happens, all timer API calls on the timer that was provided by provider A will actually be handed to provider B, which will say WTF and return an error.

This patch changes the timer API to include a pointer to the provider of the timer handle so that future operations on the timer will be forwarded to the proper provider.

(closes issue #14697)
Reported by: moy

Review: http://reviewboard.digium.com/r/211/



git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@184762 65c4cc65-6c06-0410-ace0-fbb531ad65f3
certified/1.8.6
Kevin P. Fleming 17 years ago
parent f745326750
commit 9381bff79d

@ -85,13 +85,13 @@ struct softmix_channel {
/*! \brief Function called when a bridge is created */ /*! \brief Function called when a bridge is created */
static int softmix_bridge_create(struct ast_bridge *bridge) static int softmix_bridge_create(struct ast_bridge *bridge)
{ {
int timingfd; struct ast_timer *timer;
if ((timingfd = ast_timer_open()) < 0) { if (!(timer = ast_timer_open())) {
return -1; return -1;
} }
bridge->bridge_pvt = (void*)(unsigned long)timingfd; bridge->bridge_pvt = timer;
return 0; return 0;
} }
@ -99,9 +99,7 @@ static int softmix_bridge_create(struct ast_bridge *bridge)
/*! \brief Function called when a bridge is destroyed */ /*! \brief Function called when a bridge is destroyed */
static int softmix_bridge_destroy(struct ast_bridge *bridge) static int softmix_bridge_destroy(struct ast_bridge *bridge)
{ {
int timingfd = (unsigned long)bridge->bridge_pvt; ast_timer_close((struct ast_timer *) bridge->bridge_pvt);
ast_timer_close(timingfd);
return 0; return 0;
} }
@ -209,9 +207,10 @@ static int softmix_bridge_poke(struct ast_bridge *bridge, struct ast_bridge_chan
/*! \brief Function which acts as the mixing thread */ /*! \brief Function which acts as the mixing thread */
static int softmix_bridge_thread(struct ast_bridge *bridge) static int softmix_bridge_thread(struct ast_bridge *bridge)
{ {
int timingfd = (unsigned long)bridge->bridge_pvt; struct ast_timer *timer = (struct ast_timer *) bridge->bridge_pvt;
int timingfd = ast_timer_fd(timer);
ast_timer_set_rate(timingfd, (1000 / SOFTMIX_INTERVAL)); ast_timer_set_rate(timer, (1000 / SOFTMIX_INTERVAL));
while (!bridge->stop && !bridge->refresh && bridge->array_num) { while (!bridge->stop && !bridge->refresh && bridge->array_num) {
struct ast_bridge_channel *bridge_channel = NULL; struct ast_bridge_channel *bridge_channel = NULL;
@ -268,7 +267,7 @@ static int softmix_bridge_thread(struct ast_bridge *bridge)
/* Wait for the timing source to tell us to wake up and get things done */ /* Wait for the timing source to tell us to wake up and get things done */
ast_waitfor_n_fd(&timingfd, 1, &timeout, NULL); ast_waitfor_n_fd(&timingfd, 1, &timeout, NULL);
ast_timer_ack(timingfd, 1); ast_timer_ack(timer, 1);
ao2_lock(bridge); ao2_lock(bridge);
} }

@ -257,7 +257,7 @@ static int max_reg_expire;
static int srvlookup = 0; static int srvlookup = 0;
static int timingfd = -1; /* Timing file descriptor */ static struct ast_timer *timer; /* Timer for trunking */
static struct ast_netsock_list *netsock; static struct ast_netsock_list *netsock;
static struct ast_netsock_list *outsock; /*!< used if sourceaddress specified and bindaddr == INADDR_ANY */ static struct ast_netsock_list *outsock; /*!< used if sourceaddress specified and bindaddr == INADDR_ANY */
@ -7717,8 +7717,8 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
if (iaxtrunkdebug) if (iaxtrunkdebug)
ast_verbose("Beginning trunk processing. Trunk queue ceiling is %d bytes per host\n", trunkmaxsize); ast_verbose("Beginning trunk processing. Trunk queue ceiling is %d bytes per host\n", trunkmaxsize);
if (timingfd > -1) { if (timer) {
ast_timer_ack(timingfd, 1); ast_timer_ack(timer, 1);
} }
/* For each peer that supports trunking... */ /* For each peer that supports trunking... */
@ -10500,8 +10500,8 @@ static void *network_thread(void *ignore)
int res, count, wakeup; int res, count, wakeup;
struct iax_frame *f; struct iax_frame *f;
if (timingfd > -1) if (timer)
ast_io_add(io, timingfd, timing_read, AST_IO_IN | AST_IO_PRI, NULL); ast_io_add(io, ast_timer_fd(timer), timing_read, AST_IO_IN | AST_IO_PRI, NULL);
for(;;) { for(;;) {
pthread_testcancel(); pthread_testcancel();
@ -10809,7 +10809,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
ast_string_field_set(peer, dbsecret, v->value); ast_string_field_set(peer, dbsecret, v->value);
} else if (!strcasecmp(v->name, "trunk")) { } else if (!strcasecmp(v->name, "trunk")) {
ast_set2_flag(peer, ast_true(v->value), IAX_TRUNK); ast_set2_flag(peer, ast_true(v->value), IAX_TRUNK);
if (ast_test_flag(peer, IAX_TRUNK) && (timingfd < 0)) { if (ast_test_flag(peer, IAX_TRUNK) && !timer) {
ast_log(LOG_WARNING, "Unable to support trunking on peer '%s' without a timing interface\n", peer->name); ast_log(LOG_WARNING, "Unable to support trunking on peer '%s' without a timing interface\n", peer->name);
ast_clear_flag(peer, IAX_TRUNK); ast_clear_flag(peer, IAX_TRUNK);
} }
@ -11076,7 +11076,7 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st
ast_parse_allow_disallow(&user->prefs, &user->capability,v->value, 0); ast_parse_allow_disallow(&user->prefs, &user->capability,v->value, 0);
} else if (!strcasecmp(v->name, "trunk")) { } else if (!strcasecmp(v->name, "trunk")) {
ast_set2_flag(user, ast_true(v->value), IAX_TRUNK); ast_set2_flag(user, ast_true(v->value), IAX_TRUNK);
if (ast_test_flag(user, IAX_TRUNK) && (timingfd < 0)) { if (ast_test_flag(user, IAX_TRUNK) && !timer) {
ast_log(LOG_WARNING, "Unable to support trunking on user '%s' without a timing interface\n", user->name); ast_log(LOG_WARNING, "Unable to support trunking on user '%s' without a timing interface\n", user->name);
ast_clear_flag(user, IAX_TRUNK); ast_clear_flag(user, IAX_TRUNK);
} }
@ -12486,8 +12486,8 @@ static int __unload_module(void)
ao2_ref(users, -1); ao2_ref(users, -1);
ao2_ref(iax_peercallno_pvts, -1); ao2_ref(iax_peercallno_pvts, -1);
ao2_ref(iax_transfercallno_pvts, -1); ao2_ref(iax_transfercallno_pvts, -1);
if (timingfd > -1) { if (timer) {
ast_timer_close(timingfd); ast_timer_close(timer);
} }
con = ast_context_find(regcontext); con = ast_context_find(regcontext);
@ -12627,9 +12627,8 @@ static int load_module(void)
ast_manager_register( "IAXnetstats", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_netstats, "Show IAX Netstats" ); ast_manager_register( "IAXnetstats", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_netstats, "Show IAX Netstats" );
ast_manager_register( "IAXregistry", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_registry, "Show IAX registrations"); ast_manager_register( "IAXregistry", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_registry, "Show IAX registrations");
timingfd = ast_timer_open(); if ((timer = ast_timer_open())) {
if (timingfd > -1) { ast_timer_set_rate(timer, trunkfreq);
ast_timer_set_rate(timingfd, trunkfreq);
} }
if (set_config(config, 0) == -1) { if (set_config(config, 0) == -1) {

@ -496,6 +496,7 @@ struct ast_channel {
char unused_old_dtmfq[AST_MAX_EXTENSION]; /*!< (deprecated, use readq instead) Any/all queued DTMF characters */ char unused_old_dtmfq[AST_MAX_EXTENSION]; /*!< (deprecated, use readq instead) Any/all queued DTMF characters */
struct { struct {
struct ast_bridge *bridge; /*!< Bridge this channel is participating in */ struct ast_bridge *bridge; /*!< Bridge this channel is participating in */
struct ast_timer *timer; /*!< timer object that provided timingfd */
}; };
}; };

@ -45,9 +45,6 @@
4) Multiple 'event types', so that the code using the timer can 4) Multiple 'event types', so that the code using the timer can
know whether the wakeup it received was due to a periodic trigger know whether the wakeup it received was due to a periodic trigger
or a continuous trigger. or a continuous trigger.
\todo Create an implementation of this API for Linux based on the
following API: http://www.kernel.org/doc/man-pages/online/pages/man2/timerfd_create.2.html
*/ */
#ifndef _ASTERISK_TIMING_H #ifndef _ASTERISK_TIMING_H
@ -96,7 +93,7 @@ struct ast_timing_interface {
*/ */
#define ast_register_timing_interface(i) _ast_register_timing_interface(i, ast_module_info->self) #define ast_register_timing_interface(i) _ast_register_timing_interface(i, ast_module_info->self)
void *_ast_register_timing_interface(struct ast_timing_interface *funcs, void *_ast_register_timing_interface(struct ast_timing_interface *funcs,
struct ast_module *mod); struct ast_module *mod);
/*! /*!
* \brief Unregister a previously registered timing interface. * \brief Unregister a previously registered timing interface.
@ -110,45 +107,57 @@ void *_ast_register_timing_interface(struct ast_timing_interface *funcs,
*/ */
int ast_unregister_timing_interface(void *handle); int ast_unregister_timing_interface(void *handle);
struct ast_timer;
/*! /*!
* \brief Open a timing fd * \brief Open a timer
* *
* \retval -1 error, with errno set * \retval NULL on error, with errno set
* \retval >=0 success * \retval non-NULL timer handle on success
* \since 1.6.1 * \since 1.6.1
*/ */
int ast_timer_open(void); struct ast_timer *ast_timer_open(void);
/*! /*!
* \brief Close an opened timing handle * \brief Close an opened timing handle
* *
* \param handle timing fd returned from timer_open() * \param handle timer handle returned from timer_open()
* *
* \return nothing * \return nothing
* \since 1.6.1 * \since 1.6.1
*/ */
void ast_timer_close(int handle); void ast_timer_close(struct ast_timer *handle);
/*!
* \brief Get a poll()-able file descriptor for a timer
*
* \param handle timer handle returned from timer_open()
*
* \return file descriptor which can be used with poll() to wait for events
* \since 1.6.1
*/
int ast_timer_fd(const struct ast_timer *handle);
/*! /*!
* \brief Set the timing tick rate * \brief Set the timing tick rate
* *
* \param handle timing fd returned from timer_open() * \param handle timer handle returned from timer_open()
* \param rate ticks per second, 0 turns the ticks off if needed * \param rate ticks per second, 0 turns the ticks off if needed
* *
* Use this function if you want the timing fd to show input at a certain * Use this function if you want the timer to show input at a certain
* rate. The other alternative use of a timing fd, is using the continuous * rate. The other alternative use of a timer is the continuous
* mode. * mode.
* *
* \retval -1 error, with errno set * \retval -1 error, with errno set
* \retval 0 success * \retval 0 success
* \since 1.6.1 * \since 1.6.1
*/ */
int ast_timer_set_rate(int handle, unsigned int rate); int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate);
/*! /*!
* \brief Acknowledge a timer event * \brief Acknowledge a timer event
* *
* \param handle timing fd returned from timer_open() * \param handle timer handle returned from timer_open()
* \param quantity number of timer events to acknowledge * \param quantity number of timer events to acknowledge
* *
* \note This function should only be called if timer_get_event() * \note This function should only be called if timer_get_event()
@ -157,55 +166,55 @@ int ast_timer_set_rate(int handle, unsigned int rate);
* \return nothing * \return nothing
* \since 1.6.1 * \since 1.6.1
*/ */
void ast_timer_ack(int handle, unsigned int quantity); void ast_timer_ack(const struct ast_timer *handle, unsigned int quantity);
/*! /*!
* \brief Enable continuous mode * \brief Enable continuous mode
* *
* \param handle timing fd returned from timer_open() * \param handle timer handle returned from timer_open()
* *
* Continuous mode causes poll() on the timing fd to immediately return * Continuous mode causes poll() on the timer's fd to immediately return
* always until continuous mode is disabled. * always until continuous mode is disabled.
* *
* \retval -1 failure, with errno set * \retval -1 failure, with errno set
* \retval 0 success * \retval 0 success
* \since 1.6.1 * \since 1.6.1
*/ */
int ast_timer_enable_continuous(int handle); int ast_timer_enable_continuous(const struct ast_timer *handle);
/*! /*!
* \brief Disable continuous mode * \brief Disable continuous mode
* *
* \param handle timing fd returned from timer_close() * \param handle timer handle returned from timer_close()
* *
* \retval -1 failure, with errno set * \retval -1 failure, with errno set
* \retval 0 success * \retval 0 success
* \since 1.6.1 * \since 1.6.1
*/ */
int ast_timer_disable_continuous(int handle); int ast_timer_disable_continuous(const struct ast_timer *handle);
/*! /*!
* \brief Determine timing event * \brief Retrieve timing event
* *
* \param handle timing fd returned by timer_open() * \param handle timer handle returned by timer_open()
* *
* After poll() indicates that there is input on the timing fd, this will * After poll() indicates that there is input on the timer's fd, this will
* be called to find out what triggered it. * be called to find out what triggered it.
* *
* \return which event triggered the timing fd * \return which event triggered the timer
* \since 1.6.1 * \since 1.6.1
*/ */
enum ast_timer_event ast_timer_get_event(int handle); enum ast_timer_event ast_timer_get_event(const struct ast_timer *handle);
/*! /*!
* \brief Get maximum rate supported for a timing handle * \brief Get maximum rate supported for a timer
* *
* \param handle timing fd returned by timer_open() * \param handle timer handle returned by timer_open()
* *
* \return maximum rate supported for timing handle * \return maximum rate supported by timer
* \since 1.6.1 * \since 1.6.1
*/ */
unsigned int ast_timer_get_max_rate(int handle); unsigned int ast_timer_get_max_rate(const struct ast_timer *handle);
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
} }

@ -807,17 +807,19 @@ struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_
#endif #endif
} }
tmp->timingfd = ast_timer_open(); if ((tmp->timer = ast_timer_open())) {
if (tmp->timingfd > -1) {
needqueue = 0; needqueue = 0;
tmp->timingfd = ast_timer_fd(tmp->timer);
} else {
tmp->timingfd = -1;
} }
if (needqueue) { if (needqueue) {
if (pipe(tmp->alertpipe)) { if (pipe(tmp->alertpipe)) {
ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe!\n"); ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe!\n");
alertpipe_failed: alertpipe_failed:
if (tmp->timingfd > -1) { if (tmp->timer) {
ast_timer_close(tmp->timingfd); ast_timer_close(tmp->timer);
} }
sched_context_destroy(tmp->sched); sched_context_destroy(tmp->sched);
@ -1010,7 +1012,7 @@ static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, in
chan->name, f->frametype, f->subclass, qlen, strerror(errno)); chan->name, f->frametype, f->subclass, qlen, strerror(errno));
} }
} else if (chan->timingfd > -1) { } else if (chan->timingfd > -1) {
ast_timer_enable_continuous(chan->timingfd); ast_timer_enable_continuous(chan->timer);
} else if (ast_test_flag(chan, AST_FLAG_BLOCKING)) { } else if (ast_test_flag(chan, AST_FLAG_BLOCKING)) {
pthread_kill(chan->blocker, SIGURG); pthread_kill(chan->blocker, SIGURG);
} }
@ -1378,8 +1380,9 @@ void ast_channel_free(struct ast_channel *chan)
close(fd); close(fd);
if ((fd = chan->alertpipe[1]) > -1) if ((fd = chan->alertpipe[1]) > -1)
close(fd); close(fd);
if ((fd = chan->timingfd) > -1) if (chan->timer) {
ast_timer_close(fd); ast_timer_close(chan->timer);
}
#ifdef HAVE_EPOLL #ifdef HAVE_EPOLL
for (i = 0; i < AST_MAX_FDS; i++) { for (i = 0; i < AST_MAX_FDS; i++) {
if (chan->epfd_data[i]) if (chan->epfd_data[i])
@ -2325,13 +2328,13 @@ int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const v
data = NULL; data = NULL;
} }
if (rate && rate > (max_rate = ast_timer_get_max_rate(c->timingfd))) { if (rate && rate > (max_rate = ast_timer_get_max_rate(c->timer))) {
real_rate = max_rate; real_rate = max_rate;
} }
ast_debug(1, "Scheduling timer at (%u requested / %u actual) timer ticks per second\n", rate, real_rate); ast_debug(1, "Scheduling timer at (%u requested / %u actual) timer ticks per second\n", rate, real_rate);
res = ast_timer_set_rate(c->timingfd, real_rate); res = ast_timer_set_rate(c->timer, real_rate);
c->timingfunc = func; c->timingfunc = func;
c->timingdata = data; c->timingdata = data;
@ -2584,11 +2587,11 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
ast_clear_flag(chan, AST_FLAG_EXCEPTION); ast_clear_flag(chan, AST_FLAG_EXCEPTION);
res = ast_timer_get_event(chan->timingfd); res = ast_timer_get_event(chan->timer);
switch (res) { switch (res) {
case AST_TIMING_EVENT_EXPIRED: case AST_TIMING_EVENT_EXPIRED:
ast_timer_ack(chan->timingfd, 1); ast_timer_ack(chan->timer, 1);
if (chan->timingfunc) { if (chan->timingfunc) {
/* save a copy of func/data before unlocking the channel */ /* save a copy of func/data before unlocking the channel */
@ -2598,7 +2601,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
ast_channel_unlock(chan); ast_channel_unlock(chan);
func(data); func(data);
} else { } else {
ast_timer_set_rate(chan->timingfd, 0); ast_timer_set_rate(chan->timer, 0);
chan->fdno = -1; chan->fdno = -1;
ast_channel_unlock(chan); ast_channel_unlock(chan);
} }
@ -2609,7 +2612,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
case AST_TIMING_EVENT_CONTINUOUS: case AST_TIMING_EVENT_CONTINUOUS:
if (AST_LIST_EMPTY(&chan->readq) || if (AST_LIST_EMPTY(&chan->readq) ||
!AST_LIST_NEXT(AST_LIST_FIRST(&chan->readq), frame_list)) { !AST_LIST_NEXT(AST_LIST_FIRST(&chan->readq), frame_list)) {
ast_timer_disable_continuous(chan->timingfd); ast_timer_disable_continuous(chan->timer);
} }
break; break;
} }

@ -49,6 +49,11 @@ struct timing_holder {
static struct ast_heap *timing_interfaces; static struct ast_heap *timing_interfaces;
struct ast_timer {
int fd;
struct timing_holder *holder;
};
static int timing_holder_cmp(void *_h1, void *_h2) static int timing_holder_cmp(void *_h1, void *_h2)
{ {
struct timing_holder *h1 = _h1; struct timing_holder *h1 = _h1;
@ -64,16 +69,16 @@ static int timing_holder_cmp(void *_h1, void *_h2)
} }
void *_ast_register_timing_interface(struct ast_timing_interface *funcs, void *_ast_register_timing_interface(struct ast_timing_interface *funcs,
struct ast_module *mod) struct ast_module *mod)
{ {
struct timing_holder *h; struct timing_holder *h;
if (!funcs->timer_open || if (!funcs->timer_open ||
!funcs->timer_close || !funcs->timer_close ||
!funcs->timer_set_rate || !funcs->timer_set_rate ||
!funcs->timer_ack || !funcs->timer_ack ||
!funcs->timer_get_event || !funcs->timer_get_event ||
!funcs->timer_get_max_rate || !funcs->timer_get_max_rate ||
!funcs->timer_enable_continuous || !funcs->timer_enable_continuous ||
!funcs->timer_disable_continuous) { !funcs->timer_disable_continuous) {
return NULL; return NULL;
@ -111,10 +116,11 @@ int ast_unregister_timing_interface(void *handle)
return res; return res;
} }
int ast_timer_open(void) struct ast_timer *ast_timer_open(void)
{ {
int fd = -1; int fd = -1;
struct timing_holder *h; struct timing_holder *h;
struct ast_timer *t = NULL;
ast_heap_rdlock(timing_interfaces); ast_heap_rdlock(timing_interfaces);
@ -123,124 +129,88 @@ int ast_timer_open(void)
ast_module_ref(h->mod); ast_module_ref(h->mod);
} }
if (fd != -1) {
if (!(t = ast_calloc(1, sizeof(*t)))) {
h->iface->timer_close(fd);
} else {
t->fd = fd;
t->holder = h;
}
}
ast_heap_unlock(timing_interfaces); ast_heap_unlock(timing_interfaces);
return fd; return t;
} }
void ast_timer_close(int timer) void ast_timer_close(struct ast_timer *handle)
{ {
struct timing_holder *h; handle->holder->iface->timer_close(handle->fd);
ast_module_unref(handle->holder->mod);
ast_heap_rdlock(timing_interfaces); ast_free(handle);
}
if ((h = ast_heap_peek(timing_interfaces, 1))) {
h->iface->timer_close(timer);
ast_module_unref(h->mod);
}
ast_heap_unlock(timing_interfaces); int ast_timer_fd(const struct ast_timer *handle)
{
return handle->fd;
} }
int ast_timer_set_rate(int handle, unsigned int rate) int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
{ {
struct timing_holder *h;
int res = -1; int res = -1;
ast_heap_rdlock(timing_interfaces); res = handle->holder->iface->timer_set_rate(handle->fd, rate);
if ((h = ast_heap_peek(timing_interfaces, 1))) {
res = h->iface->timer_set_rate(handle, rate);
}
ast_heap_unlock(timing_interfaces);
return res; return res;
} }
void ast_timer_ack(int handle, unsigned int quantity) void ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
{ {
struct timing_holder *h; handle->holder->iface->timer_ack(handle->fd, quantity);
ast_heap_rdlock(timing_interfaces);
if ((h = ast_heap_peek(timing_interfaces, 1))) {
h->iface->timer_ack(handle, quantity);
}
ast_heap_unlock(timing_interfaces);
} }
int ast_timer_enable_continuous(int handle) int ast_timer_enable_continuous(const struct ast_timer *handle)
{ {
struct timing_holder *h;
int res = -1; int res = -1;
ast_heap_rdlock(timing_interfaces); res = handle->holder->iface->timer_enable_continuous(handle->fd);
if ((h = ast_heap_peek(timing_interfaces, 1))) {
res = h->iface->timer_enable_continuous(handle);
}
ast_heap_unlock(timing_interfaces);
return res; return res;
} }
int ast_timer_disable_continuous(int handle) int ast_timer_disable_continuous(const struct ast_timer *handle)
{ {
struct timing_holder *h;
int res = -1; int res = -1;
ast_heap_rdlock(timing_interfaces); res = handle->holder->iface->timer_disable_continuous(handle->fd);
if ((h = ast_heap_peek(timing_interfaces, 1))) {
res = h->iface->timer_disable_continuous(handle);
}
ast_heap_unlock(timing_interfaces);
return res; return res;
} }
enum ast_timer_event ast_timer_get_event(int handle) enum ast_timer_event ast_timer_get_event(const struct ast_timer *handle)
{ {
struct timing_holder *h;
enum ast_timer_event res = -1; enum ast_timer_event res = -1;
ast_heap_rdlock(timing_interfaces); res = handle->holder->iface->timer_get_event(handle->fd);
if ((h = ast_heap_peek(timing_interfaces, 1))) {
res = h->iface->timer_get_event(handle);
}
ast_heap_unlock(timing_interfaces);
return res; return res;
} }
unsigned int ast_timer_get_max_rate(int handle) unsigned int ast_timer_get_max_rate(const struct ast_timer *handle)
{ {
struct timing_holder *h;
unsigned int res = 0; unsigned int res = 0;
ast_heap_rdlock(timing_interfaces); res = handle->holder->iface->timer_get_max_rate(handle->fd);
if ((h = ast_heap_peek(timing_interfaces, 1))) {
res = h->iface->timer_get_max_rate(handle);
}
ast_heap_unlock(timing_interfaces);
return res; return res;
} }
static char *timing_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) static char *timing_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{ {
int fd, count = 0; struct ast_timer *timer;
int count = 0;
struct timeval start, end; struct timeval start, end;
unsigned int test_rate = 50; unsigned int test_rate = 50;
struct timing_holder *h;
switch (cmd) { switch (cmd) {
case CLI_INIT: case CLI_INIT:
@ -268,26 +238,21 @@ static char *timing_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
ast_cli(a->fd, "Attempting to test a timer with %u ticks per second.\n", test_rate); ast_cli(a->fd, "Attempting to test a timer with %u ticks per second.\n", test_rate);
if ((fd = ast_timer_open()) == -1) { if (!(timer = ast_timer_open())) {
ast_cli(a->fd, "Failed to open timing fd\n"); ast_cli(a->fd, "Failed to open timing fd\n");
return CLI_FAILURE; return CLI_FAILURE;
} }
ast_heap_rdlock(timing_interfaces); ast_cli(a->fd, "Using the '%s' timing module for this test.\n", timer->holder->iface->name);
if ((h = ast_heap_peek(timing_interfaces, 1))) {
ast_cli(a->fd, "Using the '%s' timing module for this test.\n", h->iface->name);
h = NULL;
}
ast_heap_unlock(timing_interfaces);
start = ast_tvnow(); start = ast_tvnow();
ast_timer_set_rate(fd, test_rate); ast_timer_set_rate(timer, test_rate);
while (ast_tvdiff_ms((end = ast_tvnow()), start) < 1000) { while (ast_tvdiff_ms((end = ast_tvnow()), start) < 1000) {
int res; int res;
struct pollfd pfd = { struct pollfd pfd = {
.fd = fd, .fd = ast_timer_fd(timer),
.events = POLLIN | POLLPRI, .events = POLLIN | POLLPRI,
}; };
@ -295,7 +260,7 @@ static char *timing_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
if (res == 1) { if (res == 1) {
count++; count++;
ast_timer_ack(fd, 1); ast_timer_ack(timer, 1);
} else if (!res) { } else if (!res) {
ast_cli(a->fd, "poll() timed out! This is bad.\n"); ast_cli(a->fd, "poll() timed out! This is bad.\n");
} else if (errno != EAGAIN && errno != EINTR) { } else if (errno != EAGAIN && errno != EINTR) {
@ -303,7 +268,7 @@ static char *timing_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
} }
} }
ast_timer_close(fd); ast_timer_close(timer);
ast_cli(a->fd, "It has been %d milliseconds, and we got %d timer ticks\n", ast_cli(a->fd, "It has been %d milliseconds, and we got %d timer ticks\n",
ast_tvdiff_ms(end, start), count); ast_tvdiff_ms(end, start), count);

Loading…
Cancel
Save