mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-30 10:33:13 +00:00
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
This commit is contained in:
@@ -85,13 +85,13 @@ struct softmix_channel {
|
||||
/*! \brief Function called when a bridge is created */
|
||||
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;
|
||||
}
|
||||
|
||||
bridge->bridge_pvt = (void*)(unsigned long)timingfd;
|
||||
bridge->bridge_pvt = timer;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -99,9 +99,7 @@ static int softmix_bridge_create(struct ast_bridge *bridge)
|
||||
/*! \brief Function called when a bridge is destroyed */
|
||||
static int softmix_bridge_destroy(struct ast_bridge *bridge)
|
||||
{
|
||||
int timingfd = (unsigned long)bridge->bridge_pvt;
|
||||
|
||||
ast_timer_close(timingfd);
|
||||
ast_timer_close((struct ast_timer *) bridge->bridge_pvt);
|
||||
|
||||
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 */
|
||||
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) {
|
||||
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 */
|
||||
ast_waitfor_n_fd(&timingfd, 1, &timeout, NULL);
|
||||
|
||||
ast_timer_ack(timingfd, 1);
|
||||
ast_timer_ack(timer, 1);
|
||||
|
||||
ao2_lock(bridge);
|
||||
}
|
||||
|
@@ -257,7 +257,7 @@ static int max_reg_expire;
|
||||
|
||||
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 *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)
|
||||
ast_verbose("Beginning trunk processing. Trunk queue ceiling is %d bytes per host\n", trunkmaxsize);
|
||||
|
||||
if (timingfd > -1) {
|
||||
ast_timer_ack(timingfd, 1);
|
||||
if (timer) {
|
||||
ast_timer_ack(timer, 1);
|
||||
}
|
||||
|
||||
/* For each peer that supports trunking... */
|
||||
@@ -10500,8 +10500,8 @@ static void *network_thread(void *ignore)
|
||||
int res, count, wakeup;
|
||||
struct iax_frame *f;
|
||||
|
||||
if (timingfd > -1)
|
||||
ast_io_add(io, timingfd, timing_read, AST_IO_IN | AST_IO_PRI, NULL);
|
||||
if (timer)
|
||||
ast_io_add(io, ast_timer_fd(timer), timing_read, AST_IO_IN | AST_IO_PRI, NULL);
|
||||
|
||||
for(;;) {
|
||||
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);
|
||||
} else if (!strcasecmp(v->name, "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_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);
|
||||
} else if (!strcasecmp(v->name, "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_clear_flag(user, IAX_TRUNK);
|
||||
}
|
||||
@@ -12486,8 +12486,8 @@ static int __unload_module(void)
|
||||
ao2_ref(users, -1);
|
||||
ao2_ref(iax_peercallno_pvts, -1);
|
||||
ao2_ref(iax_transfercallno_pvts, -1);
|
||||
if (timingfd > -1) {
|
||||
ast_timer_close(timingfd);
|
||||
if (timer) {
|
||||
ast_timer_close(timer);
|
||||
}
|
||||
|
||||
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( "IAXregistry", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_registry, "Show IAX registrations");
|
||||
|
||||
timingfd = ast_timer_open();
|
||||
if (timingfd > -1) {
|
||||
ast_timer_set_rate(timingfd, trunkfreq);
|
||||
if ((timer = ast_timer_open())) {
|
||||
ast_timer_set_rate(timer, trunkfreq);
|
||||
}
|
||||
|
||||
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 */
|
||||
struct {
|
||||
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
|
||||
know whether the wakeup it received was due to a periodic 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
|
||||
@@ -96,7 +93,7 @@ struct ast_timing_interface {
|
||||
*/
|
||||
#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,
|
||||
struct ast_module *mod);
|
||||
struct ast_module *mod);
|
||||
|
||||
/*!
|
||||
* \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);
|
||||
|
||||
struct ast_timer;
|
||||
|
||||
/*!
|
||||
* \brief Open a timing fd
|
||||
* \brief Open a timer
|
||||
*
|
||||
* \retval -1 error, with errno set
|
||||
* \retval >=0 success
|
||||
* \retval NULL on error, with errno set
|
||||
* \retval non-NULL timer handle on success
|
||||
* \since 1.6.1
|
||||
*/
|
||||
int ast_timer_open(void);
|
||||
struct ast_timer *ast_timer_open(void);
|
||||
|
||||
/*!
|
||||
* \brief Close an opened timing handle
|
||||
*
|
||||
* \param handle timing fd returned from timer_open()
|
||||
* \param handle timer handle returned from timer_open()
|
||||
*
|
||||
* \return nothing
|
||||
* \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
|
||||
*
|
||||
* \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
|
||||
*
|
||||
* Use this function if you want the timing fd to show input at a certain
|
||||
* rate. The other alternative use of a timing fd, is using the continuous
|
||||
* Use this function if you want the timer to show input at a certain
|
||||
* rate. The other alternative use of a timer is the continuous
|
||||
* mode.
|
||||
*
|
||||
* \retval -1 error, with errno set
|
||||
* \retval 0 success
|
||||
* \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
|
||||
*
|
||||
* \param handle timing fd returned from timer_open()
|
||||
* \param handle timer handle returned from timer_open()
|
||||
* \param quantity number of timer events to acknowledge
|
||||
*
|
||||
* \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
|
||||
* \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
|
||||
*
|
||||
* \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.
|
||||
*
|
||||
* \retval -1 failure, with errno set
|
||||
* \retval 0 success
|
||||
* \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
|
||||
*
|
||||
* \param handle timing fd returned from timer_close()
|
||||
* \param handle timer handle returned from timer_close()
|
||||
*
|
||||
* \retval -1 failure, with errno set
|
||||
* \retval 0 success
|
||||
* \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.
|
||||
*
|
||||
* \return which event triggered the timing fd
|
||||
* \return which event triggered the timer
|
||||
* \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
|
||||
*/
|
||||
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)
|
||||
}
|
||||
|
@@ -807,17 +807,19 @@ struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_
|
||||
#endif
|
||||
}
|
||||
|
||||
tmp->timingfd = ast_timer_open();
|
||||
if (tmp->timingfd > -1) {
|
||||
if ((tmp->timer = ast_timer_open())) {
|
||||
needqueue = 0;
|
||||
tmp->timingfd = ast_timer_fd(tmp->timer);
|
||||
} else {
|
||||
tmp->timingfd = -1;
|
||||
}
|
||||
|
||||
if (needqueue) {
|
||||
if (pipe(tmp->alertpipe)) {
|
||||
ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe!\n");
|
||||
alertpipe_failed:
|
||||
if (tmp->timingfd > -1) {
|
||||
ast_timer_close(tmp->timingfd);
|
||||
if (tmp->timer) {
|
||||
ast_timer_close(tmp->timer);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
} 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)) {
|
||||
pthread_kill(chan->blocker, SIGURG);
|
||||
}
|
||||
@@ -1378,8 +1380,9 @@ void ast_channel_free(struct ast_channel *chan)
|
||||
close(fd);
|
||||
if ((fd = chan->alertpipe[1]) > -1)
|
||||
close(fd);
|
||||
if ((fd = chan->timingfd) > -1)
|
||||
ast_timer_close(fd);
|
||||
if (chan->timer) {
|
||||
ast_timer_close(chan->timer);
|
||||
}
|
||||
#ifdef HAVE_EPOLL
|
||||
for (i = 0; i < AST_MAX_FDS; 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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->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);
|
||||
|
||||
res = ast_timer_get_event(chan->timingfd);
|
||||
res = ast_timer_get_event(chan->timer);
|
||||
|
||||
switch (res) {
|
||||
case AST_TIMING_EVENT_EXPIRED:
|
||||
ast_timer_ack(chan->timingfd, 1);
|
||||
ast_timer_ack(chan->timer, 1);
|
||||
|
||||
if (chan->timingfunc) {
|
||||
/* 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);
|
||||
func(data);
|
||||
} else {
|
||||
ast_timer_set_rate(chan->timingfd, 0);
|
||||
ast_timer_set_rate(chan->timer, 0);
|
||||
chan->fdno = -1;
|
||||
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:
|
||||
if (AST_LIST_EMPTY(&chan->readq) ||
|
||||
!AST_LIST_NEXT(AST_LIST_FIRST(&chan->readq), frame_list)) {
|
||||
ast_timer_disable_continuous(chan->timingfd);
|
||||
ast_timer_disable_continuous(chan->timer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
137
main/timing.c
137
main/timing.c
@@ -49,6 +49,11 @@ struct timing_holder {
|
||||
|
||||
static struct ast_heap *timing_interfaces;
|
||||
|
||||
struct ast_timer {
|
||||
int fd;
|
||||
struct timing_holder *holder;
|
||||
};
|
||||
|
||||
static int timing_holder_cmp(void *_h1, void *_h2)
|
||||
{
|
||||
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,
|
||||
struct ast_module *mod)
|
||||
struct ast_module *mod)
|
||||
{
|
||||
struct timing_holder *h;
|
||||
|
||||
if (!funcs->timer_open ||
|
||||
!funcs->timer_close ||
|
||||
!funcs->timer_set_rate ||
|
||||
!funcs->timer_set_rate ||
|
||||
!funcs->timer_ack ||
|
||||
!funcs->timer_get_event ||
|
||||
!funcs->timer_get_max_rate ||
|
||||
!funcs->timer_get_max_rate ||
|
||||
!funcs->timer_enable_continuous ||
|
||||
!funcs->timer_disable_continuous) {
|
||||
return NULL;
|
||||
@@ -111,10 +116,11 @@ int ast_unregister_timing_interface(void *handle)
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_timer_open(void)
|
||||
struct ast_timer *ast_timer_open(void)
|
||||
{
|
||||
int fd = -1;
|
||||
struct timing_holder *h;
|
||||
struct ast_timer *t = NULL;
|
||||
|
||||
ast_heap_rdlock(timing_interfaces);
|
||||
|
||||
@@ -123,124 +129,88 @@ int ast_timer_open(void)
|
||||
ast_module_ref(h->mod);
|
||||
}
|
||||
|
||||
ast_heap_unlock(timing_interfaces);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void ast_timer_close(int timer)
|
||||
{
|
||||
struct timing_holder *h;
|
||||
|
||||
ast_heap_rdlock(timing_interfaces);
|
||||
|
||||
if ((h = ast_heap_peek(timing_interfaces, 1))) {
|
||||
h->iface->timer_close(timer);
|
||||
ast_module_unref(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);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
int ast_timer_set_rate(int handle, unsigned int rate)
|
||||
void ast_timer_close(struct ast_timer *handle)
|
||||
{
|
||||
handle->holder->iface->timer_close(handle->fd);
|
||||
ast_module_unref(handle->holder->mod);
|
||||
ast_free(handle);
|
||||
}
|
||||
|
||||
int ast_timer_fd(const struct ast_timer *handle)
|
||||
{
|
||||
return handle->fd;
|
||||
}
|
||||
|
||||
int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
|
||||
{
|
||||
struct timing_holder *h;
|
||||
int res = -1;
|
||||
|
||||
ast_heap_rdlock(timing_interfaces);
|
||||
|
||||
if ((h = ast_heap_peek(timing_interfaces, 1))) {
|
||||
res = h->iface->timer_set_rate(handle, rate);
|
||||
}
|
||||
|
||||
ast_heap_unlock(timing_interfaces);
|
||||
res = handle->holder->iface->timer_set_rate(handle->fd, rate);
|
||||
|
||||
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;
|
||||
|
||||
ast_heap_rdlock(timing_interfaces);
|
||||
|
||||
if ((h = ast_heap_peek(timing_interfaces, 1))) {
|
||||
h->iface->timer_ack(handle, quantity);
|
||||
}
|
||||
|
||||
ast_heap_unlock(timing_interfaces);
|
||||
handle->holder->iface->timer_ack(handle->fd, quantity);
|
||||
}
|
||||
|
||||
int ast_timer_enable_continuous(int handle)
|
||||
int ast_timer_enable_continuous(const struct ast_timer *handle)
|
||||
{
|
||||
struct timing_holder *h;
|
||||
int res = -1;
|
||||
|
||||
ast_heap_rdlock(timing_interfaces);
|
||||
|
||||
if ((h = ast_heap_peek(timing_interfaces, 1))) {
|
||||
res = h->iface->timer_enable_continuous(handle);
|
||||
}
|
||||
|
||||
ast_heap_unlock(timing_interfaces);
|
||||
res = handle->holder->iface->timer_enable_continuous(handle->fd);
|
||||
|
||||
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;
|
||||
|
||||
ast_heap_rdlock(timing_interfaces);
|
||||
|
||||
if ((h = ast_heap_peek(timing_interfaces, 1))) {
|
||||
res = h->iface->timer_disable_continuous(handle);
|
||||
}
|
||||
|
||||
ast_heap_unlock(timing_interfaces);
|
||||
res = handle->holder->iface->timer_disable_continuous(handle->fd);
|
||||
|
||||
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;
|
||||
|
||||
ast_heap_rdlock(timing_interfaces);
|
||||
|
||||
if ((h = ast_heap_peek(timing_interfaces, 1))) {
|
||||
res = h->iface->timer_get_event(handle);
|
||||
}
|
||||
|
||||
ast_heap_unlock(timing_interfaces);
|
||||
res = handle->holder->iface->timer_get_event(handle->fd);
|
||||
|
||||
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;
|
||||
|
||||
ast_heap_rdlock(timing_interfaces);
|
||||
|
||||
if ((h = ast_heap_peek(timing_interfaces, 1))) {
|
||||
res = h->iface->timer_get_max_rate(handle);
|
||||
}
|
||||
|
||||
ast_heap_unlock(timing_interfaces);
|
||||
res = handle->holder->iface->timer_get_max_rate(handle->fd);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
unsigned int test_rate = 50;
|
||||
struct timing_holder *h;
|
||||
|
||||
switch (cmd) {
|
||||
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);
|
||||
|
||||
if ((fd = ast_timer_open()) == -1) {
|
||||
if (!(timer = ast_timer_open())) {
|
||||
ast_cli(a->fd, "Failed to open timing fd\n");
|
||||
return CLI_FAILURE;
|
||||
}
|
||||
|
||||
ast_heap_rdlock(timing_interfaces);
|
||||
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);
|
||||
ast_cli(a->fd, "Using the '%s' timing module for this test.\n", timer->holder->iface->name);
|
||||
|
||||
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) {
|
||||
int res;
|
||||
struct pollfd pfd = {
|
||||
.fd = fd,
|
||||
.fd = ast_timer_fd(timer),
|
||||
.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) {
|
||||
count++;
|
||||
ast_timer_ack(fd, 1);
|
||||
ast_timer_ack(timer, 1);
|
||||
} else if (!res) {
|
||||
ast_cli(a->fd, "poll() timed out! This is bad.\n");
|
||||
} 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_tvdiff_ms(end, start), count);
|
||||
|
Reference in New Issue
Block a user