summaryrefslogtreecommitdiff
path: root/res/res_timing_kqueue.c
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2014-02-07 20:01:45 +0000
committerJoshua Colp <jcolp@digium.com>2014-02-07 20:01:45 +0000
commite8e2f91bbac77ca50dddc4a496512475990a8764 (patch)
treefdbb590820a386771e01916e9dbd7809bd187232 /res/res_timing_kqueue.c
parent5fd63e2d0beeae4e118a7567716b586899166090 (diff)
timing: Improve performance for most timing implementations.
This change allows timing implementation data to be stored directly on the timer itself thus removing the requirement for many implementations to do a container lookup for the same information. This means that API calls into timing implementations can directly access the information they need instead of having to find it. Review: https://reviewboard.asterisk.org/r/3175/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@407749 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res/res_timing_kqueue.c')
-rw-r--r--res/res_timing_kqueue.c188
1 files changed, 58 insertions, 130 deletions
diff --git a/res/res_timing_kqueue.c b/res/res_timing_kqueue.c
index b5bc01f3f..3c0bfcc73 100644
--- a/res/res_timing_kqueue.c
+++ b/res/res_timing_kqueue.c
@@ -48,14 +48,15 @@
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 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);
-static unsigned int kqueue_timer_get_max_rate(int handle);
+static void *kqueue_timer_open(void);
+static void kqueue_timer_close(void *data);
+static int kqueue_timer_set_rate(void *data, unsigned int rate);
+static int kqueue_timer_ack(void *data, unsigned int quantity);
+static int kqueue_timer_enable_continuous(void *data);
+static int kqueue_timer_disable_continuous(void *data);
+static enum ast_timer_event kqueue_timer_get_event(void *data);
+static unsigned int kqueue_timer_get_max_rate(void *data);
+static int kqueue_timer_fd(void *data);
static struct ast_timing_interface kqueue_timing = {
.name = "kqueue",
@@ -68,10 +69,9 @@ static struct ast_timing_interface kqueue_timing = {
.timer_disable_continuous = kqueue_timer_disable_continuous,
.timer_get_event = kqueue_timer_get_event,
.timer_get_max_rate = kqueue_timer_get_max_rate,
+ .timer_fd = kqueue_timer_fd,
};
-static struct ao2_container *kqueue_timers;
-
struct kqueue_timer {
int handle;
uint64_t nsecs;
@@ -79,73 +79,34 @@ struct kqueue_timer {
unsigned int is_continuous:1;
};
-static int kqueue_timer_hash(const void *obj, const int flags)
-{
- const struct kqueue_timer *timer = obj;
-
- return timer->handle;
-}
-
-static int kqueue_timer_cmp(void *obj, void *args, int flags)
-{
- struct kqueue_timer *timer1 = obj, *timer2 = args;
- return timer1->handle == timer2->handle ? CMP_MATCH | CMP_STOP : 0;
-}
-
static void timer_destroy(void *obj)
{
struct kqueue_timer *timer = obj;
close(timer->handle);
}
-#define lookup_timer(a) _lookup_timer(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
-static struct kqueue_timer *_lookup_timer(int handle, const char *file, int line, const char *func)
-{
- struct kqueue_timer *our_timer, find_helper = {
- .handle = handle,
- };
-
- if (!(our_timer = ao2_find(kqueue_timers, &find_helper, OBJ_POINTER))) {
- ast_log(__LOG_ERROR, file, line, func, "Couldn't find timer with handle %d\n", handle);
- /* API says we set errno */
- errno = ESRCH;
- return NULL;
- }
- return our_timer;
-}
-
-static int kqueue_timer_open(void)
+static void *kqueue_timer_open(void)
{
struct kqueue_timer *timer;
- int handle;
if (!(timer = ao2_alloc(sizeof(*timer), timer_destroy))) {
ast_log(LOG_ERROR, "Could not allocate memory for kqueue_timer structure\n");
return -1;
}
- if ((handle = kqueue()) < 0) {
+ if ((timer->handle = kqueue()) < 0) {
ast_log(LOG_ERROR, "Failed to create kqueue timer: %s\n", strerror(errno));
ao2_ref(timer, -1);
return -1;
}
- timer->handle = handle;
- ao2_link(kqueue_timers, timer);
- /* Get rid of the reference from the allocation */
- ao2_ref(timer, -1);
- return handle;
+ return timer;
}
-static void kqueue_timer_close(int handle)
+static void kqueue_timer_close(void *data)
{
- struct kqueue_timer *our_timer;
+ struct kqueue_timer *timer = data;
- if (!(our_timer = lookup_timer(handle))) {
- return;
- }
-
- ao2_unlink(kqueue_timers, our_timer);
- ao2_ref(our_timer, -1);
+ ao2_ref(timer, -1);
}
static void kqueue_set_nsecs(struct kqueue_timer *our_timer, uint64_t nsecs)
@@ -183,107 +144,90 @@ static void kqueue_set_nsecs(struct kqueue_timer *our_timer, uint64_t nsecs)
#endif
}
-static int kqueue_timer_set_rate(int handle, unsigned int rate)
+static int kqueue_timer_set_rate(void *data, unsigned int rate)
{
- struct kqueue_timer *our_timer;
+ struct kqueue_timer *timer = data;
- if (!(our_timer = lookup_timer(handle))) {
- return -1;
- }
-
- kqueue_set_nsecs(our_timer, (our_timer->nsecs = rate ? (long) (1000000000 / rate) : 0L));
- ao2_ref(our_timer, -1);
+ kqueue_set_nsecs(timer, (timer->nsecs = rate ? (long) (1000000000 / rate) : 0L));
return 0;
}
-static int kqueue_timer_ack(int handle, unsigned int quantity)
+static int kqueue_timer_ack(void *data, unsigned int quantity)
{
- struct kqueue_timer *our_timer;
+ struct kqueue_timer *timer = data;
- if (!(our_timer = lookup_timer(handle))) {
- return -1;
- }
-
- if (our_timer->unacked < quantity) {
+ if (timer->unacked < quantity) {
ast_debug(1, "Acking more events than have expired?!!\n");
- our_timer->unacked = 0;
- ao2_ref(our_timer, -1);
+ timer->unacked = 0;
return -1;
} else {
- our_timer->unacked -= quantity;
+ timer->unacked -= quantity;
}
- ao2_ref(our_timer, -1);
return 0;
}
-static int kqueue_timer_enable_continuous(int handle)
+static int kqueue_timer_enable_continuous(void *data)
{
- struct kqueue_timer *our_timer;
+ struct kqueue_timer *timer = data;
- if (!(our_timer = lookup_timer(handle))) {
- return -1;
- }
+ kqueue_set_nsecs(timer, 1);
+ timer->is_continuous = 1;
+ timer->unacked = 0;
- kqueue_set_nsecs(our_timer, 1);
- our_timer->is_continuous = 1;
- our_timer->unacked = 0;
- ao2_ref(our_timer, -1);
return 0;
}
-static int kqueue_timer_disable_continuous(int handle)
+static int kqueue_timer_disable_continuous(void *data)
{
- struct kqueue_timer *our_timer;
+ struct kqueue_timer *timer = data;
- if (!(our_timer = lookup_timer(handle))) {
- return -1;
- }
+ kqueue_set_nsecs(timer, timer->nsecs);
+ timer->is_continuous = 0;
+ timer->unacked = 0;
- kqueue_set_nsecs(our_timer, our_timer->nsecs);
- our_timer->is_continuous = 0;
- our_timer->unacked = 0;
- ao2_ref(our_timer, -1);
return 0;
}
-static enum ast_timer_event kqueue_timer_get_event(int handle)
+static enum ast_timer_event kqueue_timer_get_event(void *data)
{
+ struct kqueue_timer *timer = data;
enum ast_timer_event res = -1;
- struct kqueue_timer *our_timer;
struct timespec sixty_seconds = { 60, 0 };
struct kevent kev;
- if (!(our_timer = lookup_timer(handle))) {
- return -1;
- }
-
/* If we have non-ACKed events, just return immediately */
- if (our_timer->unacked == 0) {
- if (kevent(handle, NULL, 0, &kev, 1, &sixty_seconds) > 0) {
- our_timer->unacked += kev.data;
+ if (timer->unacked == 0) {
+ if (kevent(timer->handle, NULL, 0, &kev, 1, &sixty_seconds) > 0) {
+ timer->unacked += kev.data;
}
}
- if (our_timer->unacked > 0) {
- res = our_timer->is_continuous ? AST_TIMING_EVENT_CONTINUOUS : AST_TIMING_EVENT_EXPIRED;
+ if (timer->unacked > 0) {
+ res = timer->is_continuous ? AST_TIMING_EVENT_CONTINUOUS : AST_TIMING_EVENT_EXPIRED;
}
- ao2_ref(our_timer, -1);
return res;
}
-static unsigned int kqueue_timer_get_max_rate(int handle)
+static unsigned int kqueue_timer_get_max_rate(void *data)
{
/* Actually, the max rate is 2^64-1 seconds, but that's not representable in a 32-bit integer. */
return UINT_MAX;
}
+static int kqueue_timer_fd(void *data)
+{
+ struct kqueue_timer *timer = data;
+
+ return timer->handle;
+}
+
#ifdef TEST_FRAMEWORK
AST_TEST_DEFINE(test_kqueue_timing)
{
- int res = AST_TEST_PASS, handle, i;
+ int res = AST_TEST_PASS, i;
uint64_t diff;
struct pollfd pfd = { 0, POLLIN, 0 };
struct kqueue_timer *kt;
@@ -300,14 +244,14 @@ AST_TEST_DEFINE(test_kqueue_timing)
break;
}
- if (!(handle = kqueue_timer_open())) {
+ if (!(kt = kqueue_timer_open())) {
ast_test_status_update(test, "Cannot open timer!\n");
return AST_TEST_FAIL;
}
do {
- pfd.fd = handle;
- if (kqueue_timer_set_rate(handle, 1000)) {
+ pfd.fd = ast_timer_fd(kt);
+ if (kqueue_timer_set_rate(kt, 1000)) {
ast_test_status_update(test, "Cannot set timer rate to 1000/s\n");
res = AST_TEST_FAIL;
break;
@@ -322,12 +266,7 @@ AST_TEST_DEFINE(test_kqueue_timing)
res = AST_TEST_FAIL;
break;
}
- if (!(kt = lookup_timer(handle))) {
- ast_test_status_update(test, "Could not find timer structure in container?!!\n");
- res = AST_TEST_FAIL;
- break;
- }
- if (kqueue_timer_get_event(handle) <= 0) {
+ if (kqueue_timer_get_event(kt) <= 0) {
ast_test_status_update(test, "No events generated after a poll returned successfully?!!\n");
res = AST_TEST_FAIL;
break;
@@ -339,7 +278,7 @@ AST_TEST_DEFINE(test_kqueue_timing)
break;
}
#endif
- kqueue_timer_enable_continuous(handle);
+ kqueue_timer_enable_continuous(kt);
start = ast_tvnow();
for (i = 0; i < 100; i++) {
if (ast_poll(&pfd, 1, 1000) < 1) {
@@ -347,7 +286,7 @@ AST_TEST_DEFINE(test_kqueue_timing)
res = AST_TEST_FAIL;
break;
}
- if (kqueue_timer_get_event(handle) <= 0) {
+ if (kqueue_timer_get_event(kt) <= 0) {
ast_test_status_update(test, "No events generated in continuous mode after 1 microsecond?!!\n");
res = AST_TEST_FAIL;
break;
@@ -362,7 +301,7 @@ AST_TEST_DEFINE(test_kqueue_timing)
}
*/
} while (0);
- kqueue_timer_close(handle);
+ kqueue_timer_close(kt);
return res;
}
#endif
@@ -379,12 +318,7 @@ AST_TEST_DEFINE(test_kqueue_timing)
*/
static int load_module(void)
{
- if (!(kqueue_timers = ao2_container_alloc(563, kqueue_timer_hash, kqueue_timer_cmp))) {
- return AST_MODULE_LOAD_DECLINE;
- }
-
if (!(timing_funcs_handle = ast_register_timing_interface(&kqueue_timing))) {
- ao2_ref(kqueue_timers, -1);
return AST_MODULE_LOAD_DECLINE;
}
@@ -394,15 +328,9 @@ static int load_module(void)
static int unload_module(void)
{
- int res;
-
AST_TEST_UNREGISTER(test_kqueue_timing);
- if (!(res = ast_unregister_timing_interface(timing_funcs_handle))) {
- ao2_ref(kqueue_timers, -1);
- kqueue_timers = NULL;
- }
- return res;
+ return ast_unregister_timing_interface(timing_funcs_handle);
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "KQueue Timing Interface",