Wed Aug 7 17:16:12 2019

Asterisk developer's documentation


res_timing_pthread.c File Reference

pthread timing interface More...

#include "asterisk.h"
#include <stdbool.h>
#include <math.h>
#include <unistd.h>
#include <fcntl.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)
static void ack_ticks (struct pthread_timer *timer, unsigned int num)
 ASTERISK_FILE_VERSION (__FILE__,"$Revision: 386109 $")
static int check_timer (struct pthread_timer *timer)
static void * do_timing (void *arg)
static struct pthread_timerfind_timer (int handle, int unlinkobj)
static int init_timing_thread (void)
static int load_module (void)
static int 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 int run_timer (void *obj, void *arg, int flags)
static void signal_pipe (struct pthread_timer *timer)
static int unload_module (void)
static void unsignal_pipe (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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_TIMING, }
static struct ast_module_infoast_module_info = &__mod_info
static struct ao2_containerpthread_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.

Detailed Description

pthread timing interface

Author:
Russell Bryant <russell@digium.com>

Definition in file res_timing_pthread.c.


Define Documentation

#define MAX_RATE   100

Definition at line 71 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 74 of file res_timing_pthread.c.

Referenced by load_module().


Enumeration Type Documentation

anonymous enum
Enumerator:
PIPE_READ 
PIPE_WRITE 

Definition at line 76 of file res_timing_pthread.c.

00076      {
00077    PIPE_READ =  0,
00078    PIPE_WRITE = 1
00079 };

Enumerator:
TIMER_STATE_IDLE 
TIMER_STATE_TICKING 

Definition at line 81 of file res_timing_pthread.c.

00081                          {
00082    TIMER_STATE_IDLE,
00083    TIMER_STATE_TICKING,
00084 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 536 of file res_timing_pthread.c.

static void __unreg_module ( void   )  [static]

Definition at line 536 of file res_timing_pthread.c.

static void ack_ticks ( struct pthread_timer timer,
unsigned int  num 
) [static]

Definition at line 374 of file res_timing_pthread.c.

References ast_assert, pthread_timer::continuous, pthread_timer::pending_ticks, and unsignal_pipe().

Referenced by pthread_timer_ack().

00375 {
00376    int pending_ticks = timer->pending_ticks;
00377 
00378    ast_assert(quantity);
00379 
00380    if (quantity > pending_ticks) {
00381       quantity = pending_ticks;
00382    }
00383 
00384    if (!quantity) {
00385       return;
00386    }
00387 
00388    timer->pending_ticks -= quantity;
00389 
00390    if ((0 == timer->pending_ticks) && !timer->continuous) {
00391       unsignal_pipe(timer);
00392    }
00393 }

ASTERISK_FILE_VERSION ( __FILE__  ,
"$Revision: 386109 $"   
)
static int check_timer ( struct pthread_timer timer  )  [static]
Return values:
0 no timer tick needed
non-zero write to the timing pipe needed

Definition at line 348 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().

00349 {
00350    struct timeval now;
00351 
00352    if (timer->state == TIMER_STATE_IDLE) {
00353       return 0;
00354    }
00355 
00356    now = ast_tvnow();
00357 
00358    if (timer->tick_count < (ast_tvdiff_ms(now, timer->start) / timer->interval)) {
00359       timer->tick_count++;
00360       if (!timer->tick_count) {
00361          /* Handle overflow. */
00362          timer->start = now;
00363       }
00364       return 1;
00365    }
00366 
00367    return 0;
00368 }

static void* do_timing ( void *  arg  )  [static]

Definition at line 457 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().

00458 {
00459    struct timeval next_wakeup = ast_tvnow();
00460 
00461    while (!timing_thread.stop) {
00462       struct timespec ts = { 0, };
00463 
00464       ao2_callback(pthread_timers, OBJ_NODATA, run_timer, NULL);
00465 
00466       next_wakeup = ast_tvadd(next_wakeup, ast_tv(0, 5000));
00467 
00468       ts.tv_sec = next_wakeup.tv_sec;
00469       ts.tv_nsec = next_wakeup.tv_usec * 1000;
00470 
00471       ast_mutex_lock(&timing_thread.lock);
00472       if (!timing_thread.stop) {
00473          if (ao2_container_count(pthread_timers)) {
00474             ast_cond_timedwait(&timing_thread.cond, &timing_thread.lock, &ts);
00475          } else {
00476             ast_cond_wait(&timing_thread.cond, &timing_thread.lock);
00477          }
00478       }
00479       ast_mutex_unlock(&timing_thread.lock);
00480    }
00481 
00482    return NULL;
00483 }

static struct pthread_timer * find_timer ( int  handle,
int  unlinkobj 
) [static, read]

Definition at line 289 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().

00290 {
00291    struct pthread_timer *timer;
00292    struct pthread_timer tmp_timer;
00293    int flags = OBJ_POINTER;
00294 
00295    tmp_timer.pipe[PIPE_READ] = handle;
00296 
00297    if (unlinkobj) {
00298       flags |= OBJ_UNLINK;
00299    }
00300 
00301    if (!(timer = ao2_find(pthread_timers, &tmp_timer, flags))) {
00302       ast_assert(timer != NULL);
00303       return NULL;
00304    }
00305 
00306    return timer;
00307 }

static int init_timing_thread ( void   )  [static]

Definition at line 485 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().

00486 {
00487    ast_mutex_init(&timing_thread.lock);
00488    ast_cond_init(&timing_thread.cond, NULL);
00489 
00490    if (ast_pthread_create_background(&timing_thread.thread, NULL, do_timing, NULL)) {
00491       ast_log(LOG_ERROR, "Unable to start timing thread.\n");
00492       return -1;
00493    }
00494 
00495    return 0;
00496 }

static int load_module ( void   )  [static]
static int pthread_timer_ack ( int  handle,
unsigned int  quantity 
) [static]

Definition at line 203 of file res_timing_pthread.c.

References ack_ticks(), ao2_lock, ao2_ref, ao2_unlock, ast_assert, find_timer(), and timer.

00204 {
00205    struct pthread_timer *timer;
00206 
00207    ast_assert(quantity > 0);
00208 
00209    if (!(timer = find_timer(handle, 0))) {
00210       return -1;
00211    }
00212 
00213    ao2_lock(timer);
00214    ack_ticks(timer, quantity);
00215    ao2_unlock(timer);
00216 
00217    ao2_ref(timer, -1);
00218 
00219    return 0;
00220 }

static void pthread_timer_close ( int  handle  )  [static]

Definition at line 156 of file res_timing_pthread.c.

References ao2_ref, find_timer(), and timer.

00157 {
00158    struct pthread_timer *timer;
00159 
00160    if (!(timer = find_timer(handle, 1))) {
00161       return;
00162    }
00163 
00164    ao2_ref(timer, -1);
00165 }

static int pthread_timer_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]
Note:
only PIPE_READ is guaranteed valid

Definition at line 337 of file res_timing_pthread.c.

References CMP_MATCH, CMP_STOP, pthread_timer::pipe, and PIPE_READ.

Referenced by load_module().

00338 {
00339    struct pthread_timer *timer1 = obj, *timer2 = arg;
00340 
00341    return (timer1->pipe[PIPE_READ] == timer2->pipe[PIPE_READ]) ? CMP_MATCH | CMP_STOP : 0;
00342 }

static void pthread_timer_destructor ( void *  obj  )  [static]

Definition at line 309 of file res_timing_pthread.c.

References pthread_timer::pipe, PIPE_READ, PIPE_WRITE, and timer.

Referenced by pthread_timer_open().

00310 {
00311    struct pthread_timer *timer = obj;
00312 
00313    if (timer->pipe[PIPE_READ] > -1) {
00314       close(timer->pipe[PIPE_READ]);
00315       timer->pipe[PIPE_READ] = -1;
00316    }
00317 
00318    if (timer->pipe[PIPE_WRITE] > -1) {
00319       close(timer->pipe[PIPE_WRITE]);
00320       timer->pipe[PIPE_WRITE] = -1;
00321    }
00322 }

static int pthread_timer_disable_continuous ( int  handle  )  [static]

Definition at line 243 of file res_timing_pthread.c.

References ao2_lock, ao2_ref, ao2_unlock, pthread_timer::continuous, errno, find_timer(), timer, and unsignal_pipe().

00244 {
00245    struct pthread_timer *timer;
00246 
00247    if (!(timer = find_timer(handle, 0))) {
00248       errno = EINVAL;
00249       return -1;
00250    }
00251 
00252    ao2_lock(timer);
00253    if (timer->continuous) {
00254       timer->continuous = false;
00255       unsignal_pipe(timer);
00256    }
00257    ao2_unlock(timer);
00258 
00259    ao2_ref(timer, -1);
00260 
00261    return 0;
00262 }

static int pthread_timer_enable_continuous ( int  handle  )  [static]

Definition at line 222 of file res_timing_pthread.c.

References ao2_lock, ao2_ref, ao2_unlock, pthread_timer::continuous, errno, find_timer(), signal_pipe(), and timer.

00223 {
00224    struct pthread_timer *timer;
00225 
00226    if (!(timer = find_timer(handle, 0))) {
00227       errno = EINVAL;
00228       return -1;
00229    }
00230 
00231    ao2_lock(timer);
00232    if (!timer->continuous) {
00233       timer->continuous = true;
00234       signal_pipe(timer);
00235    }
00236    ao2_unlock(timer);
00237 
00238    ao2_ref(timer, -1);
00239 
00240    return 0;
00241 }

static enum ast_timer_event pthread_timer_get_event ( int  handle  )  [static]

Definition at line 264 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(), and timer.

00265 {
00266    struct pthread_timer *timer;
00267    enum ast_timer_event res = AST_TIMING_EVENT_EXPIRED;
00268 
00269    if (!(timer = find_timer(handle, 0))) {
00270       return res;
00271    }
00272 
00273    ao2_lock(timer);
00274    if (timer->continuous) {
00275       res = AST_TIMING_EVENT_CONTINUOUS;
00276    }
00277    ao2_unlock(timer);
00278 
00279    ao2_ref(timer, -1);
00280 
00281    return res;
00282 }

static unsigned int pthread_timer_get_max_rate ( int  handle  )  [static]

Definition at line 284 of file res_timing_pthread.c.

References MAX_RATE.

00285 {
00286    return MAX_RATE;
00287 }

static int pthread_timer_hash ( const void *  obj,
const int  flags 
) [static]
Note:
only PIPE_READ is guaranteed valid

Definition at line 327 of file res_timing_pthread.c.

References pthread_timer::pipe, PIPE_READ, and timer.

Referenced by load_module().

00328 {
00329    const struct pthread_timer *timer = obj;
00330 
00331    return timer->pipe[PIPE_READ];
00332 }

static int pthread_timer_open ( void   )  [static]

Definition at line 115 of file res_timing_pthread.c.

References ao2_alloc, ao2_container_count(), ao2_link, ao2_lock, ao2_ref, ao2_unlock, ARRAY_LEN, 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.

00116 {
00117    struct pthread_timer *timer;
00118    int fd;
00119    int i;
00120 
00121    if (!(timer = ao2_alloc(sizeof(*timer), pthread_timer_destructor))) {
00122       errno = ENOMEM;
00123       return -1;
00124    }
00125 
00126    timer->pipe[PIPE_READ] = timer->pipe[PIPE_WRITE] = -1;
00127    timer->state = TIMER_STATE_IDLE;
00128 
00129    if (pipe(timer->pipe)) {
00130       ao2_ref(timer, -1);
00131       return -1;
00132    }
00133 
00134    for (i = 0; i < ARRAY_LEN(timer->pipe); ++i) {
00135       int flags = fcntl(timer->pipe[i], F_GETFL);
00136       flags |= O_NONBLOCK;
00137       fcntl(timer->pipe[i], F_SETFL, flags);
00138    }
00139    
00140    ao2_lock(pthread_timers);
00141    if (!ao2_container_count(pthread_timers)) {
00142       ast_mutex_lock(&timing_thread.lock);
00143       ast_cond_signal(&timing_thread.cond);
00144       ast_mutex_unlock(&timing_thread.lock);
00145    }
00146    ao2_link(pthread_timers, timer);
00147    ao2_unlock(pthread_timers);
00148 
00149    fd = timer->pipe[PIPE_READ];
00150 
00151    ao2_ref(timer, -1);
00152 
00153    return fd;
00154 }

static int pthread_timer_set_rate ( int  handle,
unsigned int  rate 
) [static]

Definition at line 167 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.

00168 {
00169    struct pthread_timer *timer;
00170 
00171    if (!(timer = find_timer(handle, 0))) {
00172       errno = EINVAL;
00173       return -1;
00174    }
00175 
00176    if (rate > MAX_RATE) {
00177       ast_log(LOG_ERROR, "res_timing_pthread only supports timers at a "
00178             "max rate of %d / sec\n", MAX_RATE);
00179       errno = EINVAL;
00180       return -1;
00181    }
00182 
00183    ao2_lock(timer);
00184 
00185    if ((timer->rate = rate)) {
00186       timer->interval = roundf(1000.0 / ((float) rate));
00187       timer->start = ast_tvnow();
00188       timer->state = TIMER_STATE_TICKING;
00189    } else {
00190       timer->interval = 0;
00191       timer->start = ast_tv(0, 0);
00192       timer->state = TIMER_STATE_IDLE;
00193    }
00194    timer->tick_count = 0;
00195 
00196    ao2_unlock(timer);
00197 
00198    ao2_ref(timer, -1);
00199 
00200    return 0;
00201 }

static int run_timer ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 439 of file res_timing_pthread.c.

References ao2_lock, ao2_unlock, check_timer(), pthread_timer::pending_ticks, signal_pipe(), pthread_timer::state, timer, and TIMER_STATE_IDLE.

Referenced by do_timing().

00440 {
00441    struct pthread_timer *timer = obj;
00442 
00443    if (timer->state == TIMER_STATE_IDLE) {
00444       return 0;
00445    }
00446 
00447    ao2_lock(timer);
00448    if (check_timer(timer)) {
00449       timer->pending_ticks++;
00450       signal_pipe(timer);
00451    }
00452    ao2_unlock(timer);
00453 
00454    return 0;
00455 }

static void signal_pipe ( struct pthread_timer timer  )  [static]

Definition at line 399 of file res_timing_pthread.c.

References ast_log(), errno, LOG_ERROR, pthread_timer::pipe, pthread_timer::pipe_signaled, and PIPE_WRITE.

Referenced by pthread_timer_enable_continuous(), and run_timer().

00400 {
00401    ssize_t res;
00402    unsigned char x = 42;
00403 
00404    if (timer->pipe_signaled) {
00405       return;
00406    }
00407 
00408    res = write(timer->pipe[PIPE_WRITE], &x, 1);
00409    if (-1 == res) {
00410       ast_log(LOG_ERROR, "Error writing to timing pipe: %s\n",
00411             strerror(errno));
00412    } else {
00413       timer->pipe_signaled = true;
00414    }
00415 }

static int unload_module ( void   )  [static]

Definition at line 515 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.

00516 {
00517    int res;
00518 
00519    ast_mutex_lock(&timing_thread.lock);
00520    timing_thread.stop = 1;
00521    ast_cond_signal(&timing_thread.cond);
00522    ast_mutex_unlock(&timing_thread.lock);
00523    pthread_join(timing_thread.thread, NULL);
00524 
00525    if (!(res = ast_unregister_timing_interface(timing_funcs_handle))) {
00526       ao2_ref(pthread_timers, -1);
00527       pthread_timers = NULL;
00528    }
00529 
00530    return res;
00531 }

static void unsignal_pipe ( struct pthread_timer timer  )  [static]

Definition at line 421 of file res_timing_pthread.c.

References ast_log(), errno, LOG_ERROR, pthread_timer::pipe, PIPE_READ, and pthread_timer::pipe_signaled.

Referenced by ack_ticks(), and pthread_timer_disable_continuous().

00422 {
00423    ssize_t res;
00424    unsigned long buffer;
00425 
00426    if (!timer->pipe_signaled) {
00427       return;
00428    }
00429 
00430    res = read(timer->pipe[PIPE_READ], &buffer, sizeof(buffer));
00431    if (-1 == res) {
00432       ast_log(LOG_ERROR, "Error reading from pipe: %s\n",
00433             strerror(errno));
00434    } else {
00435       timer->pipe_signaled = false;
00436    }
00437 }


Variable Documentation

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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_TIMING, } [static]

Definition at line 536 of file res_timing_pthread.c.

Definition at line 536 of file res_timing_pthread.c.

Definition at line 111 of file res_timing_pthread.c.

Definition at line 110 of file res_timing_pthread.c.

struct ao2_container* pthread_timers [static]

Definition at line 73 of file res_timing_pthread.c.

Definition at line 57 of file res_timing_pthread.c.

unsigned int stop

Definition at line 112 of file res_timing_pthread.c.

pthread_t thread

Definition at line 109 of file res_timing_pthread.c.

void* timing_funcs_handle [static]

Definition at line 46 of file res_timing_pthread.c.

Referenced by load_module(), and unload_module().

struct { ... } timing_thread [static]

Data for the timing thread.

Referenced by do_timing(), init_timing_thread(), pthread_timer_open(), and unload_module().


Generated on 7 Aug 2019 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1