timerfd timing interface More...
#include "asterisk.h"#include <sys/timerfd.h>#include "asterisk/module.h"#include "asterisk/astobj2.h"#include "asterisk/timing.h"#include "asterisk/logger.h"#include "asterisk/utils.h"#include "asterisk/time.h"
Go to the source code of this file.
Data Structures | |
| struct | timerfd_timer |
Defines | |
| #define | TIMERFD_MAX_RATE 1000 |
| #define | TIMERFD_TIMER_BUCKETS 563 |
Functions | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | load_module (void) |
| static void | timer_destroy (void *obj) |
| static int | timerfd_timer_ack (int handle, unsigned int quantity) |
| static void | timerfd_timer_close (int handle) |
| static int | timerfd_timer_cmp (void *obj, void *args, int flags) |
| static int | timerfd_timer_disable_continuous (int handle) |
| static int | timerfd_timer_enable_continuous (int handle) |
| static enum ast_timer_event | timerfd_timer_get_event (int handle) |
| static unsigned int | timerfd_timer_get_max_rate (int handle) |
| static int | timerfd_timer_hash (const void *obj, const int flags) |
| static int | timerfd_timer_open (void) |
| static int | timerfd_timer_set_rate (int handle, unsigned int rate) |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Timerfd Timing Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_TIMING, } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ao2_container * | timerfd_timers |
| static struct ast_timing_interface | timerfd_timing |
| static void * | timing_funcs_handle |
timerfd timing interface
Definition in file res_timing_timerfd.c.
| #define TIMERFD_MAX_RATE 1000 |
Definition at line 69 of file res_timing_timerfd.c.
Referenced by timerfd_timer_get_max_rate().
| #define TIMERFD_TIMER_BUCKETS 563 |
Definition at line 68 of file res_timing_timerfd.c.
Referenced by load_module().
| static void __reg_module | ( | void | ) | [static] |
Definition at line 376 of file res_timing_timerfd.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 376 of file res_timing_timerfd.c.
| static int load_module | ( | void | ) | [static] |
Definition at line 336 of file res_timing_timerfd.c.
References ao2_container_alloc, ao2_ref, ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_register_timing_interface, LOG_ERROR, TIMERFD_TIMER_BUCKETS, timerfd_timer_cmp(), timerfd_timer_hash(), and timing_funcs_handle.
{
int fd;
/* Make sure we support the necessary clock type */
if ((fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) {
ast_log(LOG_ERROR, "timerfd_create() not supported by the kernel. Not loading.\n");
return AST_MODULE_LOAD_DECLINE;
}
close(fd);
if (!(timerfd_timers = ao2_container_alloc(TIMERFD_TIMER_BUCKETS, timerfd_timer_hash, timerfd_timer_cmp))) {
return AST_MODULE_LOAD_DECLINE;
}
if (!(timing_funcs_handle = ast_register_timing_interface(&timerfd_timing))) {
ao2_ref(timerfd_timers, -1);
return AST_MODULE_LOAD_DECLINE;
}
return AST_MODULE_LOAD_SUCCESS;
}
| static void timer_destroy | ( | void * | obj | ) | [static] |
Definition at line 90 of file res_timing_timerfd.c.
References timerfd_timer::handle, and timer.
Referenced by timerfd_timer_open().
{
struct timerfd_timer *timer = obj;
close(timer->handle);
timer->handle = -1;
}
| static int timerfd_timer_ack | ( | int | handle, |
| unsigned int | quantity | ||
| ) | [static] |
Definition at line 172 of file res_timing_timerfd.c.
References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_debug, ast_log(), errno, timerfd_timer::handle, LOG_ERROR, and OBJ_POINTER.
{
uint64_t expirations;
int read_result = 0;
int res = 0;
struct timerfd_timer *our_timer, find_helper = {
.handle = handle,
};
if (handle == -1) {
ast_log(LOG_ERROR, "Attempting to ack timerfd handle -1");
return -1;
}
if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
ast_log(LOG_ERROR, "Couldn't find a timer with handle %d\n", handle);
return -1;
}
ao2_lock(our_timer);
do {
struct itimerspec timer_status;
if (timerfd_gettime(handle, &timer_status)) {
ast_log(LOG_ERROR, "Call to timerfd_gettime() using handle %d error: %s\n", handle, strerror(errno));
expirations = 0;
res = -1;
break;
}
if (timer_status.it_value.tv_sec == 0 && timer_status.it_value.tv_nsec == 0) {
ast_debug(1, "Avoiding read on disarmed timerfd %d\n", handle);
expirations = 0;
break;
}
read_result = read(handle, &expirations, sizeof(expirations));
if (read_result == -1) {
if (errno == EINTR || errno == EAGAIN) {
continue;
} else {
ast_log(LOG_ERROR, "Read error: %s\n", strerror(errno));
res = -1;
break;
}
}
} while (read_result != sizeof(expirations));
ao2_unlock(our_timer);
ao2_ref(our_timer, -1);
if (expirations != quantity) {
ast_debug(2, "Expected to acknowledge %u ticks but got %llu instead\n", quantity, (unsigned long long) expirations);
}
return res;
}
| static void timerfd_timer_close | ( | int | handle | ) | [static] |
Definition at line 119 of file res_timing_timerfd.c.
References ao2_find, ao2_ref, ao2_unlink, ast_log(), timerfd_timer::handle, LOG_ERROR, and OBJ_POINTER.
{
struct timerfd_timer *our_timer, find_helper = {
.handle = handle,
};
if (handle == -1) {
ast_log(LOG_ERROR, "Attempting to close timerfd handle -1");
return;
}
if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
return;
}
ao2_unlink(timerfd_timers, our_timer);
ao2_ref(our_timer, -1);
}
| static int timerfd_timer_cmp | ( | void * | obj, |
| void * | args, | ||
| int | flags | ||
| ) | [static] |
Definition at line 84 of file res_timing_timerfd.c.
References args, CMP_MATCH, CMP_STOP, and timerfd_timer::handle.
Referenced by load_module().
{
struct timerfd_timer *timer1 = obj, *timer2 = args;
return timer1->handle == timer2->handle ? CMP_MATCH | CMP_STOP : 0;
}
| static int timerfd_timer_disable_continuous | ( | int | handle | ) | [static] |
Definition at line 267 of file res_timing_timerfd.c.
References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_log(), timerfd_timer::handle, timerfd_timer::is_continuous, LOG_ERROR, OBJ_POINTER, and timerfd_timer::saved_timer.
{
int res;
struct timerfd_timer *our_timer, find_helper = {
.handle = handle,
};
if (handle == -1) {
ast_log(LOG_ERROR, "Attempting to disable timerfd handle -1");
return -1;
}
if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
return -1;
}
ao2_lock(our_timer);
if (!our_timer->is_continuous) {
/* No reason to do anything if we're not
* in continuous mode
*/
ao2_unlock(our_timer);
ao2_ref(our_timer, -1);
return 0;
}
res = timerfd_settime(handle, 0, &our_timer->saved_timer, NULL);
our_timer->is_continuous = 0;
memset(&our_timer->saved_timer, 0, sizeof(our_timer->saved_timer));
ao2_unlock(our_timer);
ao2_ref(our_timer, -1);
return res;
}
| static int timerfd_timer_enable_continuous | ( | int | handle | ) | [static] |
Definition at line 230 of file res_timing_timerfd.c.
References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_log(), timerfd_timer::handle, timerfd_timer::is_continuous, LOG_ERROR, OBJ_POINTER, and timerfd_timer::saved_timer.
{
int res;
struct itimerspec continuous_timer = {
.it_value.tv_nsec = 1L,
};
struct timerfd_timer *our_timer, find_helper = {
.handle = handle,
};
if (handle == -1) {
ast_log(LOG_ERROR, "Attempting to enable timerfd handle -1");
return -1;
}
if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
return -1;
}
ao2_lock(our_timer);
if (our_timer->is_continuous) {
/*It's already in continous mode, no need to do
* anything further
*/
ao2_unlock(our_timer);
ao2_ref(our_timer, -1);
return 0;
}
res = timerfd_settime(handle, 0, &continuous_timer, &our_timer->saved_timer);
our_timer->is_continuous = 1;
ao2_unlock(our_timer);
ao2_ref(our_timer, -1);
return res;
}
| static enum ast_timer_event timerfd_timer_get_event | ( | int | handle | ) | [static] |
Definition at line 302 of file res_timing_timerfd.c.
References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_log(), AST_TIMING_EVENT_CONTINUOUS, AST_TIMING_EVENT_EXPIRED, timerfd_timer::handle, timerfd_timer::is_continuous, LOG_ERROR, and OBJ_POINTER.
{
enum ast_timer_event res;
struct timerfd_timer *our_timer, find_helper = {
.handle = handle,
};
if (handle == -1) {
ast_log(LOG_ERROR, "Attempting to get event from timerfd handle -1");
return -1;
}
if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
return -1;
}
ao2_lock(our_timer);
if (our_timer->is_continuous) {
res = AST_TIMING_EVENT_CONTINUOUS;
} else {
res = AST_TIMING_EVENT_EXPIRED;
}
ao2_unlock(our_timer);
ao2_ref(our_timer, -1);
return res;
}
| static unsigned int timerfd_timer_get_max_rate | ( | int | handle | ) | [static] |
Definition at line 331 of file res_timing_timerfd.c.
References TIMERFD_MAX_RATE.
{
return TIMERFD_MAX_RATE;
}
| static int timerfd_timer_hash | ( | const void * | obj, |
| const int | flags | ||
| ) | [static] |
Definition at line 77 of file res_timing_timerfd.c.
References timerfd_timer::handle, and timer.
Referenced by load_module().
{
const struct timerfd_timer *timer = obj;
return timer->handle;
}
| static int timerfd_timer_open | ( | void | ) | [static] |
Definition at line 97 of file res_timing_timerfd.c.
References ao2_alloc, ao2_link, ao2_ref, ast_log(), errno, timerfd_timer::handle, LOG_ERROR, timer, and timer_destroy().
{
struct timerfd_timer *timer;
int handle;
if (!(timer = ao2_alloc(sizeof(*timer), timer_destroy))) {
ast_log(LOG_ERROR, "Could not allocate memory for timerfd_timer structure\n");
return -1;
}
if ((handle = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) {
ast_log(LOG_ERROR, "Failed to create timerfd timer: %s\n", strerror(errno));
ao2_ref(timer, -1);
return -1;
}
timer->handle = handle;
ao2_link(timerfd_timers, timer);
/* Get rid of the reference from the allocation */
ao2_ref(timer, -1);
return handle;
}
| static int timerfd_timer_set_rate | ( | int | handle, |
| unsigned int | rate | ||
| ) | [static] |
Definition at line 139 of file res_timing_timerfd.c.
References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_log(), timerfd_timer::handle, timerfd_timer::is_continuous, LOG_ERROR, OBJ_POINTER, and timerfd_timer::saved_timer.
{
struct timerfd_timer *our_timer, find_helper = {
.handle = handle,
};
int res = 0;
if (handle == -1) {
ast_log(LOG_ERROR, "Attempting to set rate on timerfd handle -1");
return -1;
}
if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
return -1;
}
ao2_lock(our_timer);
our_timer->saved_timer.it_value.tv_sec = 0;
our_timer->saved_timer.it_value.tv_nsec = rate ? (long) (1000000000 / rate) : 0L;
our_timer->saved_timer.it_interval.tv_sec = our_timer->saved_timer.it_value.tv_sec;
our_timer->saved_timer.it_interval.tv_nsec = our_timer->saved_timer.it_value.tv_nsec;
if (!our_timer->is_continuous) {
res = timerfd_settime(handle, 0, &our_timer->saved_timer, NULL);
}
ao2_unlock(our_timer);
ao2_ref(our_timer, -1);
return res;
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 360 of file res_timing_timerfd.c.
References ao2_ref, ast_unregister_timing_interface(), and timing_funcs_handle.
{
int res;
if (!(res = ast_unregister_timing_interface(timing_funcs_handle))) {
ao2_ref(timerfd_timers, -1);
timerfd_timers = NULL;
}
return res;
}
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Timerfd Timing Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_TIMING, } [static] |
Definition at line 376 of file res_timing_timerfd.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 376 of file res_timing_timerfd.c.
struct ao2_container* timerfd_timers [static] |
Definition at line 66 of file res_timing_timerfd.c.
struct ast_timing_interface timerfd_timing [static] |
Definition at line 53 of file res_timing_timerfd.c.
void* timing_funcs_handle [static] |
Definition at line 42 of file res_timing_timerfd.c.
Referenced by load_module(), and unload_module().