00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "asterisk.h"
00032
00033 #include <sys/timerfd.h>
00034
00035 #include "asterisk/module.h"
00036 #include "asterisk/astobj2.h"
00037 #include "asterisk/timing.h"
00038 #include "asterisk/logger.h"
00039 #include "asterisk/utils.h"
00040 #include "asterisk/time.h"
00041
00042 static void *timing_funcs_handle;
00043
00044 static int timerfd_timer_open(void);
00045 static void timerfd_timer_close(int handle);
00046 static int timerfd_timer_set_rate(int handle, unsigned int rate);
00047 static void timerfd_timer_ack(int handle, unsigned int quantity);
00048 static int timerfd_timer_enable_continuous(int handle);
00049 static int timerfd_timer_disable_continuous(int handle);
00050 static enum ast_timer_event timerfd_timer_get_event(int handle);
00051 static unsigned int timerfd_timer_get_max_rate(int handle);
00052
00053 static struct ast_timing_interface timerfd_timing = {
00054 .name = "timerfd",
00055 .priority = 200,
00056 .timer_open = timerfd_timer_open,
00057 .timer_close = timerfd_timer_close,
00058 .timer_set_rate = timerfd_timer_set_rate,
00059 .timer_ack = timerfd_timer_ack,
00060 .timer_enable_continuous = timerfd_timer_enable_continuous,
00061 .timer_disable_continuous = timerfd_timer_disable_continuous,
00062 .timer_get_event = timerfd_timer_get_event,
00063 .timer_get_max_rate = timerfd_timer_get_max_rate,
00064 };
00065
00066 static struct ao2_container *timerfd_timers;
00067
00068 #define TIMERFD_TIMER_BUCKETS 563
00069 #define TIMERFD_MAX_RATE 1000
00070
00071 struct timerfd_timer {
00072 int handle;
00073 struct itimerspec saved_timer;
00074 unsigned int is_continuous:1;
00075 };
00076
00077 static int timerfd_timer_hash(const void *obj, const int flags)
00078 {
00079 const struct timerfd_timer *timer = obj;
00080
00081 return timer->handle;
00082 }
00083
00084 static int timerfd_timer_cmp(void *obj, void *args, int flags)
00085 {
00086 struct timerfd_timer *timer1 = obj, *timer2 = args;
00087 return timer1->handle == timer2->handle ? CMP_MATCH | CMP_STOP : 0;
00088 }
00089
00090 static void timer_destroy(void *obj)
00091 {
00092 struct timerfd_timer *timer = obj;
00093 close(timer->handle);
00094 }
00095
00096 static int timerfd_timer_open(void)
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
00114 ao2_ref(timer, -1);
00115 return handle;
00116 }
00117
00118 static void timerfd_timer_close(int handle)
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 }
00132
00133 static int timerfd_timer_set_rate(int handle, unsigned int rate)
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 }
00160
00161 static void timerfd_timer_ack(int handle, unsigned int quantity)
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 }
00209
00210 static int timerfd_timer_enable_continuous(int handle)
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
00228
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 }
00241
00242 static int timerfd_timer_disable_continuous(int handle)
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
00257
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 }
00271
00272 static enum ast_timer_event timerfd_timer_get_event(int handle)
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 }
00295
00296 static unsigned int timerfd_timer_get_max_rate(int handle)
00297 {
00298 return TIMERFD_MAX_RATE;
00299 }
00300
00301 static int load_module(void)
00302 {
00303 int fd;
00304
00305
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 }
00324
00325 static int unload_module(void)
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 }
00336
00337 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Timerfd Timing Interface",
00338 .load = load_module,
00339 .unload = unload_module,
00340 .load_pri = AST_MODPRI_TIMING,
00341 );