aboutsummaryrefslogtreecommitdiffstats
path: root/res/res_timing_pthread.c
diff options
context:
space:
mode:
Diffstat (limited to 'res/res_timing_pthread.c')
-rw-r--r--res/res_timing_pthread.c124
1 files changed, 62 insertions, 62 deletions
diff --git a/res/res_timing_pthread.c b/res/res_timing_pthread.c
index 8eea1a0f9..5e3c31364 100644
--- a/res/res_timing_pthread.c
+++ b/res/res_timing_pthread.c
@@ -75,7 +75,6 @@ enum {
enum pthread_timer_state {
TIMER_STATE_IDLE,
TIMER_STATE_TICKING,
- TIMER_STATE_CONTINUOUS,
};
struct pthread_timer {
@@ -85,13 +84,15 @@ struct pthread_timer {
/*! Interval in ms for current rate */
unsigned int interval;
unsigned int tick_count;
+ unsigned int pending_ticks;
struct timeval start;
+ unsigned int continuous:1;
};
static void pthread_timer_destructor(void *obj);
static struct pthread_timer *find_timer(int handle, int unlinkobj);
-static void write_byte(int wr_fd);
-static void read_pipe(int rd_fd, unsigned int num, int clear);
+static void write_byte(struct pthread_timer *timer);
+static void read_pipe(struct pthread_timer *timer, unsigned int num);
/*!
* \brief Data for the timing thread
@@ -148,23 +149,6 @@ static void pthread_timer_close(int handle)
ao2_ref(timer, -1);
}
-static void set_state(struct pthread_timer *timer)
-{
- unsigned int rate = timer->rate;
-
- if (rate) {
- timer->state = TIMER_STATE_TICKING;
- timer->interval = roundf(1000.0 / ((float) rate));
- timer->start = ast_tvnow();
- } else {
- timer->state = TIMER_STATE_IDLE;
- timer->interval = 0;
- timer->start = ast_tv(0, 0);
- }
-
- timer->tick_count = 0;
-}
-
static int pthread_timer_set_rate(int handle, unsigned int rate)
{
struct pthread_timer *timer;
@@ -175,17 +159,24 @@ static int pthread_timer_set_rate(int handle, unsigned int rate)
}
if (rate > MAX_RATE) {
- ast_log(LOG_ERROR, "res_timing_pthread only supports timers at a max rate of %d / sec\n",
- 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);
- timer->rate = rate;
- if (timer->state != TIMER_STATE_CONTINUOUS) {
- set_state(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);
@@ -204,12 +195,9 @@ static void pthread_timer_ack(int handle, unsigned int quantity)
return;
}
- if (timer->state == TIMER_STATE_CONTINUOUS) {
- /* Leave the pipe alone, please! */
- return;
- }
-
- read_pipe(timer->pipe[PIPE_READ], quantity, 0);
+ ao2_lock(timer);
+ read_pipe(timer, quantity);
+ ao2_unlock(timer);
ao2_ref(timer, -1);
}
@@ -224,8 +212,10 @@ static int pthread_timer_enable_continuous(int handle)
}
ao2_lock(timer);
- timer->state = TIMER_STATE_CONTINUOUS;
- write_byte(timer->pipe[PIPE_WRITE]);
+ if (!timer->continuous) {
+ timer->continuous = 1;
+ write_byte(timer);
+ }
ao2_unlock(timer);
ao2_ref(timer, -1);
@@ -243,8 +233,10 @@ static int pthread_timer_disable_continuous(int handle)
}
ao2_lock(timer);
- set_state(timer);
- read_pipe(timer->pipe[PIPE_READ], 0, 1);
+ if (timer->continuous) {
+ timer->continuous = 0;
+ read_pipe(timer, 1);
+ }
ao2_unlock(timer);
ao2_ref(timer, -1);
@@ -261,9 +253,11 @@ static enum ast_timer_event pthread_timer_get_event(int handle)
return res;
}
- if (timer->state == TIMER_STATE_CONTINUOUS) {
+ ao2_lock(timer);
+ if (timer->continuous && timer->pending_ticks == 1) {
res = AST_TIMING_EVENT_CONTINUOUS;
}
+ ao2_unlock(timer);
ao2_ref(timer, -1);
@@ -338,7 +332,7 @@ static int check_timer(struct pthread_timer *timer)
{
struct timeval now;
- if (timer->state == TIMER_STATE_IDLE || timer->state == TIMER_STATE_CONTINUOUS) {
+ if (timer->state == TIMER_STATE_IDLE) {
return 0;
}
@@ -347,6 +341,7 @@ static int check_timer(struct pthread_timer *timer)
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;
@@ -355,13 +350,16 @@ static int check_timer(struct pthread_timer *timer)
return 0;
}
-static void read_pipe(int rd_fd, unsigned int quantity, int clear)
+/*!
+ * \internal
+ * \pre timer is locked
+ */
+static void read_pipe(struct pthread_timer *timer, unsigned int quantity)
{
- ast_assert(quantity || clear);
+ int rd_fd = timer->pipe[PIPE_READ];
- if (!quantity && clear) {
- quantity = 1;
- }
+ ast_assert(quantity);
+ ast_assert(quantity >= timer->pending_ticks);
do {
unsigned char buf[1024];
@@ -376,6 +374,8 @@ static void read_pipe(int rd_fd, unsigned int quantity, int clear)
FD_SET(rd_fd, &rfds);
if (select(rd_fd + 1, &rfds, NULL, NULL, &timeout) != 1) {
+ ast_debug(1, "Reading not available on timing pipe, "
+ "quantity: %u\n", quantity);
break;
}
@@ -386,33 +386,35 @@ static void read_pipe(int rd_fd, unsigned int quantity, int clear)
if (errno == EAGAIN) {
continue;
}
- ast_log(LOG_ERROR, "read failed on timing pipe: %s\n", strerror(errno));
+ ast_log(LOG_ERROR, "read failed on timing pipe: %s\n",
+ strerror(errno));
break;
}
- if (clear) {
- continue;
- }
-
quantity -= res;
+ timer->pending_ticks -= res;
} while (quantity);
}
-static void write_byte(int wr_fd)
+/*!
+ * \internal
+ * \pre timer is locked
+ */
+static void write_byte(struct pthread_timer *timer)
{
- do {
- ssize_t res;
- unsigned char x = 42;
+ ssize_t res;
+ unsigned char x = 42;
- res = write(wr_fd, &x, 1);
+ do {
+ res = write(timer->pipe[PIPE_WRITE], &x, 1);
+ } while (res == -1 && errno == EAGAIN);
- if (res == -1) {
- if (errno == EAGAIN) {
- continue;
- }
- ast_log(LOG_ERROR, "Error writing to timing pipe: %s\n", strerror(errno));
- }
- } while (0);
+ if (res == -1) {
+ ast_log(LOG_ERROR, "Error writing to timing pipe: %s\n",
+ strerror(errno));
+ } else {
+ timer->pending_ticks++;
+ }
}
static int run_timer(void *obj, void *arg, int flags)
@@ -424,11 +426,9 @@ static int run_timer(void *obj, void *arg, int flags)
}
ao2_lock(timer);
-
if (check_timer(timer)) {
- write_byte(timer->pipe[PIPE_WRITE]);
+ write_byte(timer);
}
-
ao2_unlock(timer);
return 0;