From 9381bff79d8c042affb23d3733fe6aa272a1f579 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Fri, 27 Mar 2009 19:10:32 +0000 Subject: 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 --- main/timing.c | 131 +++++++++++++++++++++------------------------------------- 1 file changed, 48 insertions(+), 83 deletions(-) (limited to 'main/timing.c') 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); -- cgit v1.2.3