pthread timing interface More...
#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: 278479 $") | |
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 __MODULE_INFO_SECTION | __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "pthread Timing Interface" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .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 |
pthread timing interface
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 |
Definition at line 69 of file res_timing_pthread.c.
Referenced by load_module().
anonymous enum |
Definition at line 71 of file res_timing_pthread.c.
{ PIPE_READ = 0, PIPE_WRITE = 1 };
enum pthread_timer_state |
Definition at line 76 of file res_timing_pthread.c.
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: 278479 $" | |||
) |
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(), pthread_timer::interval, pthread_timer::start, pthread_timer::state, pthread_timer::tick_count, and TIMER_STATE_IDLE.
Referenced by run_timer().
{ struct timeval now; if (timer->state == TIMER_STATE_IDLE) { return 0; } now = ast_tvnow(); if (timer->tick_count < (ast_tvdiff_ms(now, timer->start) / timer->interval)) { timer->tick_count++; if (!timer->tick_count) { /* Handle overflow. */ timer->start = now; } return 1; } return 0; }
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, run_timer(), and timing_thread.
Referenced by init_timing_thread().
{ struct timeval next_wakeup = ast_tvnow(); while (!timing_thread.stop) { struct timespec ts = { 0, }; ao2_callback(pthread_timers, OBJ_NODATA, run_timer, NULL); next_wakeup = ast_tvadd(next_wakeup, ast_tv(0, 5000)); ts.tv_sec = next_wakeup.tv_sec; ts.tv_nsec = next_wakeup.tv_usec * 1000; ast_mutex_lock(&timing_thread.lock); if (!timing_thread.stop) { if (ao2_container_count(pthread_timers)) { ast_cond_timedwait(&timing_thread.cond, &timing_thread.lock, &ts); } else { ast_cond_wait(&timing_thread.cond, &timing_thread.lock); } } ast_mutex_unlock(&timing_thread.lock); } return NULL; }
static struct pthread_timer * find_timer | ( | int | handle, |
int | unlinkobj | ||
) | [static, read] |
Definition at line 273 of file res_timing_pthread.c.
References ao2_find, ast_assert, OBJ_POINTER, OBJ_UNLINK, pthread_timer::pipe, PIPE_READ, 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().
{ struct pthread_timer *timer; struct pthread_timer tmp_timer; int flags = OBJ_POINTER; tmp_timer.pipe[PIPE_READ] = handle; if (unlinkobj) { flags |= OBJ_UNLINK; } if (!(timer = ao2_find(pthread_timers, &tmp_timer, flags))) { ast_assert(timer != NULL); return NULL; } return timer; }
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().
{ ast_mutex_init(&timing_thread.lock); ast_cond_init(&timing_thread.cond, NULL); if (ast_pthread_create_background(&timing_thread.thread, NULL, do_timing, NULL)) { ast_log(LOG_ERROR, "Unable to start timing thread.\n"); return -1; } return 0; }
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(), and timing_funcs_handle.
{ if (!(pthread_timers = ao2_container_alloc(PTHREAD_TIMER_BUCKETS, pthread_timer_hash, pthread_timer_cmp))) { return AST_MODULE_LOAD_DECLINE; } if (init_timing_thread()) { ao2_ref(pthread_timers, -1); pthread_timers = NULL; return AST_MODULE_LOAD_DECLINE; } return (timing_funcs_handle = ast_register_timing_interface(&pthread_timing)) ? AST_MODULE_LOAD_SUCCESS : AST_MODULE_LOAD_DECLINE; }
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.
{ struct pthread_timer *timer; ast_assert(quantity > 0); if (!(timer = find_timer(handle, 0))) { return; } ao2_lock(timer); read_pipe(timer, quantity); ao2_unlock(timer); ao2_ref(timer, -1); }
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.
{ struct pthread_timer *timer; if (!(timer = find_timer(handle, 1))) { return; } ao2_ref(timer, -1); }
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().
static void pthread_timer_destructor | ( | void * | obj | ) | [static] |
Definition at line 293 of file res_timing_pthread.c.
References pthread_timer::pipe, PIPE_READ, PIPE_WRITE, and timer.
Referenced by pthread_timer_open().
{ struct pthread_timer *timer = obj; if (timer->pipe[PIPE_READ] > -1) { close(timer->pipe[PIPE_READ]); timer->pipe[PIPE_READ] = -1; } if (timer->pipe[PIPE_WRITE] > -1) { close(timer->pipe[PIPE_WRITE]); timer->pipe[PIPE_WRITE] = -1; } }
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(), pthread_timer::continuous, errno, find_timer(), read_pipe(), and timer.
{ struct pthread_timer *timer; if (!(timer = find_timer(handle, 0))) { errno = EINVAL; return -1; } ao2_lock(timer); if (timer->continuous) { timer->continuous = 0; read_pipe(timer, 1); } ao2_unlock(timer); ao2_ref(timer, -1); return 0; }
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(), pthread_timer::continuous, errno, find_timer(), timer, and write_byte().
{ struct pthread_timer *timer; if (!(timer = find_timer(handle, 0))) { errno = EINVAL; return -1; } ao2_lock(timer); if (!timer->continuous) { timer->continuous = 1; write_byte(timer); } ao2_unlock(timer); ao2_ref(timer, -1); return 0; }
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, pthread_timer::continuous, find_timer(), pthread_timer::pending_ticks, and timer.
{ struct pthread_timer *timer; enum ast_timer_event res = AST_TIMING_EVENT_EXPIRED; if (!(timer = find_timer(handle, 0))) { return res; } ao2_lock(timer); if (timer->continuous && timer->pending_ticks == 1) { res = AST_TIMING_EVENT_CONTINUOUS; } ao2_unlock(timer); ao2_ref(timer, -1); return res; }
static unsigned int pthread_timer_get_max_rate | ( | int | handle | ) | [static] |
static int pthread_timer_hash | ( | const void * | obj, |
const int | flags | ||
) | [static] |
Definition at line 311 of file res_timing_pthread.c.
References pthread_timer::pipe, PIPE_READ, and timer.
Referenced by load_module().
{ const struct pthread_timer *timer = obj; return timer->pipe[PIPE_READ]; }
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_timer::state, timer, TIMER_STATE_IDLE, and timing_thread.
{ struct pthread_timer *timer; int fd; if (!(timer = ao2_alloc(sizeof(*timer), pthread_timer_destructor))) { errno = ENOMEM; return -1; } timer->pipe[PIPE_READ] = timer->pipe[PIPE_WRITE] = -1; timer->state = TIMER_STATE_IDLE; if (pipe(timer->pipe)) { ao2_ref(timer, -1); return -1; } ao2_lock(pthread_timers); if (!ao2_container_count(pthread_timers)) { ast_mutex_lock(&timing_thread.lock); ast_cond_signal(&timing_thread.cond); ast_mutex_unlock(&timing_thread.lock); } ao2_link(pthread_timers, timer); ao2_unlock(pthread_timers); fd = timer->pipe[PIPE_READ]; ao2_ref(timer, -1); return fd; }
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(), pthread_timer::interval, LOG_ERROR, MAX_RATE, pthread_timer::rate, pthread_timer::start, pthread_timer::state, pthread_timer::tick_count, timer, TIMER_STATE_IDLE, and TIMER_STATE_TICKING.
{ struct pthread_timer *timer; if (!(timer = find_timer(handle, 0))) { errno = EINVAL; return -1; } if (rate > MAX_RATE) { ast_log(LOG_ERROR, "res_timing_pthread only supports timers at a " "max rate of %d / sec\n", MAX_RATE); errno = EINVAL; return -1; } ao2_lock(timer); if ((timer->rate = rate)) { timer->interval = roundf(1000.0 / ((float) rate)); timer->start = ast_tvnow(); timer->state = TIMER_STATE_TICKING; } else { timer->interval = 0; timer->start = ast_tv(0, 0); timer->state = TIMER_STATE_IDLE; } timer->tick_count = 0; ao2_unlock(timer); ao2_ref(timer, -1); return 0; }
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, buf, pthread_timer::continuous, errno, LOG_ERROR, pthread_timer::pending_ticks, pthread_timer::pipe, and PIPE_READ.
Referenced by pthread_timer_ack(), and pthread_timer_disable_continuous().
{ int rd_fd = timer->pipe[PIPE_READ]; int pending_ticks = timer->pending_ticks; ast_assert(quantity); if (timer->continuous && pending_ticks) { pending_ticks--; } if (quantity > pending_ticks) { quantity = pending_ticks; } if (!quantity) { return; } do { unsigned char buf[1024]; ssize_t res; struct pollfd pfd = { .fd = rd_fd, .events = POLLIN, }; if (ast_poll(&pfd, 1, 0) != 1) { ast_debug(1, "Reading not available on timing pipe, " "quantity: %u\n", quantity); break; } res = read(rd_fd, buf, (quantity < sizeof(buf)) ? quantity : sizeof(buf)); if (res == -1) { if (errno == EAGAIN) { continue; } ast_log(LOG_ERROR, "read failed on timing pipe: %s\n", strerror(errno)); break; } quantity -= res; timer->pending_ticks -= res; } while (quantity); }
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(), pthread_timer::state, timer, TIMER_STATE_IDLE, and write_byte().
Referenced by do_timing().
{ struct pthread_timer *timer = obj; if (timer->state == TIMER_STATE_IDLE) { return 0; } ao2_lock(timer); if (check_timer(timer)) { write_byte(timer); } ao2_unlock(timer); return 0; }
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(), timing_funcs_handle, and timing_thread.
{ int res; ast_mutex_lock(&timing_thread.lock); timing_thread.stop = 1; ast_cond_signal(&timing_thread.cond); ast_mutex_unlock(&timing_thread.lock); pthread_join(timing_thread.thread, NULL); if (!(res = ast_unregister_timing_interface(timing_funcs_handle))) { ao2_ref(pthread_timers, -1); pthread_timers = NULL; } return res; }
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, pthread_timer::pending_ticks, pthread_timer::pipe, and PIPE_WRITE.
Referenced by pthread_timer_enable_continuous(), and run_timer().
{ ssize_t res; unsigned char x = 42; do { res = write(timer->pipe[PIPE_WRITE], &x, 1); } while (res == -1 && errno == EAGAIN); if (res == -1) { ast_log(LOG_ERROR, "Error writing to timing pipe: %s\n", strerror(errno)); } else { timer->pending_ticks++; } }
struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "pthread Timing Interface" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = 10, } [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.
struct ast_timing_interface pthread_timing [static] |
Definition at line 52 of file res_timing_pthread.c.
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.
Referenced by load_module(), and unload_module().
struct { ... } timing_thread [static] |
Referenced by do_timing(), init_timing_thread(), pthread_timer_open(), and unload_module().