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