mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-07-15 19:40:06 +00:00
Wed Jan 28 11:52:34 CST 2009 Pekka Pessi <first.last@nokia.com>
* su_timer.c: using heap (instead of red-black tree) for keeping timers sorted Re-recorded 20070704230449-65a35-f0434c75b0f58a069806e81942c0d5e0821dc9d3 git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@11848 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
37a7c283b1
commit
5c8181cc20
@ -1 +1 @@
|
|||||||
Wed Feb 11 11:13:59 CST 2009
|
Wed Feb 11 11:14:27 CST 2009
|
||||||
|
@ -32,7 +32,17 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "su_port.h"
|
#include <sys/types.h>
|
||||||
|
#include <sofia-sip/heap.h>
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
void *private;
|
||||||
|
/* Use for debugging */
|
||||||
|
struct timers_priv { size_t _size, _used; struct su_timer_s * _heap[2]; } *actual;
|
||||||
|
} su_timer_heap_t;
|
||||||
|
|
||||||
|
#define SU_TIMER_QUEUE_T su_timer_heap_t
|
||||||
|
|
||||||
#include "sofia-sip/su.h"
|
#include "sofia-sip/su.h"
|
||||||
#include "sofia-sip/su_wait.h"
|
#include "sofia-sip/su_wait.h"
|
||||||
#include "sofia-sip/su_alloc.h"
|
#include "sofia-sip/su_alloc.h"
|
||||||
@ -144,8 +154,8 @@
|
|||||||
|
|
||||||
struct su_timer_s {
|
struct su_timer_s {
|
||||||
/** Pointers within red-black tree */
|
/** Pointers within red-black tree */
|
||||||
su_timer_t *sut_left, *sut_right, *sut_parent;
|
|
||||||
su_task_r sut_task; /**< Task reference */
|
su_task_r sut_task; /**< Task reference */
|
||||||
|
size_t sut_heap_index; /**< Timer is set (inserted in heap) */
|
||||||
su_time_t sut_when; /**< When timer should be waken up next time */
|
su_time_t sut_when; /**< When timer should be waken up next time */
|
||||||
su_duration_t sut_duration; /**< Timer duration */
|
su_duration_t sut_duration; /**< Timer duration */
|
||||||
su_timer_f sut_wakeup; /**< Function to call when waken up */
|
su_timer_f sut_wakeup; /**< Function to call when waken up */
|
||||||
@ -153,9 +163,6 @@ struct su_timer_s {
|
|||||||
su_time_t sut_run; /**< When this timer was last waken up */
|
su_time_t sut_run; /**< When this timer was last waken up */
|
||||||
unsigned sut_woken; /**< Timer has waken up this many times */
|
unsigned sut_woken; /**< Timer has waken up this many times */
|
||||||
unsigned short sut_running; /**< Timer is running */
|
unsigned short sut_running; /**< Timer is running */
|
||||||
|
|
||||||
unsigned char sut_black; /**< Black node */
|
|
||||||
unsigned char sut_set; /**< Timer is set (inserted in tree) */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Timer running status */
|
/** Timer running status */
|
||||||
@ -165,35 +172,35 @@ enum sut_running {
|
|||||||
run_for_ever = 2 /**< Do not compensate */
|
run_for_ever = 2 /**< Do not compensate */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SU_TIMER_IS_SET(sut) ((sut)->sut_set)
|
#define SU_TIMER_IS_SET(sut) ((sut)->sut_heap_index != 0)
|
||||||
|
|
||||||
/* Accessor macros for rbtree */
|
HEAP_DECLARE(su_inline, su_timer_queue_t, timers_, su_timer_t *);
|
||||||
#define LEFT(sut) ((sut)->sut_left)
|
|
||||||
#define RIGHT(sut) ((sut)->sut_right)
|
|
||||||
#define PARENT(sut) ((sut)->sut_parent)
|
|
||||||
#define SET_RED(sut) ((sut)->sut_black = 0)
|
|
||||||
#define SET_BLACK(sut) ((sut)->sut_black = 1)
|
|
||||||
#define CMP(a, b) SU_TIME_CMP((a)->sut_when, (b)->sut_when)
|
|
||||||
#define IS_RED(sut) ((sut) && (sut)->sut_black == 0)
|
|
||||||
#define IS_BLACK(sut) (!(sut) || (sut)->sut_black == 1)
|
|
||||||
#define COPY_COLOR(dst, src) ((dst)->sut_black = (src)->sut_black)
|
|
||||||
#define INSERT(sut) ((sut)->sut_set = 1)
|
|
||||||
#define REMOVE(sut) ((sut)->sut_set = 0, \
|
|
||||||
(sut)->sut_left = (sut)->sut_right = (sut)->sut_parent = NULL)
|
|
||||||
|
|
||||||
RBTREE_PROTOS(su_inline, timers, su_timer_t);
|
su_inline void timers_set(su_timer_t **array, size_t index, su_timer_t *t)
|
||||||
|
{
|
||||||
|
array[t->sut_heap_index = index] = t;
|
||||||
|
}
|
||||||
|
|
||||||
su_inline int timers_append(su_timer_queue_t *, su_timer_t *);
|
su_inline int timers_less(su_timer_t *a, su_timer_t *b)
|
||||||
su_inline void timers_remove(su_timer_queue_t *, su_timer_t *);
|
{
|
||||||
su_inline su_timer_t *timers_succ(su_timer_t const *);
|
return
|
||||||
su_inline su_timer_t *timers_prec(su_timer_t const *);
|
a->sut_when.tv_sec < b->sut_when.tv_sec ||
|
||||||
su_inline su_timer_t *timers_first(su_timer_t const *);
|
(a->sut_when.tv_sec == b->sut_when.tv_sec &&
|
||||||
su_inline su_timer_t *timers_last(su_timer_t const *);
|
a->sut_when.tv_usec < b->sut_when.tv_usec);
|
||||||
|
}
|
||||||
|
|
||||||
RBTREE_BODIES(su_inline, timers, su_timer_t,
|
su_inline void *timers_alloc(void *argument, void *memory, size_t size)
|
||||||
LEFT, RIGHT, PARENT,
|
{
|
||||||
IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR,
|
(void)argument;
|
||||||
CMP, INSERT, REMOVE);
|
|
||||||
|
if (size)
|
||||||
|
return realloc(memory, size);
|
||||||
|
else
|
||||||
|
return free(memory), NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HEAP_BODIES(su_inline, su_timer_queue_t, timers_, su_timer_t *,
|
||||||
|
timers_less, timers_set, timers_alloc, NULL);
|
||||||
|
|
||||||
/**@internal Set the timer.
|
/**@internal Set the timer.
|
||||||
*
|
*
|
||||||
@ -207,34 +214,30 @@ su_timer_set0(su_timer_queue_t *timers,
|
|||||||
su_time_t when,
|
su_time_t when,
|
||||||
su_duration_t offset)
|
su_duration_t offset)
|
||||||
{
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
assert(timers);
|
||||||
|
|
||||||
|
if (timers == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (SU_TIMER_IS_SET(t))
|
if (SU_TIMER_IS_SET(t))
|
||||||
timers_remove(timers, t);
|
timers_remove(timers[0], t->sut_heap_index)->sut_heap_index = 0;
|
||||||
|
|
||||||
t->sut_wakeup = wakeup;
|
t->sut_wakeup = wakeup;
|
||||||
t->sut_arg = arg;
|
t->sut_arg = arg;
|
||||||
t->sut_when = su_time_add(when, offset);
|
t->sut_when = su_time_add(when, offset);
|
||||||
|
|
||||||
return timers_append(timers, t);
|
if (timers_is_full(timers[0])) {
|
||||||
}
|
timers_resize(NULL, timers, 0);
|
||||||
|
assert(!timers_is_full(timers[0]));
|
||||||
|
if (timers_is_full(timers[0]))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**@internal Reset the timer.
|
retval = timers_add(timers[0], t); assert(retval == 0);
|
||||||
*
|
|
||||||
* @retval 0 when successful (always)
|
|
||||||
*/
|
|
||||||
su_inline int
|
|
||||||
su_timer_reset0(su_timer_queue_t *timers,
|
|
||||||
su_timer_t *t)
|
|
||||||
{
|
|
||||||
if (SU_TIMER_IS_SET(t))
|
|
||||||
timers_remove(timers, t);
|
|
||||||
|
|
||||||
t->sut_wakeup = NULL;
|
return retval;
|
||||||
t->sut_arg = NULL;
|
|
||||||
t->sut_running = reset;
|
|
||||||
|
|
||||||
memset(&t->sut_run, 0, sizeof(t->sut_run));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**@internal Validate timer @a t and return pointer to per-port timer tree.
|
/**@internal Validate timer @a t and return pointer to per-port timer tree.
|
||||||
@ -255,12 +258,6 @@ su_timer_queue_t *su_timer_tree(su_timer_t const *t,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
timers = su_task_timers(t->sut_task);
|
|
||||||
|
|
||||||
if (timers == NULL)
|
|
||||||
SU_DEBUG_1(("%s(%p): %s\n", caller, (void *)t,
|
|
||||||
"invalid timer"));
|
|
||||||
|
|
||||||
if (use_sut_duration && t->sut_duration == 0) {
|
if (use_sut_duration && t->sut_duration == 0) {
|
||||||
assert(t->sut_duration > 0);
|
assert(t->sut_duration > 0);
|
||||||
SU_DEBUG_1(("%s(%p): %s\n", caller, (void *)t,
|
SU_DEBUG_1(("%s(%p): %s\n", caller, (void *)t,
|
||||||
@ -268,6 +265,17 @@ su_timer_queue_t *su_timer_tree(su_timer_t const *t,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timers = su_task_timers(t->sut_task);
|
||||||
|
|
||||||
|
if (timers == NULL) {
|
||||||
|
SU_DEBUG_1(("%s(%p): %s\n", caller, (void *)t, "invalid timer"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else if (timers_is_full(timers[0]) && timers_resize(NULL, timers, 0) == -1) {
|
||||||
|
SU_DEBUG_1(("%s(%p): %s\n", caller, (void *)t, "timer queue failed"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return timers;
|
return timers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,9 +316,7 @@ su_timer_t *su_timer_create(su_task_r const task, su_duration_t msec)
|
|||||||
void su_timer_destroy(su_timer_t *t)
|
void su_timer_destroy(su_timer_t *t)
|
||||||
{
|
{
|
||||||
if (t) {
|
if (t) {
|
||||||
su_timer_queue_t *timers = su_task_timers(t->sut_task);
|
su_timer_reset(t);
|
||||||
if (timers)
|
|
||||||
su_timer_reset0(timers, t);
|
|
||||||
su_task_deinit(t->sut_task);
|
su_task_deinit(t->sut_task);
|
||||||
su_free(NULL, t);
|
su_free(NULL, t);
|
||||||
}
|
}
|
||||||
@ -471,7 +477,16 @@ int su_timer_reset(su_timer_t *t)
|
|||||||
if (timers == NULL)
|
if (timers == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return su_timer_reset0(timers, t);
|
if (SU_TIMER_IS_SET(t))
|
||||||
|
timers_remove(timers[0], t->sut_heap_index)->sut_heap_index = 0;
|
||||||
|
|
||||||
|
t->sut_wakeup = NULL;
|
||||||
|
t->sut_arg = NULL;
|
||||||
|
t->sut_running = reset;
|
||||||
|
|
||||||
|
memset(&t->sut_run, 0, sizeof(t->sut_run));
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal Check for expired timers in queue.
|
/** @internal Check for expired timers in queue.
|
||||||
@ -495,16 +510,20 @@ int su_timer_expire(su_timer_queue_t * const timers,
|
|||||||
su_timer_f f;
|
su_timer_f f;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
if (!*timers)
|
if (timers_used(timers[0]) == 0)
|
||||||
return n;
|
return 0;
|
||||||
|
|
||||||
for (;;) {
|
while ((t = timers_get(timers[0], 1))) {
|
||||||
t = timers_first(*timers);
|
if (SU_TIME_CMP(t->sut_when, now) > 0) {
|
||||||
|
su_duration_t at = su_duration(t->sut_when, now);
|
||||||
|
|
||||||
|
if (at < *timeout)
|
||||||
|
*timeout = at;
|
||||||
|
|
||||||
if (t == NULL || SU_TIME_CMP(t->sut_when, now) > 0)
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
timers_remove(timers, t);
|
timers_remove(timers[0], 1)->sut_heap_index = 0;
|
||||||
|
|
||||||
f = t->sut_wakeup; t->sut_wakeup = NULL;
|
f = t->sut_wakeup; t->sut_wakeup = NULL;
|
||||||
assert(f);
|
assert(f);
|
||||||
@ -534,13 +553,6 @@ int su_timer_expire(su_timer_queue_t * const timers,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t) {
|
|
||||||
su_duration_t at = su_duration(t->sut_when, now);
|
|
||||||
|
|
||||||
if (at < *timeout)
|
|
||||||
*timeout = at;
|
|
||||||
}
|
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -548,9 +560,16 @@ int su_timer_expire(su_timer_queue_t * const timers,
|
|||||||
/** Calculate duration in milliseconds until next timer expires. */
|
/** Calculate duration in milliseconds until next timer expires. */
|
||||||
su_duration_t su_timer_next_expires(su_timer_t const * t, su_time_t now)
|
su_duration_t su_timer_next_expires(su_timer_t const * t, su_time_t now)
|
||||||
{
|
{
|
||||||
|
su_timer_queue_t *timers;
|
||||||
|
|
||||||
su_duration_t tout;
|
su_duration_t tout;
|
||||||
|
|
||||||
t = timers_first(t);
|
if (!t)
|
||||||
|
return SU_DURATION_MAX;
|
||||||
|
|
||||||
|
timers = su_task_timers(t->sut_task);
|
||||||
|
|
||||||
|
t = timers ? timers_get(timers[0], 1) : NULL;
|
||||||
|
|
||||||
if (!t)
|
if (!t)
|
||||||
return SU_DURATION_MAX;
|
return SU_DURATION_MAX;
|
||||||
@ -573,23 +592,29 @@ su_duration_t su_timer_next_expires(su_timer_t const * t, su_time_t now)
|
|||||||
*/
|
*/
|
||||||
int su_timer_reset_all(su_timer_queue_t *timers, su_task_r task)
|
int su_timer_reset_all(su_timer_queue_t *timers, su_task_r task)
|
||||||
{
|
{
|
||||||
su_timer_t *t, *t_next;
|
size_t i;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
if (!timers || !*timers)
|
if (!timers)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (t = timers_first(*timers); t; t = t_next) {
|
timers_sort(timers[0]);
|
||||||
t_next = timers_succ(t);
|
|
||||||
|
for (i = timers_used(timers[0]); i > 0; i--) {
|
||||||
|
su_timer_t *t = timers_get(timers[0], i);
|
||||||
|
|
||||||
if (su_task_cmp(task, t->sut_task))
|
if (su_task_cmp(task, t->sut_task))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
n++;
|
timers_remove(timers[0], i)->sut_heap_index = 0;
|
||||||
timers_remove(timers, t);
|
|
||||||
su_free(NULL, t);
|
su_free(NULL, t);
|
||||||
|
n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!timers_used(timers[0]))
|
||||||
|
free(timers->private), timers->private = NULL;
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,3 +630,4 @@ su_root_t *su_timer_root(su_timer_t const *t)
|
|||||||
{
|
{
|
||||||
return t ? su_task_root(t->sut_task) : NULL;
|
return t ? su_task_root(t->sut_task) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user