From 298523461941e171ce97ea8b76892ac01bb7a49f Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Fri, 16 Oct 1998 01:18:31 +0000 Subject: [PATCH] checkpoint --- bin/tests/task_test.c | 64 ++--- lib/isc/heap.c | 164 ++++++------ lib/isc/include/isc/event.h | 29 ++ lib/isc/include/isc/heap.h | 45 ++++ lib/isc/include/isc/task.h | 2 +- lib/isc/include/isc/timer.h | 7 +- lib/isc/pthreads/include/isc/condition.h | 1 - lib/isc/pthreads/include/isc/thread.h | 1 + lib/isc/timer.c | 325 +++++++++++++++++------ lib/isc/unix/include/isc/time.h | 6 + 10 files changed, 440 insertions(+), 204 deletions(-) create mode 100644 lib/isc/include/isc/event.h create mode 100644 lib/isc/include/isc/heap.h diff --git a/bin/tests/task_test.c b/bin/tests/task_test.c index c498eb142b..3cfcc813f0 100644 --- a/bin/tests/task_test.c +++ b/bin/tests/task_test.c @@ -8,13 +8,13 @@ #include #include #include +#include +#include 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); diff --git a/lib/isc/heap.c b/lib/isc/heap.c index a0a9aa76cc..782f45e74d 100644 --- a/lib/isc/heap.c +++ b/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); } diff --git a/lib/isc/include/isc/event.h b/lib/isc/include/isc/event.h new file mode 100644 index 0000000000..dd3000f279 --- /dev/null +++ b/lib/isc/include/isc/event.h @@ -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 */ diff --git a/lib/isc/include/isc/heap.h b/lib/isc/include/isc/heap.h new file mode 100644 index 0000000000..7662ee324c --- /dev/null +++ b/lib/isc/include/isc/heap.h @@ -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 +#include +#include + +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 *); diff --git a/lib/isc/include/isc/task.h b/lib/isc/include/isc/task.h index 2a9672eab6..a77691f62b 100644 --- a/lib/isc/include/isc/task.h +++ b/lib/isc/include/isc/task.h @@ -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; diff --git a/lib/isc/include/isc/timer.h b/lib/isc/include/isc/timer.h index c7e6742829..3fefbd5fa2 100644 --- a/lib/isc/include/isc/timer.h +++ b/lib/isc/include/isc/timer.h @@ -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 diff --git a/lib/isc/pthreads/include/isc/condition.h b/lib/isc/pthreads/include/isc/condition.h index 4d39d595d6..3fe3343059 100644 --- a/lib/isc/pthreads/include/isc/condition.h +++ b/lib/isc/pthreads/include/isc/condition.h @@ -6,7 +6,6 @@ #include #include -#include typedef pthread_cond_t os_condition_t; #define OS_CONDITION_INITIALIZER PTHREAD_COND_INITIALIZER diff --git a/lib/isc/pthreads/include/isc/thread.h b/lib/isc/pthreads/include/isc/thread.h index 6185085812..080dc3e462 100644 --- a/lib/isc/pthreads/include/isc/thread.h +++ b/lib/isc/pthreads/include/isc/thread.h @@ -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 */ diff --git a/lib/isc/timer.c b/lib/isc/timer.c index 853414d5fe..6bdbfba2a8 100644 --- a/lib/isc/timer.c +++ b/lib/isc/timer.c @@ -3,6 +3,11 @@ #include #include +#include +#include +#include +#include +#include #include /* @@ -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; +} diff --git a/lib/isc/unix/include/isc/time.h b/lib/isc/unix/include/isc/time.h index bafab25b32..1d1f00f0f3 100644 --- a/lib/isc/unix/include/isc/time.h +++ b/lib/isc/unix/include/isc/time.h @@ -1,4 +1,8 @@ +#ifndef ISC_TIME_H +#define ISC_TIME_H 1 + +#include #include /* @@ -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 */