task.c revision 3f8744a28fd2cd21b058a3a32622911ef9aa8039
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews/*
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * Copyright (C) 1998, 1999 Internet Software Consortium.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews *
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * Permission to use, copy, modify, and distribute this software for any
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * purpose with or without fee is hereby granted, provided that the above
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * copyright notice and this permission notice appear in all copies.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews *
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * SOFTWARE.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews */
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews/*
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * Principal Author: Bob Halley
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews */
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews/*
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * XXXRTH Need to document the states a task can be in, and the rules
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * for changing states.
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews */
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews#include <config.h>
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews#include <isc/assertions.h>
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews#include <isc/boolean.h>
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews#include <isc/thread.h>
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews#include <isc/mutex.h>
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews#include <isc/condition.h>
09f22ac5b09e70bc526015f37168ba33e21ea91fDavid Lawrence#include <isc/error.h>
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews#include <isc/event.h>
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews#include <isc/task.h>
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews#include "util.h"
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews#ifdef ISC_TASK_TRACE
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews#define XTRACE(m) printf("%s task %p thread %lu\n", (m), \
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews task, isc_thread_self())
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews#define XTHREADTRACE(m) printf("%s thread %lu\n", (m), \
ac4e7a61a8dfc490d82b2fa0d24473953f7b4817Mark Andrews isc_thread_self())
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews#else
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews#define XTRACE(m)
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews#define XTHREADTRACE(m)
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews#endif
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews/***
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews *** Types.
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews ***/
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewstypedef enum {
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews task_state_idle, task_state_ready, task_state_running,
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews task_state_done
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews} task_state_t;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews#define TASK_MAGIC 0x5441534BU /* TASK. */
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews#define VALID_TASK(t) ((t) != NULL && \
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews (t)->magic == TASK_MAGIC)
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsstruct isc_task {
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews /* Not locked. */
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews unsigned int magic;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews isc_taskmgr_t * manager;
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews isc_mutex_t lock;
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews isc_mem_t * mctx;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews /* Locked by task lock. */
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews task_state_t state;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews unsigned int references;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews isc_eventlist_t events;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_eventlist_t on_shutdown;
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews unsigned int quantum;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews unsigned int flags;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews /* Locked by task manager lock. */
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews LINK(isc_task_t) link;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews LINK(isc_task_t) ready_link;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews};
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews#define TASK_F_DONEOK 0x01
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews#define TASK_F_SENDOK 0x02
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews#define TASK_F_SHUTTINGDOWN 0x04
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews#define DONE_FLAGS (TASK_F_DONEOK|TASK_F_SHUTTINGDOWN)
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews#define TASK_DONE(t) (((t)->flags & DONE_FLAGS) == \
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews DONE_FLAGS)
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews#define TASK_MANAGER_MAGIC 0x54534B4DU /* TSKM. */
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews#define VALID_MANAGER(m) ((m) != NULL && \
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews (m)->magic == TASK_MANAGER_MAGIC)
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsstruct isc_taskmgr {
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews /* Not locked. */
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews unsigned int magic;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews isc_mem_t * mctx;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews isc_mutex_t lock;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews unsigned int workers;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_thread_t * threads;
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews /* Locked by task manager lock. */
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews unsigned int default_quantum;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews LIST(isc_task_t) tasks;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews LIST(isc_task_t) ready_tasks;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_condition_t work_available;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_boolean_t exiting;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews};
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews#define DEFAULT_DEFAULT_QUANTUM 5
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews#define FINISHED(m) ((m)->exiting && EMPTY((m)->tasks))
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews/***
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews *** Tasks.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews ***/
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsstatic void
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewstask_free(isc_task_t *task) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_taskmgr_t *manager = task->manager;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews XTRACE("free task");
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews REQUIRE(EMPTY(task->events));
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews REQUIRE(EMPTY(task->on_shutdown));
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews LOCK(&manager->lock);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews UNLINK(manager->tasks, task, link);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews if (FINISHED(manager)) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews /*
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews * All tasks have completed and the
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * task manager is exiting. Wake up
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * any idle worker threads so they
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * can exit.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews */
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews BROADCAST(&manager->work_available);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews }
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews UNLOCK(&manager->lock);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews (void)isc_mutex_destroy(&task->lock);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews task->magic = 0;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews isc_mem_put(task->mctx, task, sizeof *task);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews}
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsisc_result_t
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsisc_task_create(isc_taskmgr_t *manager, isc_mem_t *mctx, unsigned int quantum,
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews isc_task_t **taskp)
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews{
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews isc_task_t *task;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews REQUIRE(VALID_MANAGER(manager));
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews REQUIRE(taskp != NULL && *taskp == NULL);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews if (mctx == NULL)
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews mctx = manager->mctx;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews task = isc_mem_get(mctx, sizeof *task);
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews if (task == NULL)
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews return (ISC_R_NOMEMORY);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff task->manager = manager;
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews task->mctx = mctx;
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews if (isc_mutex_init(&task->lock) != ISC_R_SUCCESS) {
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews isc_mem_put(mctx, task, sizeof *task);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews UNEXPECTED_ERROR(__FILE__, __LINE__,
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews "isc_mutex_init() failed");
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews return (ISC_R_UNEXPECTED);
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews }
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews task->state = task_state_idle;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews task->references = 1;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews INIT_LIST(task->events);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews INIT_LIST(task->on_shutdown);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews task->quantum = quantum;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews task->flags = (TASK_F_DONEOK|TASK_F_SENDOK);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews INIT_LINK(task, link);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews INIT_LINK(task, ready_link);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews LOCK(&manager->lock);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews /* XXX Should disallow if task manager is exiting. */
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews if (task->quantum == 0)
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews task->quantum = manager->default_quantum;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews APPEND(manager->tasks, task, link);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews UNLOCK(&manager->lock);
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews task->magic = TASK_MAGIC;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews *taskp = task;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews return (ISC_R_SUCCESS);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews}
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsvoid
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsisc_task_attach(isc_task_t *source, isc_task_t **targetp) {
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews /*
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * Attach *targetp to source.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews */
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews REQUIRE(VALID_TASK(source));
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews REQUIRE(targetp != NULL && *targetp == NULL);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews LOCK(&source->lock);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews source->references++;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews UNLOCK(&source->lock);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews *targetp = source;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews}
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsvoid
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsisc_task_detach(isc_task_t **taskp) {
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews isc_boolean_t free_task = ISC_FALSE;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews isc_task_t *task;
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews /*
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * Detach *taskp from its task.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews */
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff REQUIRE(taskp != NULL);
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff task = *taskp;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews REQUIRE(VALID_TASK(task));
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews XTRACE("isc_task_detach");
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews LOCK(&task->lock);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews REQUIRE(task->references > 0);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews task->references--;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews if (task->state == task_state_done && task->references == 0)
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews free_task = ISC_TRUE;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews /*
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * XXXRTH It is currently possible to detach the last
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * reference from a task that has not been shutdown. This
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * will prevent the task from being shutdown until the
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * task manager is destroyed. Should there be an
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * automatic shutdown on last detach?
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews */
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews UNLOCK(&task->lock);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (free_task)
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews task_free(task);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews *taskp = NULL;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews}
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsisc_mem_t *
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsisc_task_mem(isc_task_t *task) {
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews /*
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * Get the task's memory context.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews */
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews REQUIRE(VALID_TASK(task));
4be19dcd14cea678511f1d1b269ab89273e987eeMark Andrews
4be19dcd14cea678511f1d1b269ab89273e987eeMark Andrews return (task->mctx);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews}
4be19dcd14cea678511f1d1b269ab89273e987eeMark Andrews
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrewsisc_result_t
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrewsisc_task_send(isc_task_t *task, isc_event_t **eventp) {
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews isc_boolean_t was_idle = ISC_FALSE;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews isc_boolean_t disallowed = ISC_FALSE;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews isc_result_t result = ISC_R_SUCCESS;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews isc_event_t *event;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews /*
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * Send '*event' to 'task'.
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews */
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews REQUIRE(VALID_TASK(task));
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews REQUIRE(eventp != NULL);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews event = *eventp;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews REQUIRE(event != NULL);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews REQUIRE(event->sender != NULL);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews REQUIRE(event->type > 0);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews XTRACE("sending");
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews /*
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * We're trying hard to hold locks for as short a time as possible.
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * We're also trying to hold as few locks as possible. This is why
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * some processing is deferred until after a lock is released.
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews */
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews LOCK(&task->lock);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews /*
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * Note: we require that task->state == task_state_done implies
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * (task->flags & TASK_F_SENDOK) == 0.
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews */
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews if ((task->flags & TASK_F_SENDOK) != 0) {
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews if (task->state == task_state_idle) {
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews was_idle = ISC_TRUE;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews INSIST(EMPTY(task->events));
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews task->state = task_state_ready;
4be19dcd14cea678511f1d1b269ab89273e987eeMark Andrews }
4be19dcd14cea678511f1d1b269ab89273e987eeMark Andrews INSIST(task->state == task_state_ready ||
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews task->state == task_state_running);
4be19dcd14cea678511f1d1b269ab89273e987eeMark Andrews ENQUEUE(task->events, event, link);
4be19dcd14cea678511f1d1b269ab89273e987eeMark Andrews } else {
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews disallowed = ISC_TRUE;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews if (task->state == task_state_done)
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews result = ISC_R_TASKDONE;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews else
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews result = ISC_R_TASKNOSEND;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews }
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews UNLOCK(&task->lock);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews if (disallowed)
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews return (result);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews if (was_idle) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_taskmgr_t *manager;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews /*
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * We need to add this task to the ready queue.
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews *
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * We've waited until now to do it, rather than doing it
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * while holding the task lock, because we don't want to
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * block while holding the task lock.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews *
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * We've changed the state to ready, so no one else will
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * be trying to add this task to the ready queue. The
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * only way to leave the ready state is by executing the
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * task. It thus doesn't matter if events are added,
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * removed, or shutting_down is started in the interval
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * between the time we released the task lock, and the time
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * we add the task to the ready queue.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews */
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews manager = task->manager;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews INSIST(VALID_MANAGER(manager));
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews LOCK(&manager->lock);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews ENQUEUE(manager->ready_tasks, task, ready_link);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews SIGNAL(&manager->work_available);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews UNLOCK(&manager->lock);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews }
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews *eventp = NULL;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews XTRACE("sent");
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews return (ISC_R_SUCCESS);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews}
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsunsigned int
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsisc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first,
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews isc_eventtype_t last)
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews{
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews isc_event_t *event, *next_event;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews isc_eventlist_t purgeable;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews unsigned int purge_count;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews /*
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * Purge events from a task's event queue.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews */
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews REQUIRE(VALID_TASK(task));
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews REQUIRE(last >= first);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews /*
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff * Events matching 'sender' and whose type is >= first and
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff * <= last will be purged, unless they are marked as unpurgable.
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff * sender == NULL means "any sender".
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff *
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * Purging never changes the state of the task.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews */
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews INIT_LIST(purgeable);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews purge_count = 0;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews LOCK(&task->lock);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews for (event = HEAD(task->events);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews event != NULL;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews event = next_event) {
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews next_event = NEXT(event, link);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews if ((sender == NULL || event->sender == sender) &&
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews event->type >= first &&
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews event->type <= last &&
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews (event->attributes & ISC_EVENTATTR_NOPURGE) == 0) {
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews DEQUEUE(task->events, event, link);
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews ENQUEUE(purgeable, event, link);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews }
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews }
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews UNLOCK(&task->lock);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews for (event = HEAD(purgeable);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews event != NULL;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews event = next_event) {
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews next_event = NEXT(event, link);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews isc_event_free(&event);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews purge_count++;
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews }
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews return (purge_count);
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews}
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrewsunsigned int
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrewsisc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type) {
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews /*
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews * Purge events from a task's event queue.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews */
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews return (isc_task_purgerange(task, sender, type, type));
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews}
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrewsisc_result_t
390b2077fc751105e40174ceaa1ce34ef06e7dd4Mark Andrewsisc_task_allowsend(isc_task_t *task, isc_boolean_t allowed) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_result_t result = ISC_R_SUCCESS;
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews /*
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * Allow or disallow sending events to 'task'.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews */
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews REQUIRE(VALID_TASK(task));
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews LOCK(&task->lock);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews if (task->state == task_state_done)
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews result = ISC_R_TASKDONE;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews else {
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews if (allowed)
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews task->flags |= TASK_F_SENDOK;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews else
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews task->flags &= ~TASK_F_SENDOK;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews }
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews UNLOCK(&task->lock);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews return (result);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews}
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsisc_result_t
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsisc_task_allowdone(isc_task_t *task, isc_boolean_t allowed) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_result_t result = ISC_R_SUCCESS;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews /*
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * Allow or disallow automatic termination of 'task'.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews */
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews REQUIRE(VALID_TASK(task));
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews LOCK(&task->lock);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews if (task->state == task_state_done)
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews result = ISC_R_TASKDONE;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews else if (allowed &&
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews (task->flags & TASK_F_SHUTTINGDOWN) != 0 &&
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews task->state == task_state_idle) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews task->flags &= ~TASK_F_SENDOK;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews task->state = task_state_done;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews } else {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (allowed)
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews task->flags |= TASK_F_DONEOK;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews else
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews task->flags &= ~TASK_F_DONEOK;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews }
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews UNLOCK(&task->lock);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews return (result);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews}
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsisc_result_t
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrewsisc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, void *arg) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_boolean_t disallowed = ISC_FALSE;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_result_t result = ISC_R_SUCCESS;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_event_t *event;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews /*
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * Send a shutdown event with action 'action' and argument 'arg' when
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * 'task' is shutdown.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews */
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews REQUIRE(VALID_TASK(task));
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews REQUIRE(action != NULL);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews event = isc_event_allocate(task->mctx,
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews NULL,
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews ISC_TASKEVENT_SHUTDOWN,
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews action,
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews arg,
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff sizeof *event);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (event == NULL)
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews return (ISC_R_NOMEMORY);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews LOCK(&task->lock);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (task->state == task_state_done) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews disallowed = ISC_TRUE;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews result = ISC_R_TASKDONE;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews } else if ((task->flags & TASK_F_SHUTTINGDOWN) != 0) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews disallowed = ISC_TRUE;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews result = ISC_R_TASKSHUTTINGDOWN;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews } else
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews ENQUEUE(task->on_shutdown, event, link);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews UNLOCK(&task->lock);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews if (disallowed)
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_mem_put(task->mctx, event, sizeof *event);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews return (result);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews}
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsvoid
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrewsisc_task_shutdown(isc_task_t *task) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_boolean_t was_idle = ISC_FALSE;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_boolean_t queued_something = ISC_FALSE;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_event_t *event, *prev;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews /*
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * Shutdown 'task'.
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews */
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews REQUIRE(VALID_TASK(task));
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews /*
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * This routine is very similar to isc_task_send() above.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews */
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews LOCK(&task->lock);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews if ((task->flags & TASK_F_SHUTTINGDOWN) == 0) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews XTRACE("shutting down");
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews task->flags |= TASK_F_SHUTTINGDOWN;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (task->state == task_state_idle) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews was_idle = ISC_TRUE;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews INSIST(EMPTY(task->events));
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (EMPTY(task->on_shutdown) && TASK_DONE(task)) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews task->flags &= ~TASK_F_SENDOK;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews task->state = task_state_done;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews } else
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews task->state = task_state_ready;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews }
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews INSIST(task->state == task_state_ready ||
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews task->state == task_state_running ||
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews task->state == task_state_done);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (task->state != task_state_done) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews /*
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * Note that we post shutdown events LIFO.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews */
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews for (event = TAIL(task->on_shutdown);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews event != NULL;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews event = prev) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews prev = PREV(event, link);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews DEQUEUE(task->on_shutdown, event, link);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews ENQUEUE(task->events, event, link);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews queued_something = ISC_TRUE;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews }
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews }
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews }
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews UNLOCK(&task->lock);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (was_idle && queued_something) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_taskmgr_t *manager;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews manager = task->manager;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews INSIST(VALID_MANAGER(manager));
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews LOCK(&manager->lock);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews ENQUEUE(manager->ready_tasks, task, ready_link);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews SIGNAL(&manager->work_available);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews UNLOCK(&manager->lock);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews }
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews}
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsvoid
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsisc_task_destroy(isc_task_t **taskp) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews /*
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * Destroy '*taskp'.
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews */
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews REQUIRE(taskp != NULL);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_task_shutdown(*taskp);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews isc_task_detach(taskp);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews}
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews/***
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews *** Task Manager.
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews ***/
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrewsstatic isc_threadresult_t
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews#ifdef _WIN32
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark AndrewsWINAPI
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews#endif
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrewsrun(void *uap) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_taskmgr_t *manager = uap;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_task_t *task;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews XTHREADTRACE("start");
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews REQUIRE(VALID_MANAGER(manager));
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews /*
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * Again we're trying to hold the lock for as short a time as possible
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * and to do as little locking and unlocking as possible.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews *
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * In both while loops, the appropriate lock must be held before the
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * while body starts. Code which acquired the lock at the top of
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * the loop would be more readable, but would result in a lot of
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * extra locking. Compare:
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews *
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * Straightforward:
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews *
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * LOCK();
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * ...
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * UNLOCK();
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * while (expression) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * LOCK();
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * ...
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * UNLOCK();
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews *
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * Unlocked part here...
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews *
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * LOCK();
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * ...
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * UNLOCK();
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * }
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews *
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence * Note how if the loop continues we unlock and then immediately lock.
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * For N iterations of the loop, this code does 2N+1 locks and 2N+1
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * unlocks. Also note that the lock is not held when the while
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * condition is tested, which may or may not be important, depending
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * on the expression.
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews *
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * As written:
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews *
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * LOCK();
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * while (expression) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * ...
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * UNLOCK();
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews *
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * Unlocked part here...
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff *
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * LOCK();
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * ...
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * }
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * UNLOCK();
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews *
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * For N iterations of the loop, this code does N+1 locks and N+1
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * unlocks. The while expression is always protected by the lock.
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews */
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews LOCK(&manager->lock);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews while (!FINISHED(manager)) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews /*
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * For reasons similar to those given in the comment in
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * isc_task_send() above, it is safe for us to dequeue
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence * the task while only holding the manager lock, and then
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * change the task to running state while only holding the
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence * task lock.
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews */
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews while (EMPTY(manager->ready_tasks) && !FINISHED(manager)) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews XTHREADTRACE("wait");
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews WAIT(&manager->work_available, &manager->lock);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews XTHREADTRACE("awake");
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews }
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews XTHREADTRACE("working");
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews task = HEAD(manager->ready_tasks);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews if (task != NULL) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews unsigned int dispatch_count = 0;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_boolean_t done = ISC_FALSE;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_boolean_t requeue = ISC_FALSE;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_boolean_t free_task = ISC_FALSE;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_event_t *event;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews INSIST(VALID_TASK(task));
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews /*
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * Note we only unlock the manager lock if we actually
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * have a task to do. We must reacquire the manager
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * lock before exiting the 'if (task != NULL)' block.
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews */
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews DEQUEUE(manager->ready_tasks, task, ready_link);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews UNLOCK(&manager->lock);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews LOCK(&task->lock);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews INSIST(task->state == task_state_ready);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews if (EMPTY(task->events)) {
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews /*
390b2077fc751105e40174ceaa1ce34ef06e7dd4Mark Andrews * The task became runnable, but all events
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * in the run queue were subsequently purged.
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews * Put the task to sleep.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews */
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews task->state = task_state_idle;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews done = ISC_TRUE;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews XTRACE("ready but empty");
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews } else
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews task->state = task_state_running;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews while (!done) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews INSIST(!EMPTY(task->events));
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews event = HEAD(task->events);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews DEQUEUE(task->events, event, link);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews /*
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * Execute the event action.
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews */
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews XTRACE("execute action");
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews if (event->action != NULL) {
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews UNLOCK(&task->lock);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews (event->action)(task, event);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews LOCK(&task->lock);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews }
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews dispatch_count++;
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (EMPTY(task->events)) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews /*
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * Nothing else to do for this task
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * right now. If it is shutting down,
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * then it is done, otherwise we just
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * put it to sleep.
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews */
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews XTRACE("empty");
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (TASK_DONE(task)) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews XTRACE("done");
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (task->references == 0)
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews free_task = ISC_TRUE;
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews task->flags &=
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews ~TASK_F_SENDOK;
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews task->state = task_state_done;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews } else
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews task->state = task_state_idle;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews done = ISC_TRUE;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews } else if (dispatch_count >= task->quantum) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews /*
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * Our quantum has expired, but
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * there is more work to be done.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * We'll requeue it to the ready
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * queue later.
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews *
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * We don't check quantum until
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * dispatching at least one event,
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * so the minimum quantum is one.
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff */
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews XTRACE("quantum");
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff task->state = task_state_ready;
390b2077fc751105e40174ceaa1ce34ef06e7dd4Mark Andrews requeue = ISC_TRUE;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews done = ISC_TRUE;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews }
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews }
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews UNLOCK(&task->lock);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (free_task)
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews task_free(task);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews LOCK(&manager->lock);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (requeue) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews /*
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * We know we're awake, so we don't have
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * to wakeup any sleeping threads if the
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * ready queue is empty before we requeue.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews *
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * A possible optimization if the queue is
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * empty is to 'goto' the 'if (task != NULL)'
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * block, avoiding the ENQUEUE of the task
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * and the subsequent immediate DEQUEUE
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * (since it is the only executable task).
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * We don't do this because then we'd be
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * skipping the exit_requested check. The
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff * cost of ENQUEUE is low anyway, especially
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * when you consider that we'd have to do
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff * an extra EMPTY check to see if we could
390b2077fc751105e40174ceaa1ce34ef06e7dd4Mark Andrews * do the optimization. If the ready queue
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * were usually nonempty, the 'optimization'
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * might even hurt rather than help.
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews */
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews ENQUEUE(manager->ready_tasks, task,
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews ready_link);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews }
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews }
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews }
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews UNLOCK(&manager->lock);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews XTHREADTRACE("exit");
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews return ((isc_threadresult_t)0);
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff}
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsstatic void
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrewsmanager_free(isc_taskmgr_t *manager) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews (void)isc_condition_destroy(&manager->work_available);
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff (void)isc_mutex_destroy(&manager->lock);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_mem_put(manager->mctx, manager->threads,
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews manager->workers * sizeof (isc_thread_t));
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews manager->magic = 0;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews isc_mem_put(manager->mctx, manager, sizeof *manager);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews}
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsisc_result_t
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsisc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews unsigned int default_quantum, isc_taskmgr_t **managerp)
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews{
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews unsigned int i, started = 0;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_taskmgr_t *manager;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_thread_t *threads;
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence /*
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence * Create a new task manager.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews */
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews REQUIRE(workers > 0);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews REQUIRE(managerp != NULL && *managerp == NULL);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews manager = isc_mem_get(mctx, sizeof *manager);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (manager == NULL)
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews return (ISC_R_NOMEMORY);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews manager->magic = TASK_MANAGER_MAGIC;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews manager->mctx = mctx;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews threads = isc_mem_get(mctx, workers * sizeof (isc_thread_t));
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (threads == NULL) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_mem_put(mctx, manager, sizeof *manager);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews return (ISC_R_NOMEMORY);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews }
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews manager->threads = threads;
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews manager->workers = 0;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews if (isc_mutex_init(&manager->lock) != ISC_R_SUCCESS) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_mem_put(mctx, threads, workers * sizeof (isc_thread_t));
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_mem_put(mctx, manager, sizeof *manager);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews UNEXPECTED_ERROR(__FILE__, __LINE__,
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff "isc_mutex_init() failed");
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews return (ISC_R_UNEXPECTED);
390b2077fc751105e40174ceaa1ce34ef06e7dd4Mark Andrews }
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews if (default_quantum == 0)
4be19dcd14cea678511f1d1b269ab89273e987eeMark Andrews default_quantum = DEFAULT_DEFAULT_QUANTUM;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews manager->default_quantum = default_quantum;
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews INIT_LIST(manager->tasks);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews INIT_LIST(manager->ready_tasks);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (isc_condition_init(&manager->work_available) != ISC_R_SUCCESS) {
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews (void)isc_mutex_destroy(&manager->lock);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_mem_put(mctx, threads, workers * sizeof (isc_thread_t));
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_mem_put(mctx, manager, sizeof *manager);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews UNEXPECTED_ERROR(__FILE__, __LINE__,
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews "isc_condition_init() failed");
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews return (ISC_R_UNEXPECTED);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews }
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews manager->exiting = ISC_FALSE;
390b2077fc751105e40174ceaa1ce34ef06e7dd4Mark Andrews manager->workers = 0;
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews LOCK(&manager->lock);
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews /*
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews * Start workers.
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews */
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff for (i = 0; i < workers; i++) {
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff if (isc_thread_create(run, manager,
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews &manager->threads[manager->workers]) ==
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews ISC_R_SUCCESS) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews manager->workers++;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews started++;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews }
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews }
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews UNLOCK(&manager->lock);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews
390b2077fc751105e40174ceaa1ce34ef06e7dd4Mark Andrews if (started == 0) {
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews manager_free(manager);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews return (ISC_R_NOTHREADS);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews }
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews *managerp = manager;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews return (ISC_R_SUCCESS);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews}
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsvoid
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsisc_taskmgr_destroy(isc_taskmgr_t **managerp) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_taskmgr_t *manager;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_task_t *task;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_event_t *event, *prev;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews unsigned int i;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews /*
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * Destroy '*managerp'.
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews */
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews REQUIRE(managerp != NULL);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews manager = *managerp;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews REQUIRE(VALID_MANAGER(manager));
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews XTHREADTRACE("isc_taskmgr_destroy");
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews /*
390b2077fc751105e40174ceaa1ce34ef06e7dd4Mark Andrews * Only one non-worker thread may ever call this routine.
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * If a worker thread wants to initiate shutdown of the
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * task manager, it should ask some non-worker thread to call
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews * isc_taskmgr_destroy(), e.g. by signalling a condition variable
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews * that the startup thread is sleeping on.
440164d3e36353a4b9801fcc05fe66b6cf1fb8ceMark Andrews */
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews /*
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * Unlike elsewhere, we're going to hold this lock a long time.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * We need to do so, because otherwise the list of tasks could
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * change while we were traversing it.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews *
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * This is also the only function where we will hold both the
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * task manager lock and a task lock at the same time.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews */
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews LOCK(&manager->lock);
a5c30de2601a1d130a15a78cf3dc7610a02b2d85Mark Andrews
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews /*
* Make sure we only get called once.
*/
INSIST(!manager->exiting);
manager->exiting = ISC_TRUE;
/*
* Post shutdown event(s) to every task (if they haven't already been
* posted).
*/
for (task = HEAD(manager->tasks);
task != NULL;
task = NEXT(task, link)) {
LOCK(&task->lock);
if ((task->flags & TASK_F_SHUTTINGDOWN) == 0) {
task->flags |= TASK_F_SHUTTINGDOWN;
if (task->state == task_state_idle) {
INSIST(EMPTY(task->events));
if (EMPTY(task->on_shutdown) &&
TASK_DONE(task)) {
task->flags &= ~TASK_F_SENDOK;
task->state = task_state_done;
} else {
task->state = task_state_ready;
ENQUEUE(manager->ready_tasks, task,
ready_link);
}
}
INSIST(task->state == task_state_ready ||
task->state == task_state_running ||
task->state == task_state_done);
if (task->state != task_state_done) {
/*
* Note that we post shutdown events LIFO.
*/
for (event = TAIL(task->on_shutdown);
event != NULL;
event = prev) {
prev = PREV(event, link);
DEQUEUE(task->on_shutdown, event,
link);
ENQUEUE(task->events, event, link);
}
}
}
UNLOCK(&task->lock);
}
/*
* Wake up any sleeping workers. This ensures we get work done if
* there's work left to do, and if there are already no tasks left
* it will cause the workers to see manager->exiting.
*/
BROADCAST(&manager->work_available);
UNLOCK(&manager->lock);
/*
* Wait for all the worker threads to exit.
*/
for (i = 0; i < manager->workers; i++)
(void)isc_thread_join(manager->threads[i], NULL);
manager_free(manager);
*managerp = NULL;
}