#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: 278465 $") | |
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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } |
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 66 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 71 of file res_timing_pthread.c.
00071 { 00072 PIPE_READ = 0, 00073 PIPE_WRITE = 1 00074 };
enum pthread_timer_state |
Definition at line 76 of file res_timing_pthread.c.
00076 { 00077 TIMER_STATE_IDLE, 00078 TIMER_STATE_TICKING, 00079 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 525 of file res_timing_pthread.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 525 of file res_timing_pthread.c.
ASTERISK_FILE_VERSION | ( | __FILE__ | , | |
"$Revision: 278465 $" | ||||
) |
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 332 of file res_timing_pthread.c.
References ast_tvdiff_ms(), ast_tvnow(), timer, and TIMER_STATE_IDLE.
Referenced by run_timer().
00333 { 00334 struct timeval now; 00335 00336 if (timer->state == TIMER_STATE_IDLE) { 00337 return 0; 00338 } 00339 00340 now = ast_tvnow(); 00341 00342 if (timer->tick_count < (ast_tvdiff_ms(now, timer->start) / timer->interval)) { 00343 timer->tick_count++; 00344 if (!timer->tick_count) { 00345 /* Handle overflow. */ 00346 timer->start = now; 00347 } 00348 return 1; 00349 } 00350 00351 return 0; 00352 }
static void* do_timing | ( | void * | arg | ) | [static] |
Definition at line 446 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().
00447 { 00448 struct timeval next_wakeup = ast_tvnow(); 00449 00450 while (!timing_thread.stop) { 00451 struct timespec ts = { 0, }; 00452 00453 ao2_callback(pthread_timers, OBJ_NODATA, run_timer, NULL); 00454 00455 next_wakeup = ast_tvadd(next_wakeup, ast_tv(0, 5000)); 00456 00457 ts.tv_sec = next_wakeup.tv_sec; 00458 ts.tv_nsec = next_wakeup.tv_usec * 1000; 00459 00460 ast_mutex_lock(&timing_thread.lock); 00461 if (!timing_thread.stop) { 00462 if (ao2_container_count(pthread_timers)) { 00463 ast_cond_timedwait(&timing_thread.cond, &timing_thread.lock, &ts); 00464 } else { 00465 ast_cond_wait(&timing_thread.cond, &timing_thread.lock); 00466 } 00467 } 00468 ast_mutex_unlock(&timing_thread.lock); 00469 } 00470 00471 return NULL; 00472 }
static struct pthread_timer * find_timer | ( | int | handle, | |
int | unlinkobj | |||
) | [static] |
Definition at line 273 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().
00274 { 00275 struct pthread_timer *timer; 00276 struct pthread_timer tmp_timer; 00277 int flags = OBJ_POINTER; 00278 00279 tmp_timer.pipe[PIPE_READ] = handle; 00280 00281 if (unlinkobj) { 00282 flags |= OBJ_UNLINK; 00283 } 00284 00285 if (!(timer = ao2_find(pthread_timers, &tmp_timer, flags))) { 00286 ast_assert(timer != NULL); 00287 return NULL; 00288 } 00289 00290 return timer; 00291 }
static int init_timing_thread | ( | void | ) | [static] |
Definition at line 474 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().
00475 { 00476 ast_mutex_init(&timing_thread.lock); 00477 ast_cond_init(&timing_thread.cond, NULL); 00478 00479 if (ast_pthread_create_background(&timing_thread.thread, NULL, do_timing, NULL)) { 00480 ast_log(LOG_ERROR, "Unable to start timing thread.\n"); 00481 return -1; 00482 } 00483 00484 return 0; 00485 }
static int load_module | ( | void | ) | [static] |
Definition at line 487 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.
00488 { 00489 if (!(pthread_timers = ao2_container_alloc(PTHREAD_TIMER_BUCKETS, 00490 pthread_timer_hash, pthread_timer_cmp))) { 00491 return AST_MODULE_LOAD_DECLINE; 00492 } 00493 00494 if (init_timing_thread()) { 00495 ao2_ref(pthread_timers, -1); 00496 pthread_timers = NULL; 00497 return AST_MODULE_LOAD_DECLINE; 00498 } 00499 00500 return (timing_funcs_handle = ast_register_timing_interface(&pthread_timing)) ? 00501 AST_MODULE_LOAD_SUCCESS : AST_MODULE_LOAD_DECLINE; 00502 }
static void pthread_timer_ack | ( | int | handle, | |
unsigned int | quantity | |||
) | [static] |
Definition at line 189 of file res_timing_pthread.c.
References ao2_lock, ao2_ref, ao2_unlock, ast_assert, find_timer(), read_pipe(), and timer.
00190 { 00191 struct pthread_timer *timer; 00192 00193 ast_assert(quantity > 0); 00194 00195 if (!(timer = find_timer(handle, 0))) { 00196 return; 00197 } 00198 00199 ao2_lock(timer); 00200 read_pipe(timer, quantity); 00201 ao2_unlock(timer); 00202 00203 ao2_ref(timer, -1); 00204 }
static void pthread_timer_close | ( | int | handle | ) | [static] |
Definition at line 142 of file res_timing_pthread.c.
References ao2_ref, find_timer(), and timer.
00143 { 00144 struct pthread_timer *timer; 00145 00146 if (!(timer = find_timer(handle, 1))) { 00147 return; 00148 } 00149 00150 ao2_ref(timer, -1); 00151 }
static int pthread_timer_cmp | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 321 of file res_timing_pthread.c.
References CMP_MATCH, CMP_STOP, pthread_timer::pipe, and PIPE_READ.
Referenced by load_module().
00322 { 00323 struct pthread_timer *timer1 = obj, *timer2 = arg; 00324 00325 return (timer1->pipe[PIPE_READ] == timer2->pipe[PIPE_READ]) ? CMP_MATCH | CMP_STOP : 0; 00326 }
static void pthread_timer_destructor | ( | void * | obj | ) | [static] |
Definition at line 293 of file res_timing_pthread.c.
References PIPE_READ, PIPE_WRITE, and timer.
Referenced by pthread_timer_open().
00294 { 00295 struct pthread_timer *timer = obj; 00296 00297 if (timer->pipe[PIPE_READ] > -1) { 00298 close(timer->pipe[PIPE_READ]); 00299 timer->pipe[PIPE_READ] = -1; 00300 } 00301 00302 if (timer->pipe[PIPE_WRITE] > -1) { 00303 close(timer->pipe[PIPE_WRITE]); 00304 timer->pipe[PIPE_WRITE] = -1; 00305 } 00306 }
static int pthread_timer_disable_continuous | ( | int | handle | ) | [static] |
Definition at line 227 of file res_timing_pthread.c.
References ao2_lock, ao2_ref, ao2_unlock, errno, find_timer(), read_pipe(), and timer.
00228 { 00229 struct pthread_timer *timer; 00230 00231 if (!(timer = find_timer(handle, 0))) { 00232 errno = EINVAL; 00233 return -1; 00234 } 00235 00236 ao2_lock(timer); 00237 if (timer->continuous) { 00238 timer->continuous = 0; 00239 read_pipe(timer, 1); 00240 } 00241 ao2_unlock(timer); 00242 00243 ao2_ref(timer, -1); 00244 00245 return 0; 00246 }
static int pthread_timer_enable_continuous | ( | int | handle | ) | [static] |
Definition at line 206 of file res_timing_pthread.c.
References ao2_lock, ao2_ref, ao2_unlock, errno, find_timer(), timer, and write_byte().
00207 { 00208 struct pthread_timer *timer; 00209 00210 if (!(timer = find_timer(handle, 0))) { 00211 errno = EINVAL; 00212 return -1; 00213 } 00214 00215 ao2_lock(timer); 00216 if (!timer->continuous) { 00217 timer->continuous = 1; 00218 write_byte(timer); 00219 } 00220 ao2_unlock(timer); 00221 00222 ao2_ref(timer, -1); 00223 00224 return 0; 00225 }
static enum ast_timer_event pthread_timer_get_event | ( | int | handle | ) | [static] |
Definition at line 248 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.
00249 { 00250 struct pthread_timer *timer; 00251 enum ast_timer_event res = AST_TIMING_EVENT_EXPIRED; 00252 00253 if (!(timer = find_timer(handle, 0))) { 00254 return res; 00255 } 00256 00257 ao2_lock(timer); 00258 if (timer->continuous && timer->pending_ticks == 1) { 00259 res = AST_TIMING_EVENT_CONTINUOUS; 00260 } 00261 ao2_unlock(timer); 00262 00263 ao2_ref(timer, -1); 00264 00265 return res; 00266 }
static unsigned int pthread_timer_get_max_rate | ( | int | handle | ) | [static] |
Definition at line 268 of file res_timing_pthread.c.
References MAX_RATE.
00269 { 00270 return MAX_RATE; 00271 }
static int pthread_timer_hash | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 311 of file res_timing_pthread.c.
References PIPE_READ, and timer.
Referenced by load_module().
00312 { 00313 const struct pthread_timer *timer = obj; 00314 00315 return timer->pipe[PIPE_READ]; 00316 }
static int pthread_timer_open | ( | void | ) | [static] |
Definition at line 108 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.
00109 { 00110 struct pthread_timer *timer; 00111 int fd; 00112 00113 if (!(timer = ao2_alloc(sizeof(*timer), pthread_timer_destructor))) { 00114 errno = ENOMEM; 00115 return -1; 00116 } 00117 00118 timer->pipe[PIPE_READ] = timer->pipe[PIPE_WRITE] = -1; 00119 timer->state = TIMER_STATE_IDLE; 00120 00121 if (pipe(timer->pipe)) { 00122 ao2_ref(timer, -1); 00123 return -1; 00124 } 00125 00126 ao2_lock(pthread_timers); 00127 if (!ao2_container_count(pthread_timers)) { 00128 ast_mutex_lock(&timing_thread.lock); 00129 ast_cond_signal(&timing_thread.cond); 00130 ast_mutex_unlock(&timing_thread.lock); 00131 } 00132 ao2_link(pthread_timers, timer); 00133 ao2_unlock(pthread_timers); 00134 00135 fd = timer->pipe[PIPE_READ]; 00136 00137 ao2_ref(timer, -1); 00138 00139 return fd; 00140 }
static int pthread_timer_set_rate | ( | int | handle, | |
unsigned int | rate | |||
) | [static] |
Definition at line 153 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.
00154 { 00155 struct pthread_timer *timer; 00156 00157 if (!(timer = find_timer(handle, 0))) { 00158 errno = EINVAL; 00159 return -1; 00160 } 00161 00162 if (rate > MAX_RATE) { 00163 ast_log(LOG_ERROR, "res_timing_pthread only supports timers at a " 00164 "max rate of %d / sec\n", MAX_RATE); 00165 errno = EINVAL; 00166 return -1; 00167 } 00168 00169 ao2_lock(timer); 00170 00171 if ((timer->rate = rate)) { 00172 timer->interval = roundf(1000.0 / ((float) rate)); 00173 timer->start = ast_tvnow(); 00174 timer->state = TIMER_STATE_TICKING; 00175 } else { 00176 timer->interval = 0; 00177 timer->start = ast_tv(0, 0); 00178 timer->state = TIMER_STATE_IDLE; 00179 } 00180 timer->tick_count = 0; 00181 00182 ao2_unlock(timer); 00183 00184 ao2_ref(timer, -1); 00185 00186 return 0; 00187 }
static void read_pipe | ( | struct pthread_timer * | timer, | |
unsigned int | num | |||
) | [static] |
Definition at line 358 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().
00359 { 00360 int rd_fd = timer->pipe[PIPE_READ]; 00361 int pending_ticks = timer->pending_ticks; 00362 00363 ast_assert(quantity); 00364 00365 if (timer->continuous && pending_ticks) { 00366 pending_ticks--; 00367 } 00368 00369 if (quantity > pending_ticks) { 00370 quantity = pending_ticks; 00371 } 00372 00373 if (!quantity) { 00374 return; 00375 } 00376 00377 do { 00378 unsigned char buf[1024]; 00379 ssize_t res; 00380 struct pollfd pfd = { 00381 .fd = rd_fd, 00382 .events = POLLIN, 00383 }; 00384 00385 if (ast_poll(&pfd, 1, 0) != 1) { 00386 ast_debug(1, "Reading not available on timing pipe, " 00387 "quantity: %u\n", quantity); 00388 break; 00389 } 00390 00391 res = read(rd_fd, buf, 00392 (quantity < sizeof(buf)) ? quantity : sizeof(buf)); 00393 00394 if (res == -1) { 00395 if (errno == EAGAIN) { 00396 continue; 00397 } 00398 ast_log(LOG_ERROR, "read failed on timing pipe: %s\n", 00399 strerror(errno)); 00400 break; 00401 } 00402 00403 quantity -= res; 00404 timer->pending_ticks -= res; 00405 } while (quantity); 00406 }
static int run_timer | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 429 of file res_timing_pthread.c.
References ao2_lock, ao2_unlock, check_timer(), timer, TIMER_STATE_IDLE, and write_byte().
Referenced by do_timing().
00430 { 00431 struct pthread_timer *timer = obj; 00432 00433 if (timer->state == TIMER_STATE_IDLE) { 00434 return 0; 00435 } 00436 00437 ao2_lock(timer); 00438 if (check_timer(timer)) { 00439 write_byte(timer); 00440 } 00441 ao2_unlock(timer); 00442 00443 return 0; 00444 }
static int unload_module | ( | void | ) | [static] |
Definition at line 504 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.
00505 { 00506 int res; 00507 00508 ast_mutex_lock(&timing_thread.lock); 00509 timing_thread.stop = 1; 00510 ast_cond_signal(&timing_thread.cond); 00511 ast_mutex_unlock(&timing_thread.lock); 00512 pthread_join(timing_thread.thread, NULL); 00513 00514 if (!(res = ast_unregister_timing_interface(timing_funcs_handle))) { 00515 ao2_ref(pthread_timers, -1); 00516 pthread_timers = NULL; 00517 } 00518 00519 return res; 00520 }
static void write_byte | ( | struct pthread_timer * | timer | ) | [static] |
Definition at line 412 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().
00413 { 00414 ssize_t res; 00415 unsigned char x = 42; 00416 00417 do { 00418 res = write(timer->pipe[PIPE_WRITE], &x, 1); 00419 } while (res == -1 && errno == EAGAIN); 00420 00421 if (res == -1) { 00422 ast_log(LOG_ERROR, "Error writing to timing pipe: %s\n", 00423 strerror(errno)); 00424 } else { 00425 timer->pending_ticks++; 00426 } 00427 }
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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } [static] |
Definition at line 525 of file res_timing_pthread.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 525 of file res_timing_pthread.c.
Definition at line 104 of file res_timing_pthread.c.
Definition at line 103 of file res_timing_pthread.c.
struct ao2_container* pthread_timers [static] |
Definition at line 68 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 105 of file res_timing_pthread.c.
pthread_t thread |
Definition at line 102 of file res_timing_pthread.c.
void* timing_funcs_handle [static] |
Definition at line 41 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().