Commit 94123b51 authored by Bob Halley's avatar Bob Halley

checkpoint

parent dcd83f0e
......@@ -10,12 +10,14 @@
#include <isc/thread.h>
mem_context_t mctx = NULL;
os_mutex_t timer_lock;
os_condition_t timer_wakeup;
/*ARGSUSED*/
static boolean_t
my_callback(task_t __attribute__((unused)) task,
void *arg,
generic_event_t __attribute__((unused)) event)
task_event_t __attribute__((unused)) event)
{
int i, j;
char *name = arg;
......@@ -32,7 +34,7 @@ my_callback(task_t __attribute__((unused)) task,
static boolean_t
my_shutdown(task_t __attribute__((unused)) task,
void *arg,
generic_event_t __attribute__((unused)) event)
task_event_t __attribute__((unused)) event)
{
char *name = arg;
......@@ -44,7 +46,7 @@ my_shutdown(task_t __attribute__((unused)) task,
static boolean_t
my_tick(task_t __attribute__((unused)) task,
void *arg,
generic_event_t __attribute__((unused)) event)
task_event_t __attribute__((unused)) event)
{
char *name = arg;
......@@ -52,16 +54,41 @@ my_tick(task_t __attribute__((unused)) task,
return (FALSE);
}
/*ARGSUSED*/
static boolean_t
wakeup_timer(task_t __attribute__((unused)) task,
void *arg,
task_event_t __attribute__((unused)) event)
{
printf("wakeup timer\n");
(void)os_condition_broadcast(&timer_wakeup);
return (FALSE);
}
void *
simple_timer_run(void *arg) {
task_t task = arg;
generic_event_t event;
task_event_t event;
int i;
struct timespec ts;
struct timeval tv;
struct timeval tv1;
boolean_t timeout;
for (i = 0; i < 10; i++) {
sleep(1);
for (i = 0; i < 5; i++) {
(void)gettimeofday(&tv, NULL);
ts.tv_sec = tv.tv_sec + 5;
ts.tv_nsec = 0;
(void)os_mutex_lock(&timer_lock);
(void)os_condition_waituntil(&timer_wakeup, &timer_lock, &ts,
&timeout);
(void)os_mutex_unlock(&timer_lock);
(void)gettimeofday(&tv1, NULL);
printf("slept %d secs\n", tv1.tv_sec - tv.tv_sec);
if (timeout)
printf("timer timeout\n");
printf("sending timer to %p\n", task);
event = event_get(mctx, 2, my_tick, sizeof *event);
event = task_event_allocate(mctx, 2, my_tick, NULL, sizeof *event);
INSIST(event != NULL);
(void)task_send_event(task, &event);
}
......@@ -77,6 +104,8 @@ simple_timer_init(task_t task) {
task_clone = NULL;
task_attach(task, &task_clone);
(void)os_mutex_init(&timer_lock);
(void)os_condition_init(&timer_wakeup);
INSIST(os_thread_create(simple_timer_run, task_clone, &t));
(void)os_thread_detach(t);
}
......@@ -86,7 +115,7 @@ main(int argc, char *argv[]) {
task_manager_t manager = NULL;
task_t t1 = NULL, t2 = NULL;
task_t t3 = NULL, t4 = NULL;
generic_event_t event;
task_event_t event;
unsigned int workers;
if (argc > 1)
......@@ -110,35 +139,35 @@ main(int argc, char *argv[]) {
printf("task 2 = %p\n", t2);
sleep(2);
event = event_get(mctx, 1, my_callback, sizeof *event);
event = task_event_allocate(mctx, 1, my_callback, NULL, sizeof *event);
task_send_event(t1, &event);
event = event_get(mctx, 1, my_callback, sizeof *event);
event = task_event_allocate(mctx, 1, wakeup_timer, NULL, sizeof *event);
task_send_event(t1, &event);
event = event_get(mctx, 1, my_callback, sizeof *event);
event = task_event_allocate(mctx, 1, my_callback, NULL, sizeof *event);
task_send_event(t1, &event);
event = event_get(mctx, 1, my_callback, sizeof *event);
event = task_event_allocate(mctx, 1, my_callback, NULL, sizeof *event);
task_send_event(t1, &event);
event = event_get(mctx, 1, my_callback, sizeof *event);
event = task_event_allocate(mctx, 1, my_callback, NULL, sizeof *event);
task_send_event(t1, &event);
event = event_get(mctx, 1, my_callback, sizeof *event);
event = task_event_allocate(mctx, 1, my_callback, NULL, sizeof *event);
task_send_event(t1, &event);
event = event_get(mctx, 1, my_callback, sizeof *event);
event = task_event_allocate(mctx, 1, my_callback, NULL, sizeof *event);
task_send_event(t1, &event);
event = event_get(mctx, 1, my_callback, sizeof *event);
event = task_event_allocate(mctx, 1, my_callback, NULL, sizeof *event);
task_send_event(t1, &event);
event = event_get(mctx, 1, my_callback, sizeof *event);
event = task_event_allocate(mctx, 1, my_callback, NULL, sizeof *event);
task_send_event(t1, &event);
event = event_get(mctx, 1, my_callback, sizeof *event);
event = task_event_allocate(mctx, 1, my_callback, NULL, sizeof *event);
task_send_event(t2, &event);
event = event_get(mctx, 1, my_callback, sizeof *event);
event = task_event_allocate(mctx, 1, my_callback, NULL, sizeof *event);
task_send_event(t3, &event);
event = event_get(mctx, 1, my_callback, sizeof *event);
event = task_event_allocate(mctx, 1, my_callback, NULL, sizeof *event);
task_send_event(t4, &event);
event = event_get(mctx, 1, my_callback, sizeof *event);
event = task_event_allocate(mctx, 1, my_callback, NULL, sizeof *event);
task_send_event(t2, &event);
event = event_get(mctx, 1, my_callback, sizeof *event);
event = task_event_allocate(mctx, 1, my_callback, NULL, sizeof *event);
task_send_event(t3, &event);
event = event_get(mctx, 1, my_callback, sizeof *event);
event = task_event_allocate(mctx, 1, my_callback, NULL, sizeof *event);
task_send_event(t4, &event);
task_detach(&t1);
......
......@@ -16,7 +16,7 @@
*** Core Types.
***/
typedef struct generic_event * generic_event_t;
typedef struct task_event * task_event_t;
typedef struct task * task_t;
typedef struct task_manager * task_manager_t;
......@@ -28,99 +28,54 @@ typedef struct task_manager * task_manager_t;
/*
* Negative event types are reserved for use by the task manager.
*/
typedef int event_type_t;
typedef int task_eventtype_t;
typedef boolean_t (*event_action_t)(task_t, void *,
generic_event_t);
typedef boolean_t (*task_action_t)(task_t, void *,
task_event_t);
/*
* Unlike other type names, which are prefixed with the module's name,
* event types have a suffix of "_event_t". All event types must start
* with the same fields as the generic event.
*/
struct generic_event {
* This structure is public because "subclassing" it may be useful when
* defining new event types.
*/
struct task_event {
mem_context_t mctx;
size_t size;
event_type_t type;
event_action_t action;
LINK(struct generic_event) link;
task_eventtype_t type;
task_action_t action;
void * arg;
LINK(struct task_event) link;
};
#define TASK_NOP_EVENT (-1)
typedef generic_event_t nop_event_t;
typedef LIST(struct generic_event) event_list_t;
typedef LIST(struct task_event) task_eventlist_t;
generic_event_t event_get(mem_context_t,
event_type_t,
event_action_t,
size_t);
void event_put(generic_event_t *);
task_event_t task_event_allocate(mem_context_t,
task_eventtype_t,
task_action_t,
void *arg,
size_t);
void task_event_free(task_event_t *);
/***
*** Tasks.
***/
typedef enum {
task_state_idle, task_state_ready, task_state_running,
task_state_shutdown
} task_state_t;
#define TASK_MAGIC 0x5441534BU /* TASK. */
struct task {
/* Not locked. */
unsigned int magic;
struct task_manager * manager;
os_mutex_t lock;
/* Locked by task lock. */
task_state_t state;
unsigned int references;
event_list_t events;
unsigned int quantum;
boolean_t shutdown_pending;
event_action_t shutdown_action;
void * arg;
/* Locked by task manager lock. */
LINK(struct task) link;
LINK(struct task) ready_link;
};
boolean_t task_create(task_manager_t,
void *,
event_action_t,
task_action_t,
unsigned int,
task_t *);
void task_attach(task_t, task_t *);
void task_detach(task_t *);
boolean_t task_send_event(task_t,
generic_event_t *);
task_event_t *);
void task_shutdown(task_t);
void task_destroy(task_t *);
/***
*** Task Manager.
***/
#define TASK_MANAGER_MAGIC 0x54534B4DU /* TSKM. */
struct task_manager {
/* Not locked. */
unsigned int magic;
mem_context_t mctx;
os_mutex_t lock;
/* Locked by task manager lock. */
unsigned int default_quantum;
LIST(struct task) tasks;
LIST(struct task) ready_tasks;
os_condition_t work_available;
boolean_t exiting;
unsigned int workers;
os_condition_t no_workers;
};
unsigned int task_manager_create(mem_context_t,
unsigned int,
unsigned int,
......
......@@ -3,6 +3,9 @@
#define CONDITION_H 1
#include <pthread.h>
#include <errno.h>
#include <isc/boolean.h>
#include <isc/assertions.h>
typedef pthread_cond_t os_condition_t;
......@@ -10,6 +13,10 @@ typedef pthread_cond_t os_condition_t;
#define os_condition_init(cp) (pthread_cond_init((cp), NULL) == 0)
#define os_condition_wait(cp, mp) (pthread_cond_wait((cp), (mp)) == 0)
#define os_condition_waituntil(cp, mp, tsp, top) \
(pthread_cond_timedwait((cp), (mp), (tsp)) == 0 \
? TRUE \
: ((*(top) = (errno == ETIMEDOUT)), FALSE))
#define os_condition_signal(cp) (pthread_cond_signal((cp)) == 0)
#define os_condition_broadcast(cp) (pthread_cond_broadcast((cp)) == 0)
#define os_condition_destroy(cp) (pthread_cond_destroy((cp)) == 0)
......
......@@ -11,5 +11,6 @@ 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_self pthread_self
#endif /* THREAD_H */
......@@ -6,10 +6,10 @@
#include <isc/thread.h>
#include <isc/task.h>
#define VALID_MANAGER(m) ((m) != NULL && \
(m)->magic == TASK_MANAGER_MAGIC)
#define VALID_TASK(t) ((t) != NULL && \
(t)->magic == TASK_MAGIC)
/***
*** General Macros.
***/
/*
* We use macros instead of calling the os_ routines directly because
......@@ -23,56 +23,65 @@
#define WAIT(cvp, lp) INSIST(os_condition_wait((cvp), (lp)))
#define BROADCAST(cvp) INSIST(os_condition_broadcast((cvp)))
#define DEFAULT_DEFAULT_QUANTUM 5
#define FINISHED(m) ((m)->exiting && EMPTY((m)->tasks))
#ifdef DEBUGTRACE
#define XTRACE(m) printf("%s %p\n", (m), pthread_self())
#define XTRACE(m) printf("%s %p\n", (m), os_thread_self())
#else
#define XTRACE(m)
#endif
/***
*** Tasks.
*** Types.
***/
generic_event_t
event_get(mem_context_t mctx, event_type_t type, event_action_t action,
size_t size) {
generic_event_t event;
if (size < sizeof *event)
return (NULL);
if (type < 0)
return (NULL);
if (action == NULL)
return (NULL);
event = mem_get(mctx, size);
if (event == NULL)
return (NULL);
event->mctx = mctx;
event->size = size;
event->type = type;
event->action = action;
return (event);
}
void
event_put(generic_event_t *eventp) {
generic_event_t event;
REQUIRE(eventp != NULL);
event = *eventp;
REQUIRE(event != NULL);
mem_put(event->mctx, event, event->size);
*eventp = NULL;
}
typedef enum {
task_state_idle, task_state_ready, task_state_running,
task_state_shutdown
} task_state_t;
#define TASK_MAGIC 0x5441534BU /* TASK. */
#define VALID_TASK(t) ((t) != NULL && \
(t)->magic == TASK_MAGIC)
struct task {
/* Not locked. */
unsigned int magic;
task_manager_t manager;
os_mutex_t lock;
/* Locked by task lock. */
task_state_t state;
unsigned int references;
task_eventlist_t events;
unsigned int quantum;
boolean_t shutdown_pending;
task_action_t shutdown_action;
void * arg;
/* Locked by task manager lock. */
LINK(struct task) link;
LINK(struct task) ready_link;
};
#define TASK_MANAGER_MAGIC 0x54534B4DU /* TSKM. */
#define VALID_MANAGER(m) ((m) != NULL && \
(m)->magic == TASK_MANAGER_MAGIC)
struct task_manager {
/* Not locked. */
unsigned int magic;
mem_context_t mctx;
os_mutex_t lock;
/* Locked by task manager lock. */
unsigned int default_quantum;
LIST(struct task) tasks;
LIST(struct task) ready_tasks;
os_condition_t work_available;
boolean_t exiting;
unsigned int workers;
os_condition_t no_workers;
};
#define DEFAULT_DEFAULT_QUANTUM 5
#define FINISHED(m) ((m)->exiting && EMPTY((m)->tasks))
/***
*** Tasks.
......@@ -104,7 +113,7 @@ task_free(task_t task) {
boolean_t
task_create(task_manager_t manager, void *arg,
event_action_t shutdown_action, unsigned int quantum,
task_action_t shutdown_action, unsigned int quantum,
task_t *taskp)
{
task_t task;
......@@ -186,10 +195,10 @@ task_detach(task_t *taskp) {
}
boolean_t
task_send_event(task_t task, generic_event_t *eventp) {
task_send_event(task_t task, task_event_t *eventp) {
boolean_t was_idle = FALSE;
boolean_t discard = FALSE;
generic_event_t event;
task_event_t event;
REQUIRE(VALID_TASK(task));
REQUIRE(eventp != NULL);
......@@ -217,7 +226,7 @@ task_send_event(task_t task, generic_event_t *eventp) {
UNLOCK(&task->lock);
if (discard) {
event_put(&event);
task_event_free(&event);
*eventp = NULL;
return (TRUE);
}
......@@ -412,9 +421,9 @@ void *task_manager_run(void *uap) {
boolean_t wants_shutdown;
boolean_t free_task = FALSE;
void *arg;
event_action_t action;
generic_event_t event;
event_list_t remaining_events;
task_action_t action;
task_event_t event;
task_eventlist_t remaining_events;
boolean_t discard_remaining = FALSE;
INSIST(VALID_TASK(task));
......@@ -466,7 +475,7 @@ void *task_manager_run(void *uap) {
* callback returned.
*/
if (event != NULL)
event_put(&event);
task_event_free(&event);
else
wants_shutdown = TRUE;
......@@ -522,13 +531,13 @@ void *task_manager_run(void *uap) {
UNLOCK(&task->lock);
if (discard_remaining) {
generic_event_t next_event;
task_event_t next_event;
for (event = HEAD(remaining_events);
event != NULL;
event = next_event) {
next_event = NEXT(event, link);
event_put(&event);
task_event_free(&event);
}
}
......@@ -714,3 +723,45 @@ task_manager_destroy(task_manager_t *managerp) {
*managerp = NULL;
}
/***
*** Events.
***/
task_event_t
task_event_allocate(mem_context_t mctx, task_eventtype_t type,
task_action_t action, void *arg, size_t size)
{
task_event_t event;
if (size < sizeof *event)
return (NULL);
if (type < 0)
return (NULL);
if (action == NULL)
return (NULL);
event = mem_get(mctx, size);
if (event == NULL)
return (NULL);
event->mctx = mctx;
event->size = size;
event->type = type;
event->action = action;
event->arg = arg;
return (event);
}
void
task_event_free(task_event_t *eventp) {
task_event_t event;
REQUIRE(eventp != NULL);
event = *eventp;
REQUIRE(event != NULL);
mem_put(event->mctx, event, event->size);
*eventp = NULL;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment