checkpoint
This commit is contained in:
@@ -8,13 +8,13 @@
|
||||
#include <isc/memcluster.h>
|
||||
#include <isc/task.h>
|
||||
#include <isc/thread.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/timer.h>
|
||||
|
||||
mem_context_t mctx = NULL;
|
||||
|
||||
/*ARGSUSED*/
|
||||
static boolean_t
|
||||
my_callback(task_t __attribute__((unused)) task,
|
||||
task_event_t __attribute__((unused)) event)
|
||||
my_callback(task_t task, task_event_t event)
|
||||
{
|
||||
int i, j;
|
||||
char *name = event->arg;
|
||||
@@ -27,21 +27,16 @@ my_callback(task_t __attribute__((unused)) task,
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static boolean_t
|
||||
my_shutdown(task_t __attribute__((unused)) task,
|
||||
task_event_t __attribute__((unused)) event)
|
||||
{
|
||||
my_shutdown(task_t task, task_event_t event) {
|
||||
char *name = event->arg;
|
||||
|
||||
printf("shutdown %s\n", name);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static boolean_t
|
||||
my_tick(task_t __attribute__((unused)) task,
|
||||
task_event_t __attribute__((unused)) event)
|
||||
my_tick(task_t task, task_event_t event)
|
||||
{
|
||||
char *name = event->arg;
|
||||
|
||||
@@ -49,37 +44,6 @@ my_tick(task_t __attribute__((unused)) task,
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
void *
|
||||
simple_timer_run(void *arg) {
|
||||
task_t task = arg;
|
||||
task_event_t event;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
sleep(1);
|
||||
printf("sending timer to %p\n", task);
|
||||
event = task_event_allocate(mctx, simple_timer_run,
|
||||
2, my_tick, "foo",
|
||||
sizeof *event);
|
||||
INSIST(event != NULL);
|
||||
(void)task_send_event(task, &event);
|
||||
}
|
||||
|
||||
task_detach(&task);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
simple_timer_init(task_t task) {
|
||||
os_thread_t t;
|
||||
task_t task_clone;
|
||||
|
||||
task_clone = NULL;
|
||||
task_attach(task, &task_clone);
|
||||
INSIST(os_thread_create(simple_timer_run, task_clone, &t));
|
||||
(void)os_thread_detach(t);
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char *argv[]) {
|
||||
task_manager_t manager = NULL;
|
||||
@@ -87,6 +51,9 @@ main(int argc, char *argv[]) {
|
||||
task_t t3 = NULL, t4 = NULL;
|
||||
task_event_t event;
|
||||
unsigned int workers;
|
||||
timer_manager_t timgr;
|
||||
timer_t ti1, ti2;
|
||||
os_time_t absolute, interval;
|
||||
|
||||
if (argc > 1)
|
||||
workers = atoi(argv[1]);
|
||||
@@ -103,8 +70,19 @@ main(int argc, char *argv[]) {
|
||||
INSIST(task_create(manager, my_shutdown, "3", 0, &t3));
|
||||
INSIST(task_create(manager, my_shutdown, "4", 0, &t4));
|
||||
|
||||
simple_timer_init(t1);
|
||||
simple_timer_init(t2);
|
||||
timgr = NULL;
|
||||
INSIST(timer_manager_create(mctx, &timgr) == ISC_R_SUCCESS);
|
||||
ti1 = NULL;
|
||||
absolute.seconds = 0;
|
||||
absolute.nanoseconds = 0;
|
||||
interval.seconds = 5;
|
||||
interval.nanoseconds = 0;
|
||||
INSIST(timer_create(timgr, timer_type_ticker, absolute, interval,
|
||||
t1, my_tick, "foo", &ti1) == ISC_R_SUCCESS);
|
||||
ti2 = NULL;
|
||||
INSIST(timer_create(timgr, timer_type_ticker, absolute, interval,
|
||||
t2, my_tick, "bar", &ti2) == ISC_R_SUCCESS);
|
||||
|
||||
printf("task 1 = %p\n", t1);
|
||||
printf("task 2 = %p\n", t2);
|
||||
sleep(2);
|
||||
|
||||
164
lib/isc/heap.c
164
lib/isc/heap.c
@@ -42,8 +42,8 @@
|
||||
#define SIZE_INCREMENT 1024
|
||||
|
||||
#define HEAP_MAGIC 0x48454150U /* HEAP. */
|
||||
#define VALID_CONTEXT(ctx) ((ctx) != NULL && \
|
||||
(ctx)->magic == HEAP_MAGIC)
|
||||
#define VALID_HEAP(h) ((h) != NULL && \
|
||||
(h)->magic == HEAP_MAGIC)
|
||||
|
||||
struct heap_context {
|
||||
unsigned int magic;
|
||||
@@ -59,167 +59,167 @@ struct heap_context {
|
||||
isc_result
|
||||
heap_create(mem_context_t mctx, heap_higher_priority_func higher_priority,
|
||||
heap_index_func index, unsigned int size_increment,
|
||||
heap_context_t *ctxp)
|
||||
heap_t *heapp)
|
||||
{
|
||||
heap_context_t ctx;
|
||||
heap_t heap;
|
||||
|
||||
REQUIRE(ctxp != NULL && *ctxp == NULL);
|
||||
REQUIRE(heapp != NULL && *heapp == NULL);
|
||||
REQUIRE(higher_priority != NULL);
|
||||
|
||||
ctx = mem_get(mctx, sizeof *ctx);
|
||||
if (ctx == NULL)
|
||||
heap = mem_get(mctx, sizeof *heap);
|
||||
if (heap == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
ctx->magic = HEAP_MAGIC;
|
||||
ctx->size = 0;
|
||||
heap->magic = HEAP_MAGIC;
|
||||
heap->size = 0;
|
||||
if (size_increment == 0)
|
||||
ctx->size_increment = SIZE_INCREMENT;
|
||||
heap->size_increment = SIZE_INCREMENT;
|
||||
else
|
||||
ctx->size_increment = size_increment;
|
||||
ctx->last = 0;
|
||||
ctx->array = NULL;
|
||||
ctx->higher_priority = higher_priority;
|
||||
ctx->index = index;
|
||||
heap->size_increment = size_increment;
|
||||
heap->last = 0;
|
||||
heap->array = NULL;
|
||||
heap->higher_priority = higher_priority;
|
||||
heap->index = index;
|
||||
|
||||
*ctxp = ctx;
|
||||
*heapp = heap;
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
heap_destroy(heap_context_t *ctxp) {
|
||||
heap_context_t ctx;
|
||||
heap_destroy(heap_t *heapp) {
|
||||
heap_t heap;
|
||||
|
||||
REQUIRE(ctxp != NULL);
|
||||
ctx = *ctxp;
|
||||
REQUIRE(VALID_CONTEXT(ctx));
|
||||
REQUIRE(heapp != NULL);
|
||||
heap = *heapp;
|
||||
REQUIRE(VALID_HEAP(heap));
|
||||
|
||||
if (ctx->array != NULL)
|
||||
mem_put(ctx->mctx, ctx->array,
|
||||
ctx->size * sizeof (void *));
|
||||
ctx->magic = 0;
|
||||
mem_put(ctx->mctx, ctx, sizeof *ctx);
|
||||
if (heap->array != NULL)
|
||||
mem_put(heap->mctx, heap->array,
|
||||
heap->size * sizeof (void *));
|
||||
heap->magic = 0;
|
||||
mem_put(heap->mctx, heap, sizeof *heap);
|
||||
|
||||
*ctxp = NULL;
|
||||
*heapp = NULL;
|
||||
}
|
||||
|
||||
static boolean_t
|
||||
resize(heap_context_t ctx) {
|
||||
resize(heap_t heap) {
|
||||
void **new_array;
|
||||
size_t new_size;
|
||||
|
||||
REQUIRE(VALID_CONTEXT(ctx));
|
||||
REQUIRE(VALID_HEAP(heap));
|
||||
|
||||
new_size = ctx->size + ctx->size_increment;
|
||||
new_array = mem_get(ctx->mctx, new_size * sizeof (void *));
|
||||
new_size = heap->size + heap->size_increment;
|
||||
new_array = mem_get(heap->mctx, new_size * sizeof (void *));
|
||||
if (new_array == NULL)
|
||||
return (FALSE);
|
||||
memcpy(new_array, ctx->array, ctx->size);
|
||||
mem_put(ctx->mctx, ctx->array,
|
||||
ctx->size * sizeof (void *));
|
||||
ctx->size = new_size;
|
||||
ctx->array = new_array;
|
||||
memcpy(new_array, heap->array, heap->size);
|
||||
mem_put(heap->mctx, heap->array,
|
||||
heap->size * sizeof (void *));
|
||||
heap->size = new_size;
|
||||
heap->array = new_array;
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
float_up(heap_context_t ctx, unsigned int i, void *elt) {
|
||||
float_up(heap_t heap, unsigned int i, void *elt) {
|
||||
unsigned int p;
|
||||
|
||||
for ( p = heap_parent(i);
|
||||
i > 1 && ctx->higher_priority(elt, ctx->array[p]);
|
||||
i > 1 && heap->higher_priority(elt, heap->array[p]);
|
||||
i = p, p = heap_parent(i) ) {
|
||||
ctx->array[i] = ctx->array[p];
|
||||
if (ctx->index != NULL)
|
||||
(ctx->index)(ctx->array[i], i);
|
||||
heap->array[i] = heap->array[p];
|
||||
if (heap->index != NULL)
|
||||
(heap->index)(heap->array[i], i);
|
||||
}
|
||||
ctx->array[i] = elt;
|
||||
if (ctx->index != NULL)
|
||||
(ctx->index)(ctx->array[i], i);
|
||||
heap->array[i] = elt;
|
||||
if (heap->index != NULL)
|
||||
(heap->index)(heap->array[i], i);
|
||||
}
|
||||
|
||||
static void
|
||||
sink_down(heap_context_t ctx, unsigned int i, void *elt) {
|
||||
sink_down(heap_t heap, unsigned int i, void *elt) {
|
||||
unsigned int j, size, half_size;
|
||||
|
||||
size = ctx->last;
|
||||
size = heap->last;
|
||||
half_size = size / 2;
|
||||
while (i <= half_size) {
|
||||
/* find smallest of the (at most) two children */
|
||||
j = heap_left(i);
|
||||
if (j < size && ctx->higher_priority(ctx->array[j+1],
|
||||
ctx->array[j]))
|
||||
if (j < size && heap->higher_priority(heap->array[j+1],
|
||||
heap->array[j]))
|
||||
j++;
|
||||
if (ctx->higher_priority(elt, ctx->array[j]))
|
||||
if (heap->higher_priority(elt, heap->array[j]))
|
||||
break;
|
||||
ctx->array[i] = ctx->array[j];
|
||||
if (ctx->index != NULL)
|
||||
(ctx->index)(ctx->array[i], i);
|
||||
heap->array[i] = heap->array[j];
|
||||
if (heap->index != NULL)
|
||||
(heap->index)(heap->array[i], i);
|
||||
i = j;
|
||||
}
|
||||
ctx->array[i] = elt;
|
||||
if (ctx->index != NULL)
|
||||
(ctx->index)(ctx->array[i], i);
|
||||
heap->array[i] = elt;
|
||||
if (heap->index != NULL)
|
||||
(heap->index)(heap->array[i], i);
|
||||
}
|
||||
|
||||
isc_result
|
||||
heap_insert(heap_context_t ctx, void *elt) {
|
||||
heap_insert(heap_t heap, void *elt) {
|
||||
unsigned int i;
|
||||
|
||||
REQUIRE(VALID_CONTEXT(ctx));
|
||||
REQUIRE(VALID_HEAP(heap));
|
||||
|
||||
i = ++ctx->last;
|
||||
if (ctx->last >= ctx->size && !resize(ctx))
|
||||
i = ++heap->last;
|
||||
if (heap->last >= heap->size && !resize(heap))
|
||||
return (ISC_R_NOMEMORY);
|
||||
|
||||
float_up(ctx, i, elt);
|
||||
float_up(heap, i, elt);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
heap_delete(heap_context_t ctx, unsigned int i) {
|
||||
heap_delete(heap_t heap, unsigned int i) {
|
||||
void *elt;
|
||||
|
||||
REQUIRE(VALID_CONTEXT(ctx));
|
||||
REQUIRE(i >= 1 && i <= ctx->last);
|
||||
REQUIRE(VALID_HEAP(heap));
|
||||
REQUIRE(i >= 1 && i <= heap->last);
|
||||
|
||||
elt = ctx->array[ctx->last];
|
||||
if (--ctx->last > 0)
|
||||
sink_down(ctx, i, elt);
|
||||
elt = heap->array[heap->last];
|
||||
if (--heap->last > 0)
|
||||
sink_down(heap, i, elt);
|
||||
}
|
||||
|
||||
void
|
||||
heap_increased(heap_context_t ctx, unsigned int i) {
|
||||
REQUIRE(VALID_CONTEXT(ctx));
|
||||
REQUIRE(i >= 1 && i <= ctx->last);
|
||||
heap_increased(heap_t heap, unsigned int i) {
|
||||
REQUIRE(VALID_HEAP(heap));
|
||||
REQUIRE(i >= 1 && i <= heap->last);
|
||||
|
||||
float_up(ctx, i, ctx->array[i]);
|
||||
float_up(heap, i, heap->array[i]);
|
||||
}
|
||||
|
||||
void
|
||||
heap_decreased(heap_context_t ctx, unsigned int i) {
|
||||
REQUIRE(VALID_CONTEXT(ctx));
|
||||
REQUIRE(i >= 1 && i <= ctx->last);
|
||||
heap_decreased(heap_t heap, unsigned int i) {
|
||||
REQUIRE(VALID_HEAP(heap));
|
||||
REQUIRE(i >= 1 && i <= heap->last);
|
||||
|
||||
sink_down(ctx, i, ctx->array[i]);
|
||||
sink_down(heap, i, heap->array[i]);
|
||||
}
|
||||
|
||||
void *
|
||||
heap_element(heap_context_t ctx, unsigned int i) {
|
||||
REQUIRE(VALID_CONTEXT(ctx));
|
||||
REQUIRE(i >= 1 && i <= ctx->last);
|
||||
heap_element(heap_t heap, unsigned int i) {
|
||||
REQUIRE(VALID_HEAP(heap));
|
||||
REQUIRE(i >= 1 && i <= heap->last);
|
||||
|
||||
return (ctx->array[i]);
|
||||
return (heap->array[i]);
|
||||
}
|
||||
|
||||
void
|
||||
heap_for_each(heap_context_t ctx, heap_for_each_func action, void *uap) {
|
||||
heap_for_each(heap_t heap, heap_for_each_func action, void *uap) {
|
||||
unsigned int i;
|
||||
|
||||
REQUIRE(VALID_CONTEXT(ctx));
|
||||
REQUIRE(VALID_HEAP(heap));
|
||||
REQUIRE(action != NULL);
|
||||
|
||||
for (i = 1; i <= ctx->last; i++)
|
||||
(action)(ctx->array[i], uap);
|
||||
for (i = 1; i <= heap->last; i++)
|
||||
(action)(heap->array[i], uap);
|
||||
}
|
||||
|
||||
29
lib/isc/include/isc/event.h
Normal file
29
lib/isc/include/isc/event.h
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
#ifndef ISC_EVENT_H
|
||||
#define ISC_EVENT_H 1
|
||||
|
||||
/***
|
||||
*** Registry of Predefined Event Type Classes
|
||||
***/
|
||||
|
||||
/*
|
||||
* An event class is a 16 bit number, the most sigificant bit of which must be
|
||||
* zero. Each class may contain up to 65536 events. An event type is
|
||||
* formed by adding the event number within the class to the class number.
|
||||
* E.g., the first event in the timer class is EVENT_CLASS_TIMER + 1. Event
|
||||
* number zero is always reserved in each class.
|
||||
*/
|
||||
|
||||
#define EVENT_CLASS(class) ((class) << 16)
|
||||
|
||||
#define EVENT_CLASS_TASK EVENT_CLASS(0)
|
||||
|
||||
#define EVENT_CLASS_TIMER EVENT_CLASS(1)
|
||||
#define EVENT_CLASS_NET EVENT_CLASS(2)
|
||||
#define EVENT_CLASS_FILE EVENT_CLASS(3)
|
||||
|
||||
/*
|
||||
* Event classes >= 1024 and <= 32767 are reserved for application use.
|
||||
*/
|
||||
|
||||
#endif /* ISC_EVENT_H */
|
||||
45
lib/isc/include/isc/heap.h
Normal file
45
lib/isc/include/isc/heap.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 1998 by Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <isc/result.h>
|
||||
#include <isc/boolean.h>
|
||||
#include <isc/memcluster.h>
|
||||
|
||||
typedef boolean_t (*heap_higher_priority_func)(void *, void *);
|
||||
typedef void (*heap_index_func)(void *, unsigned int);
|
||||
typedef void (*heap_for_each_func)(void *, void *);
|
||||
|
||||
typedef struct heap_context *heap_t;
|
||||
|
||||
#define heap_create __heap_create
|
||||
#define heap_destroy __heap_destroy
|
||||
#define heap_insert __heap_insert
|
||||
#define heap_delete __heap_delete
|
||||
#define heap_increased __heap_increased
|
||||
#define heap_decreased __heap_decreased
|
||||
#define heap_element __heap_element
|
||||
#define heap_for_each __heap_for_each
|
||||
|
||||
isc_result heap_create(mem_context_t, heap_higher_priority_func,
|
||||
heap_index_func, unsigned int, heap_t *);
|
||||
void heap_destroy(heap_t *);
|
||||
isc_result heap_insert(heap_t, void *);
|
||||
void heap_delete(heap_t, unsigned int);
|
||||
void heap_increased(heap_t, unsigned int);
|
||||
void heap_decreased(heap_t, unsigned int);
|
||||
void * heap_element(heap_t, unsigned int);
|
||||
void heap_for_each(heap_t, heap_for_each_func, void *);
|
||||
@@ -46,7 +46,7 @@ struct task_event {
|
||||
LINK(struct task_event) link;
|
||||
};
|
||||
|
||||
#define TASK_EVENT_NOP 0
|
||||
#define TASK_EVENT_ANYEVENT 0
|
||||
#define TASK_EVENT_SHUTDOWN (-1)
|
||||
|
||||
typedef LIST(struct task_event) task_eventlist_t;
|
||||
|
||||
@@ -95,13 +95,14 @@ timer_create(timer_manager_t manager,
|
||||
os_time_t absolute,
|
||||
os_time_t interval,
|
||||
task_t task,
|
||||
task_action_t action,
|
||||
void *arg,
|
||||
timer_t *timerp);
|
||||
/*
|
||||
* Create a new 'type' timer managed by 'manager'. The timers parameters
|
||||
* are specified by 'absolute' and 'interval'. Events will be posted to
|
||||
* 'task' and will use 'arg' as the arg value. The new timer is returned in
|
||||
* 'timerp'.
|
||||
* 'task' and when dispatched 'action' will be called with 'arg' as the
|
||||
* arg value. The new timer is returned in 'timerp'.
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
@@ -122,6 +123,8 @@ timer_create(timer_manager_t manager,
|
||||
*
|
||||
* 'task' is a valid task
|
||||
*
|
||||
* 'action' is a valid action
|
||||
*
|
||||
* 'absolute' and 'idle' may not both be 0
|
||||
*
|
||||
* 'timerp' is a valid pointer, and *timerp == NULL
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <isc/boolean.h>
|
||||
#include <isc/mutex.h>
|
||||
#include <isc/assertions.h>
|
||||
|
||||
typedef pthread_cond_t os_condition_t;
|
||||
#define OS_CONDITION_INITIALIZER PTHREAD_COND_INITIALIZER
|
||||
|
||||
@@ -11,6 +11,7 @@ typedef pthread_t os_thread_t;
|
||||
#define os_thread_create(s, a, tp) (pthread_create((tp), NULL, (s), (a)) \
|
||||
== 0)
|
||||
#define os_thread_detach(t) (pthread_detach((t)) == 0)
|
||||
#define os_thread_join(t) (pthread_join((t), NULL) == 0)
|
||||
#define os_thread_self pthread_self
|
||||
|
||||
#endif /* THREAD_H */
|
||||
|
||||
325
lib/isc/timer.c
325
lib/isc/timer.c
@@ -3,6 +3,11 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <isc/assertions.h>
|
||||
#include <isc/unexpect.h>
|
||||
#include <isc/thread.h>
|
||||
#include <isc/mutex.h>
|
||||
#include <isc/condition.h>
|
||||
#include <isc/heap.h>
|
||||
#include <isc/timer.h>
|
||||
|
||||
/*
|
||||
@@ -12,10 +17,12 @@
|
||||
* We INSIST that they succeed since there's no way for us to continue
|
||||
* if they fail.
|
||||
*/
|
||||
#define LOCK(lp) INSIST(os_mutex_lock((lp)))
|
||||
#define UNLOCK(lp) INSIST(os_mutex_unlock((lp)))
|
||||
#define BROADCAST(cvp) INSIST(os_condition_broadcast((cvp)))
|
||||
|
||||
#define LOCK(lp) INSIST(os_mutex_lock((lp)))
|
||||
#define UNLOCK(lp) INSIST(os_mutex_unlock((lp)))
|
||||
#define BROADCAST(cvp) INSIST(os_condition_broadcast((cvp)))
|
||||
#define WAIT(cvp, lp) INSIST(os_condition_wait((cvp), (lp)))
|
||||
#define WAITUNTIL(cvp, lp, tp, bp) INSIST(os_condition_waituntil((cvp), \
|
||||
(lp), (tp), (bp)))
|
||||
|
||||
#define TIMER_MAGIC 0x54494D52U /* TIMR. */
|
||||
#define VALID_TIMER(t) ((t) != NULL && \
|
||||
@@ -33,8 +40,9 @@ struct timer_t {
|
||||
os_time_t absolute;
|
||||
os_time_t interval;
|
||||
task_t task;
|
||||
task_action_t action;
|
||||
void * arg;
|
||||
int index;
|
||||
unsigned int index;
|
||||
os_time_t next_time;
|
||||
LINK(struct timer_t) link;
|
||||
};
|
||||
@@ -49,14 +57,42 @@ struct timer_manager_t {
|
||||
mem_context_t mctx;
|
||||
os_mutex_t lock;
|
||||
/* Locked by manager lock. */
|
||||
boolean_t done;
|
||||
LIST(struct timer_t) timers;
|
||||
unsigned int nscheduled;
|
||||
os_time_t next_time;
|
||||
os_condition_t wakeup;
|
||||
os_thread_t thread;
|
||||
heap_context heap;
|
||||
heap_t heap;
|
||||
};
|
||||
|
||||
|
||||
static boolean_t
|
||||
sooner(void *v1, void *v2) {
|
||||
timer_t t1, t2;
|
||||
|
||||
t1 = v1;
|
||||
t2 = v2;
|
||||
REQUIRE(VALID_TIMER(t1));
|
||||
REQUIRE(VALID_TIMER(t2));
|
||||
|
||||
if (os_time_compare(&t1->next_time, &t2->next_time) < 0)
|
||||
return (TRUE);
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
set_index(void *what, unsigned int index) {
|
||||
timer_t timer;
|
||||
|
||||
timer = what;
|
||||
REQUIRE(VALID_TIMER(timer));
|
||||
|
||||
timer->index = index;
|
||||
}
|
||||
|
||||
static inline void
|
||||
schedule(timer_t timer, os_time_t *now, boolean_t first_time) {
|
||||
nexttime(timer_t timer, os_time_t *nowp, boolean_t first_time) {
|
||||
/*
|
||||
* The caller must ensure locking.
|
||||
*/
|
||||
@@ -65,19 +101,19 @@ schedule(timer_t timer, os_time_t *now, boolean_t first_time) {
|
||||
if (first_time) {
|
||||
if (timer->absolute.seconds == 0 &&
|
||||
timer->absolute.nanoseconds == 0)
|
||||
timer->next_time = now;
|
||||
timer->next_time = *nowp;
|
||||
else
|
||||
timer->next_time = timer->absolute;
|
||||
} else
|
||||
os_time_add(&now, &timer->interval, &timer->next_time);
|
||||
os_time_add(nowp, &timer->interval, &timer->next_time);
|
||||
} else {
|
||||
/* Idle timer. */
|
||||
if (os_time_compare(&timer->touched, &now) <= 0) {
|
||||
if (os_time_compare(&timer->touched, nowp) <= 0) {
|
||||
os_time_t idle, remaining;
|
||||
|
||||
os_time_subtract(&now, &timer->touched, &idle);
|
||||
os_time_subtract(nowp, &timer->touched, &idle);
|
||||
if (os_time_compare(&idle, &timer->interval) >= 0) {
|
||||
os_time_add(&now, &timer->interval,
|
||||
os_time_add(nowp, &timer->interval,
|
||||
&timer->next_time);
|
||||
} else {
|
||||
|
||||
@@ -86,24 +122,81 @@ schedule(timer_t timer, os_time_t *now, boolean_t first_time) {
|
||||
/*
|
||||
* Time touched is in the future! Make it now.
|
||||
*/
|
||||
timer->touched = now;
|
||||
os_time_add(&now, &timer->interval, &timer->next_time);
|
||||
timer->touched = *nowp;
|
||||
os_time_add(nowp, &timer->interval, &timer->next_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline isc_result
|
||||
schedule(timer_t timer, os_time_t *new_nextimep) {
|
||||
isc_result result;
|
||||
timer_manager_t manager;
|
||||
|
||||
/*
|
||||
* The caller must ensure locking.
|
||||
*/
|
||||
|
||||
manager = timer->manager;
|
||||
if (timer->index > 0) {
|
||||
/*
|
||||
* Already scheduled.
|
||||
*/
|
||||
switch (os_time_compare(new_nextimep, &timer->next_time)) {
|
||||
case -1:
|
||||
heap_increased(manager->heap, timer->index);
|
||||
break;
|
||||
case 1:
|
||||
heap_decreased(manager->heap, timer->index);
|
||||
break;
|
||||
case 0:
|
||||
/* Nothing to do. */
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
result = heap_insert(manager->heap, timer);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
INSIST(result == ISC_R_NOMEMORY);
|
||||
return (ISC_R_NOMEMORY);
|
||||
}
|
||||
manager->nscheduled++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this timer is at the head of the queue, we must wake up the
|
||||
* run thread so it doesn't sleep too long.
|
||||
*/
|
||||
if (timer->index == 1)
|
||||
BROADCAST(&manager->wakeup);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static inline void
|
||||
deschedule(timer_t) {
|
||||
deschedule(timer_t timer) {
|
||||
boolean_t need_wakeup = FALSE;
|
||||
timer_manager_t manager;
|
||||
|
||||
/*
|
||||
* The caller must ensure locking.
|
||||
*/
|
||||
|
||||
manager = timer->manager;
|
||||
if (timer->index > 0) {
|
||||
if (timer->index == 1)
|
||||
need_wakeup = TRUE;
|
||||
heap_delete(manager->heap, timer->index);
|
||||
timer->index = 0;
|
||||
INSIST(manager->nscheduled > 0);
|
||||
manager->nscheduled--;
|
||||
if (need_wakeup)
|
||||
BROADCAST(&manager->wakeup);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(timer_t timer) {
|
||||
timer_manager_t manager = timer->manager;
|
||||
isc_result result;
|
||||
|
||||
/*
|
||||
* The caller must ensure locking.
|
||||
@@ -126,23 +219,25 @@ destroy(timer_t timer) {
|
||||
isc_result
|
||||
timer_create(timer_manager_t manager, timer_type_t type,
|
||||
os_time_t absolute, os_time_t interval,
|
||||
task_t task, void *arg, timer_t *timerp)
|
||||
task_t task, task_action_t action, void *arg, timer_t *timerp)
|
||||
{
|
||||
timer_t timer;
|
||||
isc_result result;
|
||||
os_time_t now;
|
||||
os_time_t now, next_time;
|
||||
|
||||
/*
|
||||
* Create a new 'type' timer managed by 'manager'. The timers
|
||||
* parameters are specified by 'absolute' and 'interval'. Events
|
||||
* will be posted to 'task' and will use 'arg' as the arg value.
|
||||
* The new timer is returned in 'timerp'.
|
||||
* will be posted to 'task' and when dispatched 'action' will be
|
||||
* called with 'arg' as the arg value. The new timer is returned
|
||||
* in 'timerp'.
|
||||
*/
|
||||
|
||||
REQUIRE(VALID_MANAGER(manager));
|
||||
REQUIRE(task != NULL);
|
||||
REQUIRE(!(absolute->seconds == 0 && absolute->nanoseconds == 0 &&
|
||||
interval->seconds == 0 && interval->nanoseconds == 0));
|
||||
REQUIRE(action != NULL);
|
||||
REQUIRE(!(absolute.seconds == 0 && absolute.nanoseconds == 0 &&
|
||||
interval.seconds == 0 && interval.nanoseconds == 0));
|
||||
REQUIRE(timerp != NULL && *timerp == NULL);
|
||||
|
||||
/*
|
||||
@@ -163,13 +258,15 @@ timer_create(timer_manager_t manager, timer_type_t type,
|
||||
timer->magic = TIMER_MAGIC;
|
||||
timer->manager = manager;
|
||||
timer->references = 1;
|
||||
timer->touched = now;
|
||||
timer->type = type;
|
||||
timer->absolute = absolute;
|
||||
timer->interval = interval;
|
||||
timer->task = NULL;
|
||||
task_attach(task, &timer->task);
|
||||
timer->action = action;
|
||||
timer->arg = arg;
|
||||
timer->touched = now;
|
||||
timer->index = 0;
|
||||
if (!os_mutex_init(&timer->lock)) {
|
||||
mem_put(manager->mctx, timer, sizeof *timer);
|
||||
unexpected_error(__FILE__, __LINE__, "os_mutex_init() failed");
|
||||
@@ -184,7 +281,7 @@ timer_create(timer_manager_t manager, timer_type_t type,
|
||||
*/
|
||||
|
||||
APPEND(manager->timers, timer, link);
|
||||
result = schedule(timer, &now, TRUE);
|
||||
result = schedule(timer, &next_time);
|
||||
|
||||
UNLOCK(&manager->lock);
|
||||
|
||||
@@ -198,7 +295,7 @@ isc_result
|
||||
timer_reset(timer_t timer, timer_type_t type,
|
||||
os_time_t absolute, os_time_t interval)
|
||||
{
|
||||
os_time_t now;
|
||||
os_time_t now, next_time;
|
||||
timer_manager_t manager;
|
||||
isc_result result;
|
||||
|
||||
@@ -210,8 +307,8 @@ timer_reset(timer_t timer, timer_type_t type,
|
||||
REQUIRE(VALID_TIMER(timer));
|
||||
manager = timer->manager;
|
||||
REQUIRE(VALID_MANAGER(manager));
|
||||
REQUIRE(!(absolute->seconds == 0 && absolute->nanoseconds == 0 &&
|
||||
interval->seconds == 0 && interval->nanoseconds == 0));
|
||||
REQUIRE(!(absolute.seconds == 0 && absolute.nanoseconds == 0 &&
|
||||
interval.seconds == 0 && interval.nanoseconds == 0));
|
||||
|
||||
/*
|
||||
* Get current time.
|
||||
@@ -234,7 +331,7 @@ timer_reset(timer_t timer, timer_type_t type,
|
||||
timer->interval = interval;
|
||||
timer->touched = now;
|
||||
|
||||
result = schedule(timer, &now, FALSE);
|
||||
result = schedule(timer, &next_time);
|
||||
|
||||
UNLOCK(&timer->lock);
|
||||
UNLOCK(&manager->lock);
|
||||
@@ -269,6 +366,8 @@ timer_shutdown(timer_t timer) {
|
||||
|
||||
isc_result
|
||||
timer_touch(timer_t timer) {
|
||||
isc_result result;
|
||||
|
||||
/*
|
||||
* Set the last-touched time of 'timer' to the current time.
|
||||
*/
|
||||
@@ -317,8 +416,9 @@ timer_detach(timer_t *timerp) {
|
||||
* Detach *timerp from its timer.
|
||||
*/
|
||||
|
||||
REQUIRE(timerp != NULL);
|
||||
timer = *timerp;
|
||||
REQUIRE(VALID_TIMER(timer));
|
||||
REQUIRE(timerp != NULL && *timerp == NULL);
|
||||
|
||||
LOCK(&timer->lock);
|
||||
REQUIRE(timer->references > 0);
|
||||
@@ -333,53 +433,128 @@ timer_detach(timer_t *timerp) {
|
||||
*timerp = NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
run(void *uap) {
|
||||
timer_manager_t manager = uap;
|
||||
struct timespec ts;
|
||||
boolean_t timeout;
|
||||
|
||||
LOCK(&manager->lock);
|
||||
while (!manager->done) {
|
||||
|
||||
printf("timer run thread awake\n");
|
||||
|
||||
if (manager->nscheduled > 0) {
|
||||
ts.tv_sec = manager->next_time.seconds;
|
||||
ts.tv_nsec = manager->next_time.nanoseconds;
|
||||
|
||||
timeout = FALSE;
|
||||
WAITUNTIL(&manager->wakeup, &manager->lock, &ts,
|
||||
&timeout);
|
||||
} else {
|
||||
WAIT(&manager->wakeup, &manager->lock);
|
||||
timeout = FALSE;
|
||||
}
|
||||
}
|
||||
UNLOCK(&manager->lock);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
isc_result
|
||||
timer_manager_create(mem_context_t mctx, timer_manager_t *managerp);
|
||||
/*
|
||||
* Create a timer manager.
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* All memory will be allocated in memory context 'mctx'.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
* 'mctx' is a valid memory context.
|
||||
*
|
||||
* 'managerp' points to a NULL timer_manager_t.
|
||||
*
|
||||
* Ensures:
|
||||
*
|
||||
* '*managerp' is a valid timer_manager_t.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Success
|
||||
* No memory
|
||||
* Unexpected error
|
||||
*/
|
||||
timer_manager_create(mem_context_t mctx, timer_manager_t *managerp) {
|
||||
timer_manager_t manager;
|
||||
isc_result result;
|
||||
|
||||
/*
|
||||
* Create a timer manager.
|
||||
*/
|
||||
|
||||
REQUIRE(managerp != NULL && *managerp == NULL);
|
||||
|
||||
manager = mem_get(mctx, sizeof *manager);
|
||||
if (manager == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
|
||||
manager->magic = TIMER_MANAGER_MAGIC;
|
||||
manager->mctx = mctx;
|
||||
manager->done = FALSE;
|
||||
INIT_LIST(manager->timers);
|
||||
manager->nscheduled = 0;
|
||||
manager->next_time.seconds = 0;
|
||||
manager->next_time.nanoseconds = 0;
|
||||
manager->heap = NULL;
|
||||
result = heap_create(mctx, sooner, set_index, 0, &manager->heap);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
INSIST(result == ISC_R_NOMEMORY);
|
||||
mem_put(mctx, manager, sizeof *manager);
|
||||
return (ISC_R_NOMEMORY);
|
||||
}
|
||||
if (!os_mutex_init(&manager->lock)) {
|
||||
heap_destroy(&manager->heap);
|
||||
mem_put(mctx, manager, sizeof *manager);
|
||||
unexpected_error(__FILE__, __LINE__, "os_mutex_init() failed");
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
if (!os_condition_init(&manager->wakeup)) {
|
||||
(void)os_mutex_destroy(&manager->lock);
|
||||
heap_destroy(&manager->heap);
|
||||
mem_put(mctx, manager, sizeof *manager);
|
||||
unexpected_error(__FILE__, __LINE__,
|
||||
"os_condition_init() failed");
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
if (!os_thread_create(run, manager, &manager->thread)) {
|
||||
(void)os_condition_destroy(&manager->wakeup);
|
||||
(void)os_mutex_destroy(&manager->lock);
|
||||
heap_destroy(&manager->heap);
|
||||
mem_put(mctx, manager, sizeof *manager);
|
||||
unexpected_error(__FILE__, __LINE__,
|
||||
"os_thread_create() failed");
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
|
||||
*managerp = manager;
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
timer_manager_destroy(timer_manager_t *);
|
||||
/*
|
||||
* Destroy a timer manager.
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* This routine blocks until there are no timers left in the manager,
|
||||
* so if the caller holds any timer references using the manager, it
|
||||
* must detach them before calling timer_manager_destroy() or it will
|
||||
* block forever.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
* '*managerp' is a valid timer_manager_t.
|
||||
*
|
||||
* Ensures:
|
||||
*
|
||||
* *managerp == NULL
|
||||
*
|
||||
* All resources used by the manager have been freed.
|
||||
*/
|
||||
timer_manager_destroy(timer_manager_t *managerp) {
|
||||
timer_manager_t manager;
|
||||
|
||||
#endif /* ISC_TIMER_H */
|
||||
/*
|
||||
* Destroy a timer manager.
|
||||
*/
|
||||
|
||||
REQUIRE(managerp != NULL);
|
||||
manager = *managerp;
|
||||
REQUIRE(VALID_MANAGER(manager));
|
||||
|
||||
LOCK(&manager->lock);
|
||||
|
||||
REQUIRE(EMPTY(manager->timers));
|
||||
manager->done = TRUE;
|
||||
|
||||
UNLOCK(&manager->lock);
|
||||
|
||||
BROADCAST(&manager->wakeup);
|
||||
|
||||
/*
|
||||
* Wait for thread to exit.
|
||||
*/
|
||||
if (!os_thread_join(manager->thread))
|
||||
unexpected_error(__FILE__, __LINE__,
|
||||
"os_thread_join() failed");
|
||||
|
||||
/*
|
||||
* Clean up.
|
||||
*/
|
||||
(void)os_condition_destroy(&manager->wakeup);
|
||||
(void)os_mutex_destroy(&manager->lock);
|
||||
heap_destroy(&manager->heap);
|
||||
manager->magic = 0;
|
||||
mem_put(manager->mctx, manager, sizeof *manager);
|
||||
|
||||
*managerp = NULL;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
|
||||
#ifndef ISC_TIME_H
|
||||
#define ISC_TIME_H 1
|
||||
|
||||
#include <time.h>
|
||||
#include <isc/result.h>
|
||||
|
||||
/*
|
||||
@@ -63,3 +67,5 @@ os_time_subtract(os_time_t *t1p, os_time_t *t2p, os_time_t *t3p);
|
||||
*
|
||||
* *tp1 >= *t2p
|
||||
*/
|
||||
|
||||
#endif /* ISC_TIME_H */
|
||||
|
||||
Reference in New Issue
Block a user