44 static void *timing_funcs_handle;
46 static void *pthread_timer_open(
void);
47 static void pthread_timer_close(
void *data);
48 static int pthread_timer_set_rate(
void *data,
unsigned int rate);
49 static int pthread_timer_ack(
void *data,
unsigned int quantity);
50 static int pthread_timer_enable_continuous(
void *data);
51 static int pthread_timer_disable_continuous(
void *data);
52 static enum ast_timer_event pthread_timer_get_event(
void *data);
53 static unsigned int pthread_timer_get_max_rate(
void *data);
54 static int pthread_timer_fd(
void *data);
59 .timer_open = pthread_timer_open,
60 .timer_close = pthread_timer_close,
61 .timer_set_rate = pthread_timer_set_rate,
62 .timer_ack = pthread_timer_ack,
63 .timer_enable_continuous = pthread_timer_enable_continuous,
64 .timer_disable_continuous = pthread_timer_disable_continuous,
65 .timer_get_event = pthread_timer_get_event,
66 .timer_get_max_rate = pthread_timer_get_max_rate,
67 .timer_fd = pthread_timer_fd,
74 #define PTHREAD_TIMER_BUCKETS 563
81 enum pthread_timer_state {
88 enum pthread_timer_state
state;
92 unsigned int tick_count;
93 unsigned int pending_ticks;
99 static void pthread_timer_destructor(
void *obj);
102 static void ack_ticks(
struct pthread_timer *timer,
unsigned int num);
114 static void *pthread_timer_open(
void)
118 if (!(timer = ao2_alloc(
sizeof(*timer), pthread_timer_destructor))) {
123 timer->pipe[PIPE_READ] = timer->pipe[PIPE_WRITE] = -1;
124 timer->state = TIMER_STATE_IDLE;
131 ao2_lock(pthread_timers);
138 ao2_unlock(pthread_timers);
143 static void pthread_timer_close(
void *data)
151 static int pthread_timer_set_rate(
void *data,
unsigned int rate)
155 if (rate > MAX_RATE) {
156 ast_log(LOG_ERROR,
"res_timing_pthread only supports timers at a "
157 "max rate of %d / sec\n", MAX_RATE);
164 if ((timer->rate = rate)) {
165 timer->
interval = roundf(1000.0 / ((
float) rate));
167 timer->state = TIMER_STATE_TICKING;
170 timer->start =
ast_tv(0, 0);
171 timer->state = TIMER_STATE_IDLE;
173 timer->tick_count = 0;
180 static int pthread_timer_ack(
void *data,
unsigned int quantity)
184 ast_assert(quantity > 0);
187 ack_ticks(timer, quantity);
193 static int pthread_timer_enable_continuous(
void *data)
198 if (!timer->continuous) {
199 timer->continuous =
true;
207 static int pthread_timer_disable_continuous(
void *data)
212 if (timer->continuous) {
213 timer->continuous =
false;
214 unsignal_pipe(timer);
221 static enum ast_timer_event pthread_timer_get_event(
void *data)
224 enum ast_timer_event res = AST_TIMING_EVENT_EXPIRED;
227 if (timer->continuous) {
228 res = AST_TIMING_EVENT_CONTINUOUS;
235 static unsigned int pthread_timer_get_max_rate(
void *data)
240 static int pthread_timer_fd(
void *data)
244 return timer->pipe[PIPE_READ];
247 static void pthread_timer_destructor(
void *obj)
251 if (timer->pipe[PIPE_READ] > -1) {
252 close(timer->pipe[PIPE_READ]);
253 timer->pipe[PIPE_READ] = -1;
256 if (timer->pipe[PIPE_WRITE] > -1) {
257 close(timer->pipe[PIPE_WRITE]);
258 timer->pipe[PIPE_WRITE] = -1;
269 return timer->pipe[PIPE_READ];
279 return (timer1->pipe[PIPE_READ] == timer2->pipe[PIPE_READ]) ?
CMP_MATCH |
CMP_STOP : 0;
290 if (timer->state == TIMER_STATE_IDLE) {
298 if (!timer->tick_count) {
312 static void ack_ticks(
struct pthread_timer *timer,
unsigned int quantity)
314 int pending_ticks = timer->pending_ticks;
316 ast_assert(quantity);
318 if (quantity > pending_ticks) {
319 quantity = pending_ticks;
326 timer->pending_ticks -= quantity;
328 if ((0 == timer->pending_ticks) && !timer->continuous) {
329 unsignal_pipe(timer);
340 unsigned char x = 42;
342 if (timer->pipe_signaled) {
346 res = write(timer->pipe[PIPE_WRITE], &x, 1);
348 ast_log(LOG_ERROR,
"Error writing to timing pipe: %s\n",
351 timer->pipe_signaled =
true;
362 unsigned long buffer;
364 if (!timer->pipe_signaled) {
368 res = read(timer->pipe[PIPE_READ], &buffer,
sizeof(buffer));
370 ast_log(LOG_ERROR,
"Error reading from pipe: %s\n",
373 timer->pipe_signaled =
false;
377 static int run_timer(
void *obj,
void *arg,
int flags)
381 if (timer->state == TIMER_STATE_IDLE) {
387 timer->pending_ticks++;
395 static void *do_timing(
void *arg)
397 struct timeval next_wakeup =
ast_tvnow();
400 struct timespec ts = { 0, };
406 ts.tv_sec = next_wakeup.tv_sec;
407 ts.tv_nsec = next_wakeup.tv_usec * 1000;
423 static int init_timing_thread(
void)
428 if (ast_pthread_create_background(&
timing_thread.thread, NULL, do_timing, NULL)) {
429 ast_log(LOG_ERROR,
"Unable to start timing thread.\n");
436 static int load_module(
void)
440 if (!pthread_timers) {
444 if (init_timing_thread()) {
446 pthread_timers = NULL;
454 static int unload_module(
void)
466 pthread_timers = NULL;
471 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"pthread Timing Interface",
472 .support_level = AST_MODULE_SUPPORT_EXTENDED,
474 .unload = unload_module,
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ast_pipe_nonblock(filedes)
Create a non-blocking pipe.
static int check_timer(struct pthread_timer *timer)
Time-related functions and macros.
int ast_unregister_timing_interface(void *handle)
Unregister a previously registered timing interface.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Assume that the ao2_container is already locked.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
static int pthread_timer_cmp(void *obj, void *arg, int flags)
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
#define ao2_unlink(container, obj)
Remove an object from a container.
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Module has failed to load, may be in an inconsistent state.
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
#define ast_register_timing_interface(i)
Register a set of timing functions.
#define ASTERISK_GPL_KEY
The text the key() function should return.
static struct @491 timing_thread
Data for the timing thread.
Asterisk module definitions.
Timing source management.
Structure for mutex and tracking information.
static int pthread_timer_hash(const void *obj, const int flags)