aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b>2009-03-27 19:17:22 +0000
committerkpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b>2009-03-27 19:17:22 +0000
commit55337ecaa6dcc942686c070d002c615cb6191dff (patch)
treee6d02b30d5e60fecf8037b37f51059e617698553
parent4793ed0202690b9cb09e07b6149b2c2b64eee94e (diff)
Merged revisions 184762 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk ........ r184762 | kpfleming | 2009-03-27 14:10:32 -0500 (Fri, 27 Mar 2009) | 12 lines 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: http://svn.digium.com/svn/asterisk/branches/1.6.1@184765 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--channels/chan_iax2.c23
-rw-r--r--include/asterisk/channel.h8
-rw-r--r--include/asterisk/timing.h66
-rw-r--r--main/channel.c29
-rw-r--r--main/timing.c131
5 files changed, 121 insertions, 136 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 5643952af..e4d495a38 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -175,7 +175,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 */
@@ -7550,8 +7550,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... */
@@ -10359,8 +10359,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();
@@ -10669,7 +10669,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);
}
@@ -10924,7 +10924,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);
}
@@ -12321,8 +12321,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);
@@ -12463,9 +12463,8 @@ static int load_module(void)
ast_manager_register( "IAXpeerlist", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_peer_list, "List IAX Peers" );
ast_manager_register( "IAXnetstats", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_netstats, "Show IAX Netstats" );
- 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) {
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index b7bc66fa7..e4e8bfea7 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -492,7 +492,13 @@ struct ast_channel {
unsigned short transfercapability; /*!< ISDN Transfer Capbility - AST_FLAG_DIGITAL is not enough */
- char unused_old_dtmfq[AST_MAX_EXTENSION]; /*!< (deprecated, use readq instead) Any/all queued DTMF characters */
+ union {
+ char unused_old_dtmfq[AST_MAX_EXTENSION]; /*!< (deprecated, use readq instead) Any/all queued DTMF characters */
+ struct {
+ struct ast_timer *timer; /*!< timer object that provided timingfd */
+ };
+ };
+
char context[AST_MAX_CONTEXT]; /*!< Dialplan: Current extension context */
char exten[AST_MAX_EXTENSION]; /*!< Dialplan: Current extension number */
char macrocontext[AST_MAX_CONTEXT]; /*!< Macro: Current non-macro context. See app_macro.c */
diff --git a/include/asterisk/timing.h b/include/asterisk/timing.h
index c9a8fcba9..d93f4f408 100644
--- a/include/asterisk/timing.h
+++ b/include/asterisk/timing.h
@@ -93,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.
@@ -107,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()
@@ -154,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)
}
diff --git a/main/channel.c b/main/channel.c
index 7afa49dd6..4b056766c 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -806,17 +806,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);
@@ -1005,7 +1007,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);
}
@@ -1355,8 +1357,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])
@@ -2298,13 +2301,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;
@@ -2557,11 +2560,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 */
@@ -2571,7 +2574,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);
}
@@ -2582,7 +2585,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;
}
diff --git a/main/timing.c b/main/timing.c
index c24db2e29..d0e6a6d24 100644
--- a/main/timing.c
+++ b/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);
}
+ 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 fd;
+ return t;
}
-void ast_timer_close(int timer)
+void ast_timer_close(struct ast_timer *handle)
{
- 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);
- }
+ handle->holder->iface->timer_close(handle->fd);
+ ast_module_unref(handle->holder->mod);
+ ast_free(handle);
+}
- 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;
- 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);