Commit 29852346 authored by Bob Halley's avatar Bob Halley
Browse files

checkpoint

parent 00c6365a
......@@ -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);
......
......@@ -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);
}
#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 */
/*
* 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 */
......@@ -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);
}
}