33 #include <sys/timerfd.h>
42 static void *timing_funcs_handle;
44 static void *timerfd_timer_open(
void);
45 static void timerfd_timer_close(
void *data);
46 static int timerfd_timer_set_rate(
void *data,
unsigned int rate);
47 static int timerfd_timer_ack(
void *data,
unsigned int quantity);
48 static int timerfd_timer_enable_continuous(
void *data);
49 static int timerfd_timer_disable_continuous(
void *data);
50 static enum ast_timer_event timerfd_timer_get_event(
void *data);
51 static unsigned int timerfd_timer_get_max_rate(
void *data);
52 static int timerfd_timer_fd(
void *data);
57 .timer_open = timerfd_timer_open,
58 .timer_close = timerfd_timer_close,
59 .timer_set_rate = timerfd_timer_set_rate,
60 .timer_ack = timerfd_timer_ack,
61 .timer_enable_continuous = timerfd_timer_enable_continuous,
62 .timer_disable_continuous = timerfd_timer_disable_continuous,
63 .timer_get_event = timerfd_timer_get_event,
64 .timer_get_max_rate = timerfd_timer_get_max_rate,
65 .timer_fd = timerfd_timer_fd,
68 #define TIMERFD_MAX_RATE 1000
72 struct itimerspec saved_timer;
73 unsigned int is_continuous:1;
76 static void timer_destroy(
void *obj)
84 static void *timerfd_timer_open(
void)
88 if (!(timer = ao2_alloc(
sizeof(*timer), timer_destroy))) {
89 ast_log(LOG_ERROR,
"Could not allocate memory for timerfd_timer structure\n");
92 if ((timer->fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) {
93 ast_log(LOG_ERROR,
"Failed to create timerfd timer: %s\n", strerror(errno));
101 static void timerfd_timer_close(
void *data)
106 static int timerfd_timer_set_rate(
void *data,
unsigned int rate)
113 timer->saved_timer.it_value.tv_sec = 0;
114 timer->saved_timer.it_value.tv_nsec = rate ? (long) (1000000000 / rate) : 0L;
115 timer->saved_timer.it_interval.tv_sec = timer->saved_timer.it_value.tv_sec;
116 timer->saved_timer.it_interval.tv_nsec = timer->saved_timer.it_value.tv_nsec;
118 if (!timer->is_continuous) {
119 res = timerfd_settime(timer->fd, 0, &timer->saved_timer, NULL);
127 static int timerfd_timer_ack(
void *data,
unsigned int quantity)
130 uint64_t expirations;
137 struct itimerspec timer_status;
139 if (timerfd_gettime(timer->fd, &timer_status)) {
140 ast_log(LOG_ERROR,
"Call to timerfd_gettime() using handle %d error: %s\n", timer->fd, strerror(errno));
146 if (timer_status.it_value.tv_sec == 0 && timer_status.it_value.tv_nsec == 0) {
147 ast_debug(1,
"Avoiding read on disarmed timerfd %d\n", timer->fd);
152 read_result = read(timer->fd, &expirations,
sizeof(expirations));
153 if (read_result == -1) {
154 if (errno == EINTR || errno == EAGAIN) {
157 ast_log(LOG_ERROR,
"Read error: %s\n", strerror(errno));
162 }
while (read_result !=
sizeof(expirations));
166 if (expirations != quantity) {
167 ast_debug(2,
"Expected to acknowledge %u ticks but got %llu instead\n", quantity, (
unsigned long long) expirations);
173 static int timerfd_timer_enable_continuous(
void *data)
177 static const struct itimerspec continuous_timer = {
178 .it_value.tv_nsec = 1L,
183 if (timer->is_continuous) {
191 res = timerfd_settime(timer->fd, 0, &continuous_timer, &timer->saved_timer);
192 timer->is_continuous = 1;
198 static int timerfd_timer_disable_continuous(
void *data)
205 if (!timer->is_continuous) {
213 res = timerfd_settime(timer->fd, 0, &timer->saved_timer, NULL);
214 timer->is_continuous = 0;
215 memset(&timer->saved_timer, 0,
sizeof(timer->saved_timer));
221 static enum ast_timer_event timerfd_timer_get_event(
void *data)
224 enum ast_timer_event res;
228 if (timer->is_continuous) {
229 res = AST_TIMING_EVENT_CONTINUOUS;
231 res = AST_TIMING_EVENT_EXPIRED;
239 static unsigned int timerfd_timer_get_max_rate(
void *data)
241 return TIMERFD_MAX_RATE;
244 static int timerfd_timer_fd(
void *data)
251 static int load_module(
void)
256 if ((fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) {
257 ast_log(LOG_ERROR,
"timerfd_create() not supported by the kernel. Not loading.\n");
270 static int unload_module(
void)
275 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"Timerfd Timing Interface",
276 .support_level = AST_MODULE_SUPPORT_CORE,
278 .unload = unload_module,
Asterisk main include file. File version handling, generic pbx functions.
Time-related functions and macros.
int ast_unregister_timing_interface(void *handle)
Unregister a previously registered timing interface.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define ast_debug(level,...)
Log a DEBUG message.
Support for logging to various files, console and syslog Configuration in file logger.conf.
Module has failed to load, may be in an inconsistent state.
#define ast_register_timing_interface(i)
Register a set of timing functions.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
Timing source management.