#include "asterisk.h"
#include <math.h>
#include <sys/select.h>
#include "asterisk/module.h"
#include "asterisk/timing.h"
#include "asterisk/utils.h"
#include "asterisk/astobj2.h"
#include "asterisk/time.h"
#include "asterisk/lock.h"
#include "asterisk/poll-compat.h"
Go to the source code of this file.
Data Structures | |
struct | pthread_timer |
Defines | |
#define | MAX_RATE 100 |
#define | PTHREAD_TIMER_BUCKETS 563 |
Enumerations | |
enum | { PIPE_READ = 0, PIPE_WRITE = 1 } |
enum | pthread_timer_state { TIMER_STATE_IDLE, TIMER_STATE_TICKING } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
ASTERISK_FILE_VERSION (__FILE__,"$Revision: 349194 $") | |
static int | check_timer (struct pthread_timer *timer) |
static void * | do_timing (void *arg) |
static struct pthread_timer * | find_timer (int handle, int unlinkobj) |
static int | init_timing_thread (void) |
static int | load_module (void) |
static void | pthread_timer_ack (int handle, unsigned int quantity) |
static void | pthread_timer_close (int handle) |
static int | pthread_timer_cmp (void *obj, void *arg, int flags) |
static void | pthread_timer_destructor (void *obj) |
static int | pthread_timer_disable_continuous (int handle) |
static int | pthread_timer_enable_continuous (int handle) |
static enum ast_timer_event | pthread_timer_get_event (int handle) |
static unsigned int | pthread_timer_get_max_rate (int handle) |
static int | pthread_timer_hash (const void *obj, const int flags) |
static int | pthread_timer_open (void) |
static int | pthread_timer_set_rate (int handle, unsigned int rate) |
static void | read_pipe (struct pthread_timer *timer, unsigned int num) |
static int | run_timer (void *obj, void *arg, int flags) |
static int | unload_module (void) |
static void | write_byte (struct pthread_timer *timer) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "pthread 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 * | pthread_timers |
static struct ast_timing_interface | pthread_timing |
static void * | timing_funcs_handle |
struct { | |
ast_cond_t cond | |
ast_mutex_t lock | |
unsigned int stop:1 | |
pthread_t thread | |
} | timing_thread |
Data for the timing thread. |
Definition in file res_timing_pthread.c.
#define MAX_RATE 100 |
Definition at line 70 of file res_timing_pthread.c.
Referenced by pthread_timer_get_max_rate(), and pthread_timer_set_rate().
#define PTHREAD_TIMER_BUCKETS 563 |
anonymous enum |
Definition at line 75 of file res_timing_pthread.c.
00075 { 00076 PIPE_READ = 0, 00077 PIPE_WRITE = 1 00078 };
enum pthread_timer_state |
Definition at line 80 of file res_timing_pthread.c.
00080 { 00081 TIMER_STATE_IDLE, 00082 TIMER_STATE_TICKING, 00083 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 529 of file res_timing_pthread.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 529 of file res_timing_pthread.c.
ASTERISK_FILE_VERSION | ( | __FILE__ | , | |
"$Revision: 349194 $" | ||||
) |
static int check_timer | ( | struct pthread_timer * | timer | ) | [static] |
0 | no timer tick needed | |
non-zero | write to the timing pipe needed |
Definition at line 336 of file res_timing_pthread.c.
References ast_tvdiff_ms(), ast_tvnow(), timer, and TIMER_STATE_IDLE.
Referenced by run_timer().
00337 { 00338 struct timeval now; 00339 00340 if (timer->state == TIMER_STATE_IDLE) { 00341 return 0; 00342 } 00343 00344 now = ast_tvnow(); 00345 00346 if (timer->tick_count < (ast_tvdiff_ms(now, timer->start) / timer->interval)) { 00347 timer->tick_count++; 00348 if (!timer->tick_count) { 00349 /* Handle overflow. */ 00350 timer->start = now; 00351 } 00352 return 1; 00353 } 00354 00355 return 0; 00356 }
static void* do_timing | ( | void * | arg | ) | [static] |
Definition at line 450 of file res_timing_pthread.c.
References ao2_callback, ao2_container_count(), ast_cond_timedwait, ast_cond_wait, ast_mutex_lock, ast_mutex_unlock, ast_tv(), ast_tvadd(), ast_tvnow(), OBJ_NODATA, pthread_timers, run_timer(), and timing_thread.
Referenced by init_timing_thread().
00451 { 00452 struct timeval next_wakeup = ast_tvnow(); 00453 00454 while (!timing_thread.stop) { 00455 struct timespec ts = { 0, }; 00456 00457 ao2_callback(pthread_timers, OBJ_NODATA, run_timer, NULL); 00458 00459 next_wakeup = ast_tvadd(next_wakeup, ast_tv(0, 5000)); 00460 00461 ts.tv_sec = next_wakeup.tv_sec; 00462 ts.tv_nsec = next_wakeup.tv_usec * 1000; 00463 00464 ast_mutex_lock(&timing_thread.lock); 00465 if (!timing_thread.stop) { 00466 if (ao2_container_count(pthread_timers)) { 00467 ast_cond_timedwait(&timing_thread.cond, &timing_thread.lock, &ts); 00468 } else { 00469 ast_cond_wait(&timing_thread.cond, &timing_thread.lock); 00470 } 00471 } 00472 ast_mutex_unlock(&timing_thread.lock); 00473 } 00474 00475 return NULL; 00476 }
static struct pthread_timer * find_timer | ( | int | handle, | |
int | unlinkobj | |||
) | [static] |
Definition at line 277 of file res_timing_pthread.c.
References ao2_find, ast_assert, OBJ_POINTER, OBJ_UNLINK, pthread_timer::pipe, PIPE_READ, pthread_timers, and timer.
Referenced by pthread_timer_ack(), pthread_timer_close(), pthread_timer_disable_continuous(), pthread_timer_enable_continuous(), pthread_timer_get_event(), and pthread_timer_set_rate().
00278 { 00279 struct pthread_timer *timer; 00280 struct pthread_timer tmp_timer; 00281 int flags = OBJ_POINTER; 00282 00283 tmp_timer.pipe[PIPE_READ] = handle; 00284 00285 if (unlinkobj) { 00286 flags |= OBJ_UNLINK; 00287 } 00288 00289 if (!(timer = ao2_find(pthread_timers, &tmp_timer, flags))) { 00290 ast_assert(timer != NULL); 00291 return NULL; 00292 } 00293 00294 return timer; 00295 }
static int init_timing_thread | ( | void | ) | [static] |
Definition at line 478 of file res_timing_pthread.c.
References ast_cond_init, ast_log(), ast_mutex_init, ast_pthread_create_background, do_timing(), LOG_ERROR, and timing_thread.
Referenced by load_module().
00479 { 00480 ast_mutex_init(&timing_thread.lock); 00481 ast_cond_init(&timing_thread.cond, NULL); 00482 00483 if (ast_pthread_create_background(&timing_thread.thread, NULL, do_timing, NULL)) { 00484 ast_log(LOG_ERROR, "Unable to start timing thread.\n"); 00485 return -1; 00486 } 00487 00488 return 0; 00489 }
static int load_module | ( | void | ) | [static] |
Definition at line 491 of file res_timing_pthread.c.
References ao2_container_alloc, ao2_ref, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_register_timing_interface, init_timing_thread(), PTHREAD_TIMER_BUCKETS, pthread_timer_cmp(), pthread_timer_hash(), pthread_timers, pthread_timing, and timing_funcs_handle.
00492 { 00493 if (!(pthread_timers = ao2_container_alloc(PTHREAD_TIMER_BUCKETS, 00494 pthread_timer_hash, pthread_timer_cmp))) { 00495 return AST_MODULE_LOAD_DECLINE; 00496 } 00497 00498 if (init_timing_thread()) { 00499 ao2_ref(pthread_timers, -1); 00500 pthread_timers = NULL; 00501 return AST_MODULE_LOAD_DECLINE; 00502 } 00503 00504 return (timing_funcs_handle = ast_register_timing_interface(&pthread_timing)) ? 00505 AST_MODULE_LOAD_SUCCESS : AST_MODULE_LOAD_DECLINE; 00506 }
static void pthread_timer_ack | ( | int | handle, | |
unsigned int | quantity | |||
) | [static] |
Definition at line 193 of file res_timing_pthread.c.
References ao2_lock, ao2_ref, ao2_unlock, ast_assert, find_timer(), read_pipe(), and timer.
00194 { 00195 struct pthread_timer *timer; 00196 00197 ast_assert(quantity > 0); 00198 00199 if (!(timer = find_timer(handle, 0))) { 00200 return; 00201 } 00202 00203 ao2_lock(timer); 00204 read_pipe(timer, quantity); 00205 ao2_unlock(timer); 00206 00207 ao2_ref(timer, -1); 00208 }
static void pthread_timer_close | ( | int | handle | ) | [static] |
Definition at line 146 of file res_timing_pthread.c.
References ao2_ref, find_timer(), and timer.
00147 { 00148 struct pthread_timer *timer; 00149 00150 if (!(timer = find_timer(handle, 1))) { 00151 return; 00152 } 00153 00154 ao2_ref(timer, -1); 00155 }
static int pthread_timer_cmp | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 325 of file res_timing_pthread.c.
References CMP_MATCH, CMP_STOP, pthread_timer::pipe, and PIPE_READ.
Referenced by load_module().
00326 { 00327 struct pthread_timer *timer1 = obj, *timer2 = arg; 00328 00329 return (timer1->pipe[PIPE_READ] == timer2->pipe[PIPE_READ]) ? CMP_MATCH | CMP_STOP : 0; 00330 }
static void pthread_timer_destructor | ( | void * | obj | ) | [static] |
Definition at line 297 of file res_timing_pthread.c.
References PIPE_READ, PIPE_WRITE, and timer.
Referenced by pthread_timer_open().
00298 { 00299 struct pthread_timer *timer = obj; 00300 00301 if (timer->pipe[PIPE_READ] > -1) { 00302 close(timer->pipe[PIPE_READ]); 00303 timer->pipe[PIPE_READ] = -1; 00304 } 00305 00306 if (timer->pipe[PIPE_WRITE] > -1) { 00307 close(timer->pipe[PIPE_WRITE]); 00308 timer->pipe[PIPE_WRITE] = -1; 00309 } 00310 }
static int pthread_timer_disable_continuous | ( | int | handle | ) | [static] |
Definition at line 231 of file res_timing_pthread.c.
References ao2_lock, ao2_ref, ao2_unlock, errno, find_timer(), read_pipe(), and timer.
00232 { 00233 struct pthread_timer *timer; 00234 00235 if (!(timer = find_timer(handle, 0))) { 00236 errno = EINVAL; 00237 return -1; 00238 } 00239 00240 ao2_lock(timer); 00241 if (timer->continuous) { 00242 timer->continuous = 0; 00243 read_pipe(timer, 1); 00244 } 00245 ao2_unlock(timer); 00246 00247 ao2_ref(timer, -1); 00248 00249 return 0; 00250 }
static int pthread_timer_enable_continuous | ( | int | handle | ) | [static] |
Definition at line 210 of file res_timing_pthread.c.
References ao2_lock, ao2_ref, ao2_unlock, errno, find_timer(), timer, and write_byte().
00211 { 00212 struct pthread_timer *timer; 00213 00214 if (!(timer = find_timer(handle, 0))) { 00215 errno = EINVAL; 00216 return -1; 00217 } 00218 00219 ao2_lock(timer); 00220 if (!timer->continuous) { 00221 timer->continuous = 1; 00222 write_byte(timer); 00223 } 00224 ao2_unlock(timer); 00225 00226 ao2_ref(timer, -1); 00227 00228 return 0; 00229 }
static enum ast_timer_event pthread_timer_get_event | ( | int | handle | ) | [static] |
Definition at line 252 of file res_timing_pthread.c.
References ao2_lock, ao2_ref, ao2_unlock, AST_TIMING_EVENT_CONTINUOUS, AST_TIMING_EVENT_EXPIRED, find_timer(), and timer.
00253 { 00254 struct pthread_timer *timer; 00255 enum ast_timer_event res = AST_TIMING_EVENT_EXPIRED; 00256 00257 if (!(timer = find_timer(handle, 0))) { 00258 return res; 00259 } 00260 00261 ao2_lock(timer); 00262 if (timer->continuous && timer->pending_ticks == 1) { 00263 res = AST_TIMING_EVENT_CONTINUOUS; 00264 } 00265 ao2_unlock(timer); 00266 00267 ao2_ref(timer, -1); 00268 00269 return res; 00270 }
static unsigned int pthread_timer_get_max_rate | ( | int | handle | ) | [static] |
Definition at line 272 of file res_timing_pthread.c.
References MAX_RATE.
00273 { 00274 return MAX_RATE; 00275 }
static int pthread_timer_hash | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 315 of file res_timing_pthread.c.
References PIPE_READ, and timer.
Referenced by load_module().
00316 { 00317 const struct pthread_timer *timer = obj; 00318 00319 return timer->pipe[PIPE_READ]; 00320 }
static int pthread_timer_open | ( | void | ) | [static] |
Definition at line 112 of file res_timing_pthread.c.
References ao2_alloc, ao2_container_count(), ao2_link, ao2_lock, ao2_ref, ao2_unlock, ast_cond_signal, ast_mutex_lock, ast_mutex_unlock, errno, pthread_timer::pipe, PIPE_READ, PIPE_WRITE, pthread_timer_destructor(), pthread_timers, timer, TIMER_STATE_IDLE, and timing_thread.
00113 { 00114 struct pthread_timer *timer; 00115 int fd; 00116 00117 if (!(timer = ao2_alloc(sizeof(*timer), pthread_timer_destructor))) { 00118 errno = ENOMEM; 00119 return -1; 00120 } 00121 00122 timer->pipe[PIPE_READ] = timer->pipe[PIPE_WRITE] = -1; 00123 timer->state = TIMER_STATE_IDLE; 00124 00125 if (pipe(timer->pipe)) { 00126 ao2_ref(timer, -1); 00127 return -1; 00128 } 00129 00130 ao2_lock(pthread_timers); 00131 if (!ao2_container_count(pthread_timers)) { 00132 ast_mutex_lock(&timing_thread.lock); 00133 ast_cond_signal(&timing_thread.cond); 00134 ast_mutex_unlock(&timing_thread.lock); 00135 } 00136 ao2_link(pthread_timers, timer); 00137 ao2_unlock(pthread_timers); 00138 00139 fd = timer->pipe[PIPE_READ]; 00140 00141 ao2_ref(timer, -1); 00142 00143 return fd; 00144 }
static int pthread_timer_set_rate | ( | int | handle, | |
unsigned int | rate | |||
) | [static] |
Definition at line 157 of file res_timing_pthread.c.
References ao2_lock, ao2_ref, ao2_unlock, ast_log(), ast_tv(), ast_tvnow(), errno, find_timer(), LOG_ERROR, MAX_RATE, timer, TIMER_STATE_IDLE, and TIMER_STATE_TICKING.
00158 { 00159 struct pthread_timer *timer; 00160 00161 if (!(timer = find_timer(handle, 0))) { 00162 errno = EINVAL; 00163 return -1; 00164 } 00165 00166 if (rate > MAX_RATE) { 00167 ast_log(LOG_ERROR, "res_timing_pthread only supports timers at a " 00168 "max rate of %d / sec\n", MAX_RATE); 00169 errno = EINVAL; 00170 return -1; 00171 } 00172 00173 ao2_lock(timer); 00174 00175 if ((timer->rate = rate)) { 00176 timer->interval = roundf(1000.0 / ((float) rate)); 00177 timer->start = ast_tvnow(); 00178 timer->state = TIMER_STATE_TICKING; 00179 } else { 00180 timer->interval = 0; 00181 timer->start = ast_tv(0, 0); 00182 timer->state = TIMER_STATE_IDLE; 00183 } 00184 timer->tick_count = 0; 00185 00186 ao2_unlock(timer); 00187 00188 ao2_ref(timer, -1); 00189 00190 return 0; 00191 }
static void read_pipe | ( | struct pthread_timer * | timer, | |
unsigned int | num | |||
) | [static] |
Definition at line 362 of file res_timing_pthread.c.
References ast_assert, ast_debug, ast_log(), ast_poll, errno, LOG_ERROR, PIPE_READ, and timer.
Referenced by pthread_timer_ack(), and pthread_timer_disable_continuous().
00363 { 00364 int rd_fd = timer->pipe[PIPE_READ]; 00365 int pending_ticks = timer->pending_ticks; 00366 00367 ast_assert(quantity); 00368 00369 if (timer->continuous && pending_ticks) { 00370 pending_ticks--; 00371 } 00372 00373 if (quantity > pending_ticks) { 00374 quantity = pending_ticks; 00375 } 00376 00377 if (!quantity) { 00378 return; 00379 } 00380 00381 do { 00382 unsigned char buf[1024]; 00383 ssize_t res; 00384 struct pollfd pfd = { 00385 .fd = rd_fd, 00386 .events = POLLIN, 00387 }; 00388 00389 if (ast_poll(&pfd, 1, 0) != 1) { 00390 ast_debug(1, "Reading not available on timing pipe, " 00391 "quantity: %u\n", quantity); 00392 break; 00393 } 00394 00395 res = read(rd_fd, buf, 00396 (quantity < sizeof(buf)) ? quantity : sizeof(buf)); 00397 00398 if (res == -1) { 00399 if (errno == EAGAIN) { 00400 continue; 00401 } 00402 ast_log(LOG_ERROR, "read failed on timing pipe: %s\n", 00403 strerror(errno)); 00404 break; 00405 } 00406 00407 quantity -= res; 00408 timer->pending_ticks -= res; 00409 } while (quantity); 00410 }
static int run_timer | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 433 of file res_timing_pthread.c.
References ao2_lock, ao2_unlock, check_timer(), timer, TIMER_STATE_IDLE, and write_byte().
Referenced by do_timing().
00434 { 00435 struct pthread_timer *timer = obj; 00436 00437 if (timer->state == TIMER_STATE_IDLE) { 00438 return 0; 00439 } 00440 00441 ao2_lock(timer); 00442 if (check_timer(timer)) { 00443 write_byte(timer); 00444 } 00445 ao2_unlock(timer); 00446 00447 return 0; 00448 }
static int unload_module | ( | void | ) | [static] |
Definition at line 508 of file res_timing_pthread.c.
References ao2_ref, ast_cond_signal, ast_mutex_lock, ast_mutex_unlock, ast_unregister_timing_interface(), pthread_timers, timing_funcs_handle, and timing_thread.
00509 { 00510 int res; 00511 00512 ast_mutex_lock(&timing_thread.lock); 00513 timing_thread.stop = 1; 00514 ast_cond_signal(&timing_thread.cond); 00515 ast_mutex_unlock(&timing_thread.lock); 00516 pthread_join(timing_thread.thread, NULL); 00517 00518 if (!(res = ast_unregister_timing_interface(timing_funcs_handle))) { 00519 ao2_ref(pthread_timers, -1); 00520 pthread_timers = NULL; 00521 } 00522 00523 return res; 00524 }
static void write_byte | ( | struct pthread_timer * | timer | ) | [static] |
Definition at line 416 of file res_timing_pthread.c.
References ast_log(), errno, LOG_ERROR, PIPE_WRITE, and timer.
Referenced by pthread_timer_enable_continuous(), and run_timer().
00417 { 00418 ssize_t res; 00419 unsigned char x = 42; 00420 00421 do { 00422 res = write(timer->pipe[PIPE_WRITE], &x, 1); 00423 } while (res == -1 && errno == EAGAIN); 00424 00425 if (res == -1) { 00426 ast_log(LOG_ERROR, "Error writing to timing pipe: %s\n", 00427 strerror(errno)); 00428 } else { 00429 timer->pending_ticks++; 00430 } 00431 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "pthread 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 529 of file res_timing_pthread.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 529 of file res_timing_pthread.c.
Definition at line 108 of file res_timing_pthread.c.
Definition at line 107 of file res_timing_pthread.c.
struct ao2_container* pthread_timers [static] |
Definition at line 72 of file res_timing_pthread.c.
Referenced by do_timing(), find_timer(), load_module(), pthread_timer_open(), and unload_module().
struct ast_timing_interface pthread_timing [static] |
unsigned int stop |
Definition at line 109 of file res_timing_pthread.c.
pthread_t thread |
Definition at line 106 of file res_timing_pthread.c.
void* timing_funcs_handle [static] |
Definition at line 45 of file res_timing_pthread.c.
struct { ... } timing_thread [static] |
Data for the timing thread.
Referenced by do_timing(), init_timing_thread(), pthread_timer_open(), and unload_module().