#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 void | 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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 |
Definition in file res_timing_timerfd.c.
#define TIMERFD_MAX_RATE 1000 |
#define TIMERFD_TIMER_BUCKETS 563 |
static void __reg_module | ( | void | ) | [static] |
Definition at line 341 of file res_timing_timerfd.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 341 of file res_timing_timerfd.c.
static int load_module | ( | void | ) | [static] |
Definition at line 301 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(), timerfd_timers, timerfd_timing, and timing_funcs_handle.
00302 { 00303 int fd; 00304 00305 /* Make sure we support the necessary clock type */ 00306 if ((fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) { 00307 ast_log(LOG_ERROR, "timerfd_create() not supported by the kernel. Not loading.\n"); 00308 return AST_MODULE_LOAD_DECLINE; 00309 } 00310 00311 close(fd); 00312 00313 if (!(timerfd_timers = ao2_container_alloc(TIMERFD_TIMER_BUCKETS, timerfd_timer_hash, timerfd_timer_cmp))) { 00314 return AST_MODULE_LOAD_DECLINE; 00315 } 00316 00317 if (!(timing_funcs_handle = ast_register_timing_interface(&timerfd_timing))) { 00318 ao2_ref(timerfd_timers, -1); 00319 return AST_MODULE_LOAD_DECLINE; 00320 } 00321 00322 return AST_MODULE_LOAD_SUCCESS; 00323 }
static void timer_destroy | ( | void * | obj | ) | [static] |
Definition at line 90 of file res_timing_timerfd.c.
References timer.
00091 { 00092 struct timerfd_timer *timer = obj; 00093 close(timer->handle); 00094 }
static void timerfd_timer_ack | ( | int | handle, | |
unsigned int | quantity | |||
) | [static] |
Definition at line 161 of file res_timing_timerfd.c.
References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_debug, ast_log(), errno, LOG_ERROR, OBJ_POINTER, and timerfd_timers.
00162 { 00163 uint64_t expirations; 00164 int read_result = 0; 00165 struct timerfd_timer *our_timer, find_helper = { 00166 .handle = handle, 00167 }; 00168 00169 if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) { 00170 ast_log(LOG_ERROR, "Couldn't find a timer with handle %d\n", handle); 00171 return; 00172 } 00173 00174 ao2_lock(our_timer); 00175 00176 do { 00177 struct itimerspec timer_status; 00178 00179 if (timerfd_gettime(handle, &timer_status)) { 00180 ast_log(LOG_ERROR, "Call to timerfd_gettime() error: %s\n", strerror(errno)); 00181 expirations = 0; 00182 break; 00183 } 00184 00185 if (timer_status.it_value.tv_sec == 0 && timer_status.it_value.tv_nsec == 0) { 00186 ast_debug(1, "Avoiding read on disarmed timerfd %d\n", handle); 00187 expirations = 0; 00188 break; 00189 } 00190 00191 read_result = read(handle, &expirations, sizeof(expirations)); 00192 if (read_result == -1) { 00193 if (errno == EINTR || errno == EAGAIN) { 00194 continue; 00195 } else { 00196 ast_log(LOG_ERROR, "Read error: %s\n", strerror(errno)); 00197 break; 00198 } 00199 } 00200 } while (read_result != sizeof(expirations)); 00201 00202 ao2_unlock(our_timer); 00203 ao2_ref(our_timer, -1); 00204 00205 if (expirations != quantity) { 00206 ast_debug(2, "Expected to acknowledge %u ticks but got %llu instead\n", quantity, (unsigned long long) expirations); 00207 } 00208 }
static void timerfd_timer_close | ( | int | handle | ) | [static] |
Definition at line 118 of file res_timing_timerfd.c.
References ao2_find, ao2_ref, ao2_unlink, ast_log(), LOG_ERROR, OBJ_POINTER, and timerfd_timers.
00119 { 00120 struct timerfd_timer *our_timer, find_helper = { 00121 .handle = handle, 00122 }; 00123 00124 if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) { 00125 ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle); 00126 return; 00127 } 00128 00129 ao2_unlink(timerfd_timers, our_timer); 00130 ao2_ref(our_timer, -1); 00131 }
static int timerfd_timer_cmp | ( | void * | obj, | |
void * | args, | |||
int | flags | |||
) | [static] |
Definition at line 84 of file res_timing_timerfd.c.
References CMP_MATCH, CMP_STOP, and timerfd_timer::handle.
Referenced by load_module().
00085 { 00086 struct timerfd_timer *timer1 = obj, *timer2 = args; 00087 return timer1->handle == timer2->handle ? CMP_MATCH | CMP_STOP : 0; 00088 }
static int timerfd_timer_disable_continuous | ( | int | handle | ) | [static] |
Definition at line 242 of file res_timing_timerfd.c.
References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_log(), timerfd_timer::is_continuous, LOG_ERROR, OBJ_POINTER, timerfd_timer::saved_timer, and timerfd_timers.
00243 { 00244 int res; 00245 struct timerfd_timer *our_timer, find_helper = { 00246 .handle = handle, 00247 }; 00248 00249 if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) { 00250 ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle); 00251 return -1; 00252 } 00253 ao2_lock(our_timer); 00254 00255 if(!our_timer->is_continuous) { 00256 /* No reason to do anything if we're not 00257 * in continuous mode 00258 */ 00259 ao2_unlock(our_timer); 00260 ao2_ref(our_timer, -1); 00261 return 0; 00262 } 00263 00264 res = timerfd_settime(handle, 0, &our_timer->saved_timer, NULL); 00265 our_timer->is_continuous = 0; 00266 memset(&our_timer->saved_timer, 0, sizeof(our_timer->saved_timer)); 00267 ao2_unlock(our_timer); 00268 ao2_ref(our_timer, -1); 00269 return res; 00270 }
static int timerfd_timer_enable_continuous | ( | int | handle | ) | [static] |
Definition at line 210 of file res_timing_timerfd.c.
References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_log(), timerfd_timer::is_continuous, LOG_ERROR, OBJ_POINTER, timerfd_timer::saved_timer, and timerfd_timers.
00211 { 00212 int res; 00213 struct itimerspec continuous_timer = { 00214 .it_value.tv_nsec = 1L, 00215 }; 00216 struct timerfd_timer *our_timer, find_helper = { 00217 .handle = handle, 00218 }; 00219 00220 if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) { 00221 ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle); 00222 return -1; 00223 } 00224 ao2_lock(our_timer); 00225 00226 if (our_timer->is_continuous) { 00227 /*It's already in continous mode, no need to do 00228 * anything further 00229 */ 00230 ao2_unlock(our_timer); 00231 ao2_ref(our_timer, -1); 00232 return 0; 00233 } 00234 00235 res = timerfd_settime(handle, 0, &continuous_timer, &our_timer->saved_timer); 00236 our_timer->is_continuous = 1; 00237 ao2_unlock(our_timer); 00238 ao2_ref(our_timer, -1); 00239 return res; 00240 }
static enum ast_timer_event timerfd_timer_get_event | ( | int | handle | ) | [static] |
Definition at line 272 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::is_continuous, LOG_ERROR, OBJ_POINTER, and timerfd_timers.
00273 { 00274 enum ast_timer_event res; 00275 struct timerfd_timer *our_timer, find_helper = { 00276 .handle = handle, 00277 }; 00278 00279 if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) { 00280 ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle); 00281 return -1; 00282 } 00283 ao2_lock(our_timer); 00284 00285 if (our_timer->is_continuous) { 00286 res = AST_TIMING_EVENT_CONTINUOUS; 00287 } else { 00288 res = AST_TIMING_EVENT_EXPIRED; 00289 } 00290 00291 ao2_unlock(our_timer); 00292 ao2_ref(our_timer, -1); 00293 return res; 00294 }
static unsigned int timerfd_timer_get_max_rate | ( | int | handle | ) | [static] |
Definition at line 296 of file res_timing_timerfd.c.
References TIMERFD_MAX_RATE.
00297 { 00298 return TIMERFD_MAX_RATE; 00299 }
static int timerfd_timer_hash | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 77 of file res_timing_timerfd.c.
References timer.
Referenced by load_module().
00078 { 00079 const struct timerfd_timer *timer = obj; 00080 00081 return timer->handle; 00082 }
static int timerfd_timer_open | ( | void | ) | [static] |
Definition at line 96 of file res_timing_timerfd.c.
References ao2_alloc, ao2_link, ao2_ref, ast_log(), errno, timerfd_timer::handle, LOG_ERROR, timer, timer_destroy(), and timerfd_timers.
00097 { 00098 struct timerfd_timer *timer; 00099 int handle; 00100 00101 if (!(timer = ao2_alloc(sizeof(*timer), timer_destroy))) { 00102 ast_log(LOG_ERROR, "Could not allocate memory for timerfd_timer structure\n"); 00103 return -1; 00104 } 00105 if ((handle = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) { 00106 ast_log(LOG_ERROR, "Failed to create timerfd timer: %s\n", strerror(errno)); 00107 ao2_ref(timer, -1); 00108 return -1; 00109 } 00110 00111 timer->handle = handle; 00112 ao2_link(timerfd_timers, timer); 00113 /* Get rid of the reference from the allocation */ 00114 ao2_ref(timer, -1); 00115 return handle; 00116 }
static int timerfd_timer_set_rate | ( | int | handle, | |
unsigned int | rate | |||
) | [static] |
Definition at line 133 of file res_timing_timerfd.c.
References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_log(), timerfd_timer::is_continuous, LOG_ERROR, OBJ_POINTER, timerfd_timer::saved_timer, and timerfd_timers.
00134 { 00135 struct timerfd_timer *our_timer, find_helper = { 00136 .handle = handle, 00137 }; 00138 int res = 0; 00139 00140 if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) { 00141 ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle); 00142 return -1; 00143 } 00144 ao2_lock(our_timer); 00145 00146 our_timer->saved_timer.it_value.tv_sec = 0; 00147 our_timer->saved_timer.it_value.tv_nsec = rate ? (long) (1000000000 / rate) : 0L; 00148 our_timer->saved_timer.it_interval.tv_sec = our_timer->saved_timer.it_value.tv_sec; 00149 our_timer->saved_timer.it_interval.tv_nsec = our_timer->saved_timer.it_value.tv_nsec; 00150 00151 if (!our_timer->is_continuous) { 00152 res = timerfd_settime(handle, 0, &our_timer->saved_timer, NULL); 00153 } 00154 00155 ao2_unlock(our_timer); 00156 ao2_ref(our_timer, -1); 00157 00158 return res; 00159 }
static int unload_module | ( | void | ) | [static] |
Definition at line 325 of file res_timing_timerfd.c.
References ao2_ref, ast_unregister_timing_interface(), timerfd_timers, and timing_funcs_handle.
00326 { 00327 int res; 00328 00329 if (!(res = ast_unregister_timing_interface(timing_funcs_handle))) { 00330 ao2_ref(timerfd_timers, -1); 00331 timerfd_timers = NULL; 00332 } 00333 00334 return res; 00335 }
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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_TIMING, } [static] |
Definition at line 341 of file res_timing_timerfd.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 341 of file res_timing_timerfd.c.
struct ao2_container* timerfd_timers [static] |
Definition at line 66 of file res_timing_timerfd.c.
Referenced by load_module(), timerfd_timer_ack(), timerfd_timer_close(), timerfd_timer_disable_continuous(), timerfd_timer_enable_continuous(), timerfd_timer_get_event(), timerfd_timer_open(), timerfd_timer_set_rate(), and unload_module().
struct ast_timing_interface timerfd_timing [static] |
void* timing_funcs_handle [static] |
Definition at line 42 of file res_timing_timerfd.c.