task.c revision 9b8123723a4b38cc8885baf14344396f3edad4cc
1633838b8255282d10af15c5c84cee5a51466712Bob Halley/*
7d32c065c7bb56f281651ae3dd2888f32ce4f1d9Bob Halley * Copyright (C) 1998, 1999 Internet Software Consortium.
1633838b8255282d10af15c5c84cee5a51466712Bob Halley *
1633838b8255282d10af15c5c84cee5a51466712Bob Halley * Permission to use, copy, modify, and distribute this software for any
1633838b8255282d10af15c5c84cee5a51466712Bob Halley * purpose with or without fee is hereby granted, provided that the above
1633838b8255282d10af15c5c84cee5a51466712Bob Halley * copyright notice and this permission notice appear in all copies.
1633838b8255282d10af15c5c84cee5a51466712Bob Halley *
1633838b8255282d10af15c5c84cee5a51466712Bob Halley * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
1633838b8255282d10af15c5c84cee5a51466712Bob Halley * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
1633838b8255282d10af15c5c84cee5a51466712Bob Halley * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
1633838b8255282d10af15c5c84cee5a51466712Bob Halley * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
1633838b8255282d10af15c5c84cee5a51466712Bob Halley * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
1633838b8255282d10af15c5c84cee5a51466712Bob Halley * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
1633838b8255282d10af15c5c84cee5a51466712Bob Halley * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1633838b8255282d10af15c5c84cee5a51466712Bob Halley * SOFTWARE.
1633838b8255282d10af15c5c84cee5a51466712Bob Halley */
d25afd60ee2286cb171c4960a790f3d7041b6f85Bob Halley
d25afd60ee2286cb171c4960a790f3d7041b6f85Bob Halley#include <config.h>
d25afd60ee2286cb171c4960a790f3d7041b6f85Bob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley#include <isc/assertions.h>
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley#include <isc/boolean.h>
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley#include <isc/thread.h>
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley#include <isc/mutex.h>
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley#include <isc/condition.h>
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley#include <isc/error.h>
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley#include <isc/task.h>
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley#include "util.h"
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley#ifdef ISC_TASK_TRACE
9192e92f7d0f4e78385a1d5f9b6607cc5bf0e42aBob Halley#define XTRACE(m) printf("%s task %p thread %lu\n", (m), \
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley task, isc_thread_self())
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley#else
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley#define XTRACE(m)
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley#endif
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley/***
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley *** Types.
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley ***/
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halleytypedef enum {
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley task_state_idle, task_state_ready, task_state_running,
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley task_state_shutdown
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley} task_state_t;
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley#define TASK_MAGIC 0x5441534BU /* TASK. */
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley#define VALID_TASK(t) ((t) != NULL && \
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley (t)->magic == TASK_MAGIC)
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halleystruct isc_task {
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley /* Not locked. */
cee7525336d4710a64368875d92eb439d4d3efb1Mark Andrews unsigned int magic;
cee7525336d4710a64368875d92eb439d4d3efb1Mark Andrews isc_taskmgr_t * manager;
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley isc_mutex_t lock;
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley isc_mem_t * mctx;
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley /* Locked by task lock. */
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley task_state_t state;
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley unsigned int references;
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley isc_eventlist_t events;
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley isc_eventlist_t on_shutdown;
ecb6c5782ea248307e86c4bceac6c371d27576a6David Lawrence unsigned int quantum;
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley isc_boolean_t enqueue_allowed;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_boolean_t shutting_down;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley /* Locked by task manager lock. */
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley LINK(isc_task_t) link;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley LINK(isc_task_t) ready_link;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley};
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley#define TASK_MANAGER_MAGIC 0x54534B4DU /* TSKM. */
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley#define VALID_MANAGER(m) ((m) != NULL && \
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley (m)->magic == TASK_MANAGER_MAGIC)
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halleystruct isc_taskmgr {
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley /* Not locked. */
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley unsigned int magic;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_mem_t * mctx;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_mutex_t lock;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley unsigned int workers;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_thread_t * threads;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley /* Locked by task manager lock. */
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley unsigned int default_quantum;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley LIST(isc_task_t) tasks;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley LIST(isc_task_t) ready_tasks;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_condition_t work_available;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_boolean_t exiting;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley};
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley#define DEFAULT_DEFAULT_QUANTUM 5
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley#define FINISHED(m) ((m)->exiting && EMPTY((m)->tasks))
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley/***
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley *** Events.
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley ***/
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halleystatic inline isc_event_t *
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halleyevent_allocate(isc_mem_t *mctx, void *sender, isc_eventtype_t type,
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_taskaction_t action, void *arg, size_t size)
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley{
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_event_t *event;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley event = isc_mem_get(mctx, size);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley if (event == NULL)
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley return (NULL);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley event->mctx = mctx;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley event->size = size;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley event->sender = sender;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley event->type = type;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley event->action = action;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley event->arg = arg;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley event->destroy = NULL;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley INIT_LINK(event, link);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley return (event);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley}
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halleyisc_event_t *
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halleyisc_event_allocate(isc_mem_t *mctx, void *sender, isc_eventtype_t type,
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_taskaction_t action, void *arg, size_t size)
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley{
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley if (size < sizeof (struct isc_event))
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley return (NULL);
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley if (type < 0)
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley return (NULL);
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley if (action == NULL)
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley return (NULL);
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley return (event_allocate(mctx, sender, type, action, arg, size));
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley}
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halleyvoid
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halleyisc_event_free(isc_event_t **eventp) {
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley isc_event_t *event;
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley REQUIRE(eventp != NULL);
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley event = *eventp;
c5839c39bd07c9dd3d4cd598035deb0537098475Bob Halley REQUIRE(event != NULL);
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley if (event->destroy != NULL)
70fdfcd1fa7ebd059deffa9a2cecc29df96dfe52Bob Halley (event->destroy)(event);
70fdfcd1fa7ebd059deffa9a2cecc29df96dfe52Bob Halley isc_mem_put(event->mctx, event, event->size);
70fdfcd1fa7ebd059deffa9a2cecc29df96dfe52Bob Halley
70fdfcd1fa7ebd059deffa9a2cecc29df96dfe52Bob Halley *eventp = NULL;
70fdfcd1fa7ebd059deffa9a2cecc29df96dfe52Bob Halley}
70fdfcd1fa7ebd059deffa9a2cecc29df96dfe52Bob Halley
70fdfcd1fa7ebd059deffa9a2cecc29df96dfe52Bob Halley/***
70fdfcd1fa7ebd059deffa9a2cecc29df96dfe52Bob Halley *** Tasks.
70fdfcd1fa7ebd059deffa9a2cecc29df96dfe52Bob Halley ***/
70fdfcd1fa7ebd059deffa9a2cecc29df96dfe52Bob Halley
70fdfcd1fa7ebd059deffa9a2cecc29df96dfe52Bob Halleystatic void
70fdfcd1fa7ebd059deffa9a2cecc29df96dfe52Bob Halleytask_free(isc_task_t *task) {
08c8a934ceb2dfc6a5ebfd3be4ba5a1b3243bc73Bob Halley isc_taskmgr_t *manager = task->manager;
08c8a934ceb2dfc6a5ebfd3be4ba5a1b3243bc73Bob Halley
08c8a934ceb2dfc6a5ebfd3be4ba5a1b3243bc73Bob Halley XTRACE("free task");
08c8a934ceb2dfc6a5ebfd3be4ba5a1b3243bc73Bob Halley REQUIRE(EMPTY(task->events));
08c8a934ceb2dfc6a5ebfd3be4ba5a1b3243bc73Bob Halley REQUIRE(EMPTY(task->on_shutdown));
08c8a934ceb2dfc6a5ebfd3be4ba5a1b3243bc73Bob Halley
08c8a934ceb2dfc6a5ebfd3be4ba5a1b3243bc73Bob Halley LOCK(&manager->lock);
08c8a934ceb2dfc6a5ebfd3be4ba5a1b3243bc73Bob Halley UNLINK(manager->tasks, task, link);
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley if (FINISHED(manager)) {
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley /*
95f78a208ad6dfb8359320c77ab30c670c773922Mark Andrews * All tasks have completed and the
95f78a208ad6dfb8359320c77ab30c670c773922Mark Andrews * task manager is exiting. Wake up
95f78a208ad6dfb8359320c77ab30c670c773922Mark Andrews * any idle worker threads so they
8db3b065b4659f593f7b8eaa7c9ca0c3daa4da02Bob Halley * can exit.
8db3b065b4659f593f7b8eaa7c9ca0c3daa4da02Bob Halley */
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley BROADCAST(&manager->work_available);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley }
3740b569ae76295b941d57a724a43beb75b533baBob Halley UNLOCK(&manager->lock);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley (void)isc_mutex_destroy(&task->lock);
5f120ce962b03e4dcf6f1974b9b896f0fa7cacb0Bob Halley task->magic = 0;
5f120ce962b03e4dcf6f1974b9b896f0fa7cacb0Bob Halley isc_mem_put(task->mctx, task, sizeof *task);
5f120ce962b03e4dcf6f1974b9b896f0fa7cacb0Bob Halley}
5f120ce962b03e4dcf6f1974b9b896f0fa7cacb0Bob Halley
5f120ce962b03e4dcf6f1974b9b896f0fa7cacb0Bob Halleyisc_result_t
5f120ce962b03e4dcf6f1974b9b896f0fa7cacb0Bob Halleyisc_task_create(isc_taskmgr_t *manager, isc_mem_t *mctx, unsigned int quantum,
5f120ce962b03e4dcf6f1974b9b896f0fa7cacb0Bob Halley isc_task_t **taskp)
5f120ce962b03e4dcf6f1974b9b896f0fa7cacb0Bob Halley{
5f120ce962b03e4dcf6f1974b9b896f0fa7cacb0Bob Halley isc_task_t *task;
5f120ce962b03e4dcf6f1974b9b896f0fa7cacb0Bob Halley
5f120ce962b03e4dcf6f1974b9b896f0fa7cacb0Bob Halley REQUIRE(VALID_MANAGER(manager));
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley REQUIRE(taskp != NULL && *taskp == NULL);
c5839c39bd07c9dd3d4cd598035deb0537098475Bob Halley
c5839c39bd07c9dd3d4cd598035deb0537098475Bob Halley if (mctx == NULL)
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley mctx = manager->mctx;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley task = isc_mem_get(mctx, sizeof *task);
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley if (task == NULL)
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley return (ISC_R_NOMEMORY);
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley task->manager = manager;
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley task->mctx = mctx;
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley if (isc_mutex_init(&task->lock) != ISC_R_SUCCESS) {
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley isc_mem_put(mctx, task, sizeof *task);
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley UNEXPECTED_ERROR(__FILE__, __LINE__,
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley "isc_mutex_init() failed");
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley return (ISC_R_UNEXPECTED);
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley }
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley task->state = task_state_idle;
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley task->references = 1;
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley INIT_LIST(task->events);
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley INIT_LIST(task->on_shutdown);
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley task->quantum = quantum;
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley task->enqueue_allowed = ISC_TRUE;
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley task->shutting_down = ISC_FALSE;
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley INIT_LINK(task, link);
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley INIT_LINK(task, ready_link);
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley LOCK(&manager->lock);
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley /* XXX Should disallow if task manager is exiting. */
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley if (task->quantum == 0)
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley task->quantum = manager->default_quantum;
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley APPEND(manager->tasks, task, link);
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley UNLOCK(&manager->lock);
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley
577179503f2eb7695ec668d8eeb41889a150e28fBob Halley task->magic = TASK_MAGIC;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley *taskp = task;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
3740b569ae76295b941d57a724a43beb75b533baBob Halley return (ISC_R_SUCCESS);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley}
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halleyvoid
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halleyisc_task_attach(isc_task_t *task, isc_task_t **taskp) {
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley REQUIRE(VALID_TASK(task));
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley REQUIRE(taskp != NULL && *taskp == NULL);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley LOCK(&task->lock);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley task->references++;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley UNLOCK(&task->lock);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley *taskp = task;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley}
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halleyvoid
3740b569ae76295b941d57a724a43beb75b533baBob Halleyisc_task_detach(isc_task_t **taskp) {
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_boolean_t free_task = ISC_FALSE;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_task_t *task;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley XTRACE("isc_task_detach");
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley REQUIRE(taskp != NULL);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley task = *taskp;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley REQUIRE(VALID_TASK(task));
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley LOCK(&task->lock);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley REQUIRE(task->references > 0);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley task->references--;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley if (task->state == task_state_shutdown && task->references == 0)
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley free_task = ISC_TRUE;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley UNLOCK(&task->lock);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley if (free_task)
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley task_free(task);
3740b569ae76295b941d57a724a43beb75b533baBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley *taskp = NULL;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley}
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halleyisc_mem_t *
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halleyisc_task_mem(isc_task_t *task) {
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley REQUIRE(VALID_TASK(task));
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley return (task->mctx);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley}
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halleyisc_result_t
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halleyisc_task_send(isc_task_t *task, isc_event_t **eventp) {
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_boolean_t was_idle = ISC_FALSE;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_boolean_t disallowed = ISC_FALSE;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_result_t result = ISC_R_SUCCESS;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_event_t *event;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley REQUIRE(VALID_TASK(task));
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley REQUIRE(eventp != NULL);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley event = *eventp;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley REQUIRE(event != NULL);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley REQUIRE(event->sender != NULL);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley REQUIRE(event->type > 0);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley XTRACE("sending");
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley /*
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * We're trying hard to hold locks for as short a time as possible.
70fdfcd1fa7ebd059deffa9a2cecc29df96dfe52Bob Halley * We're also trying to hold as few locks as possible. This is why
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * some processing is deferred until after a lock is released.
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley */
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley LOCK(&task->lock);
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley /*
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley * Note: we require that task->shutting_down implies
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley * !task->enqueue_allowed.
c5839c39bd07c9dd3d4cd598035deb0537098475Bob Halley */
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley if (task->enqueue_allowed) {
ce3761f64d3d734cc94605026985898900ecc474Bob Halley if (task->state == task_state_idle) {
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley was_idle = ISC_TRUE;
8db3b065b4659f593f7b8eaa7c9ca0c3daa4da02Bob Halley INSIST(EMPTY(task->events));
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley task->state = task_state_ready;
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley }
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley INSIST(task->state == task_state_ready ||
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley task->state == task_state_running);
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley ENQUEUE(task->events, event, link);
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley } else {
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley disallowed = ISC_TRUE;
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley if (task->state == task_state_shutdown)
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley result = ISC_R_TASKSHUTDOWN;
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley else if (task->shutting_down)
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley result = ISC_R_TASKSHUTTINGDOWN;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley else
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley result = ISC_R_TASKNOSEND;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley }
c5839c39bd07c9dd3d4cd598035deb0537098475Bob Halley UNLOCK(&task->lock);
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley
ce3761f64d3d734cc94605026985898900ecc474Bob Halley if (disallowed)
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley return (result);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley if (was_idle) {
ce3761f64d3d734cc94605026985898900ecc474Bob Halley isc_taskmgr_t *manager;
ce3761f64d3d734cc94605026985898900ecc474Bob Halley
ce3761f64d3d734cc94605026985898900ecc474Bob Halley /*
ce3761f64d3d734cc94605026985898900ecc474Bob Halley * We need to add this task to the ready queue.
ce3761f64d3d734cc94605026985898900ecc474Bob Halley *
ce3761f64d3d734cc94605026985898900ecc474Bob Halley * We've waited until now to do it, rather than doing it
ce3761f64d3d734cc94605026985898900ecc474Bob Halley * while holding the task lock, because we don't want to
5fc1b54cc6134bd70f4e22df90a2e5631aaea77aBob Halley * block while holding the task lock.
5fc1b54cc6134bd70f4e22df90a2e5631aaea77aBob Halley *
5fc1b54cc6134bd70f4e22df90a2e5631aaea77aBob Halley * We've changed the state to ready, so no one else will
5fc1b54cc6134bd70f4e22df90a2e5631aaea77aBob Halley * be trying to add this task to the ready queue. It
ce3761f64d3d734cc94605026985898900ecc474Bob Halley * thus doesn't matter if more events have been added to
ce3761f64d3d734cc94605026985898900ecc474Bob Halley * the queue after we gave up the task lock.
ce3761f64d3d734cc94605026985898900ecc474Bob Halley *
ce3761f64d3d734cc94605026985898900ecc474Bob Halley * Shutting down a task requires posting a shutdown event
ce3761f64d3d734cc94605026985898900ecc474Bob Halley * to the task's queue and then executing it, so there's
ce3761f64d3d734cc94605026985898900ecc474Bob Halley * no way the task can disappear. A task is always on the
ce3761f64d3d734cc94605026985898900ecc474Bob Halley * task manager's 'tasks' list, so the task manager can
ce3761f64d3d734cc94605026985898900ecc474Bob Halley * always post a shutdown event to all tasks if it is
ce3761f64d3d734cc94605026985898900ecc474Bob Halley * requested to shutdown.
ce3761f64d3d734cc94605026985898900ecc474Bob Halley */
ce3761f64d3d734cc94605026985898900ecc474Bob Halley manager = task->manager;
ce3761f64d3d734cc94605026985898900ecc474Bob Halley INSIST(VALID_MANAGER(manager));
ce3761f64d3d734cc94605026985898900ecc474Bob Halley LOCK(&manager->lock);
ce3761f64d3d734cc94605026985898900ecc474Bob Halley ENQUEUE(manager->ready_tasks, task, ready_link);
ce3761f64d3d734cc94605026985898900ecc474Bob Halley SIGNAL(&manager->work_available);
ce3761f64d3d734cc94605026985898900ecc474Bob Halley UNLOCK(&manager->lock);
ce3761f64d3d734cc94605026985898900ecc474Bob Halley }
ce3761f64d3d734cc94605026985898900ecc474Bob Halley
38d2d0e9326a2f70b5893302b89a26978b539405Bob Halley *eventp = NULL;
3740b569ae76295b941d57a724a43beb75b533baBob Halley
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley XTRACE("sent");
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley return (ISC_R_SUCCESS);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley}
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halleyunsigned int
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halleyisc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type) {
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_event_t *event, *next_event;
c5839c39bd07c9dd3d4cd598035deb0537098475Bob Halley isc_eventlist_t purgeable;
38d2d0e9326a2f70b5893302b89a26978b539405Bob Halley unsigned int purge_count;
38d2d0e9326a2f70b5893302b89a26978b539405Bob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley REQUIRE(VALID_TASK(task));
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley REQUIRE(type >= 0);
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley /*
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley * Purge events matching 'sender' and 'type'. sender == NULL means
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley * "any sender". type == NULL means any type. Task manager events
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley * cannot be purged.
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley *
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley * Purging never changes the state of the task.
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley */
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley INIT_LIST(purgeable);
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley purge_count = 0;
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley LOCK(&task->lock);
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley for (event = HEAD(task->events);
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley event != NULL;
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley event = next_event) {
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley next_event = NEXT(event, link);
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley if ((sender == NULL || event->sender == sender) &&
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley ((type == 0 && event->type > 0) || event->type == type)) {
00d81794884f1eee59ca058a292f2d1e50d9547cBob Halley DEQUEUE(task->events, event, link);
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley ENQUEUE(purgeable, event, link);
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley }
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley }
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley UNLOCK(&task->lock);
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley for (event = HEAD(purgeable);
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley event != NULL;
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley event = next_event) {
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley next_event = NEXT(event, link);
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley isc_event_free(&event);
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley purge_count++;
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley }
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley return (purge_count);
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley}
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley
f18f3c93e7fecf120302658f93addae573a6e874Bob Halleyisc_result_t
f18f3c93e7fecf120302658f93addae573a6e874Bob Halleyisc_task_allowsend(isc_task_t *task, isc_boolean_t enqueue_allowed) {
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley isc_result_t result = ISC_R_SUCCESS;
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley REQUIRE(VALID_TASK(task));
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley LOCK(&task->lock);
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley if (task->state == task_state_shutdown)
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley result = ISC_R_TASKSHUTDOWN;
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley else if (task->shutting_down)
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley result = ISC_R_TASKSHUTTINGDOWN;
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley else
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley task->enqueue_allowed = enqueue_allowed;
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley UNLOCK(&task->lock);
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley return (result);
f18f3c93e7fecf120302658f93addae573a6e874Bob Halley}
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley
1366b7833c86343de278480b9abd71754e418bfaBob Halleyisc_result_t
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halleyisc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, void *arg) {
f0bbac2c0f1afa74b88cab902daf11202ebe7cbdBob Halley isc_boolean_t disallowed = ISC_FALSE;
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley isc_result_t result = ISC_R_SUCCESS;
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley isc_event_t *event;
1366b7833c86343de278480b9abd71754e418bfaBob Halley
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley REQUIRE(VALID_TASK(task));
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley event = event_allocate(task->mctx,
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley NULL,
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley ISC_TASKEVENT_SHUTDOWN,
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley action,
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley arg,
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley sizeof *event);
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley if (event == NULL)
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley return (ISC_R_NOMEMORY);
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley LOCK(&task->lock);
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley if (task->state == task_state_shutdown) {
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley disallowed = ISC_TRUE;
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley result = ISC_R_TASKSHUTDOWN;
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley } else if (task->shutting_down) {
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley disallowed = ISC_TRUE;
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley result = ISC_R_TASKSHUTTINGDOWN;
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley } else
1366b7833c86343de278480b9abd71754e418bfaBob Halley ENQUEUE(task->on_shutdown, event, link);
1366b7833c86343de278480b9abd71754e418bfaBob Halley UNLOCK(&task->lock);
1366b7833c86343de278480b9abd71754e418bfaBob Halley
1366b7833c86343de278480b9abd71754e418bfaBob Halley if (disallowed)
1366b7833c86343de278480b9abd71754e418bfaBob Halley isc_mem_put(task->mctx, event, sizeof *event);
1366b7833c86343de278480b9abd71754e418bfaBob Halley
1366b7833c86343de278480b9abd71754e418bfaBob Halley return (result);
1366b7833c86343de278480b9abd71754e418bfaBob Halley}
1366b7833c86343de278480b9abd71754e418bfaBob Halley
1366b7833c86343de278480b9abd71754e418bfaBob Halleyvoid
1366b7833c86343de278480b9abd71754e418bfaBob Halleyisc_task_shutdown(isc_task_t *task) {
1366b7833c86343de278480b9abd71754e418bfaBob Halley isc_boolean_t was_idle = ISC_FALSE;
1366b7833c86343de278480b9abd71754e418bfaBob Halley isc_boolean_t queued_something = ISC_FALSE;
1366b7833c86343de278480b9abd71754e418bfaBob Halley isc_event_t *event, *prev;
1366b7833c86343de278480b9abd71754e418bfaBob Halley
1366b7833c86343de278480b9abd71754e418bfaBob Halley REQUIRE(VALID_TASK(task));
1366b7833c86343de278480b9abd71754e418bfaBob Halley
1366b7833c86343de278480b9abd71754e418bfaBob Halley /*
1366b7833c86343de278480b9abd71754e418bfaBob Halley * This routine is very similar to isc_task_send() above.
1366b7833c86343de278480b9abd71754e418bfaBob Halley */
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley LOCK(&task->lock);
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley if (!task->shutting_down) {
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley if (task->state == task_state_idle) {
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley was_idle = ISC_TRUE;
bcfcece57e9411ee4bd352b45a8b1ac1dbcf01f4Bob Halley INSIST(EMPTY(task->events));
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley task->state = task_state_ready;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley }
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley INSIST(task->state == task_state_ready ||
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley task->state == task_state_running);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley /*
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * Note that we post shutdown events LIFO.
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley */
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley for (event = TAIL(task->on_shutdown);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley event != NULL;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley event = prev) {
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley prev = PREV(event, link);
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley DEQUEUE(task->on_shutdown, event, link);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley ENQUEUE(task->events, event, link);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley queued_something = ISC_TRUE;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley }
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley task->enqueue_allowed = ISC_FALSE;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley task->shutting_down = ISC_TRUE;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley }
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley UNLOCK(&task->lock);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley if (was_idle && queued_something) {
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley isc_taskmgr_t *manager;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley manager = task->manager;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley INSIST(VALID_MANAGER(manager));
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley LOCK(&manager->lock);
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley ENQUEUE(manager->ready_tasks, task, ready_link);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley SIGNAL(&manager->work_available);
95c86af1e92dae4ff837a39e7e2dcb7308dd9cceBob Halley UNLOCK(&manager->lock);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley }
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley}
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halleyvoid
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halleyisc_task_destroy(isc_task_t **taskp) {
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley REQUIRE(taskp != NULL);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_task_shutdown(*taskp);
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley isc_task_detach(taskp);
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley}
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley/***
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley *** Task Manager.
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley ***/
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halleystatic isc_threadresult_t
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley#ifdef _WIN32
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob HalleyWINAPI
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley#endif
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halleyrun(void *uap) {
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_taskmgr_t *manager = uap;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley isc_task_t *task;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley XTRACE("start");
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley REQUIRE(VALID_MANAGER(manager));
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley /*
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley * Again we're trying to hold the lock for as short a time as possible
86131d8d7aaf1bb8b8bfc7819985d05ea369b708Bob Halley * and to do as little locking and unlocking as possible.
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley *
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * In both while loops, the appropriate lock must be held before the
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * while body starts. Code which acquired the lock at the top of
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * the loop would be more readable, but would result in a lot of
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * extra locking. Compare:
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley *
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * Straightforward:
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley *
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * LOCK();
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * ...
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * UNLOCK();
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * while (expression) {
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * LOCK();
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * ...
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * UNLOCK();
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley *
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * Unlocked part here...
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley *
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * LOCK();
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * ...
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * UNLOCK();
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * }
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley *
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * Note how if the loop continues we unlock and then immediately lock.
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * For N iterations of the loop, this code does 2N+1 locks and 2N+1
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * unlocks. Also note that the lock is not held when the while
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * condition is tested, which may or may not be important, depending
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * on the expression.
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley *
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * As written:
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley *
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * LOCK();
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * while (expression) {
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * ...
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * UNLOCK();
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley *
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * Unlocked part here...
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley *
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * LOCK();
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * ...
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * }
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * UNLOCK();
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley *
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * For N iterations of the loop, this code does N+1 locks and N+1
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * unlocks. The while expression is always protected by the lock.
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley */
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley LOCK(&manager->lock);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley while (!FINISHED(manager)) {
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley /*
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * For reasons similar to those given in the comment in
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * isc_task_send() above, it is safe for us to dequeue
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * the task while only holding the manager lock, and then
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * change the task to running state while only holding the
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * task lock.
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley */
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley while (EMPTY(manager->ready_tasks) && !FINISHED(manager)) {
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley XTRACE("wait");
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley WAIT(&manager->work_available, &manager->lock);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley XTRACE("awake");
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley }
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley XTRACE("working");
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley task = HEAD(manager->ready_tasks);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley if (task != NULL) {
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley unsigned int dispatch_count = 0;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley isc_boolean_t done = ISC_FALSE;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley isc_boolean_t requeue = ISC_FALSE;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley isc_boolean_t free_task = ISC_FALSE;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley isc_event_t *event;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley INSIST(VALID_TASK(task));
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley /*
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * Note we only unlock the manager lock if we actually
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * have a task to do. We must reacquire the manager
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * lock before exiting the 'if (task != NULL)' block.
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley */
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley DEQUEUE(manager->ready_tasks, task, ready_link);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley UNLOCK(&manager->lock);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley LOCK(&task->lock);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley INSIST(task->state == task_state_ready);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley if (EMPTY(task->events)) {
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley /*
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * The task became runnable, but all events
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * in the run queue were subsequently purged.
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * Put the task to sleep.
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley */
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley task->state = task_state_idle;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley done = ISC_TRUE;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley XTRACE("ready but empty");
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley } else
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley task->state = task_state_running;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley while (!done) {
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley INSIST(!EMPTY(task->events));
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley event = HEAD(task->events);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley DEQUEUE(task->events, event, link);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley UNLOCK(&task->lock);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley /*
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * Execute the event action.
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley */
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley XTRACE("execute action");
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley if (event->action != NULL)
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley (event->action)(task, event);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley dispatch_count++;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley LOCK(&task->lock);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley if (EMPTY(task->events)) {
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley /*
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * Nothing else to do for this task
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * right now. If it is shutting down,
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * then it is done, otherwise we just
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * put it to sleep.
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley */
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley XTRACE("empty");
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley if (task->shutting_down) {
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley XTRACE("shutdown");
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley if (task->references == 0)
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley free_task = ISC_TRUE;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley task->state =
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley task_state_shutdown;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley } else
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley task->state = task_state_idle;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley done = ISC_TRUE;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley } else if (dispatch_count >= task->quantum) {
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley /*
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * Our quantum has expired, but
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * there is more work to be done.
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * We'll requeue it to the ready
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * queue later.
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley *
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * We don't check quantum until
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * dispatching at least one event,
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * so the minimum quantum is one.
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley */
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley XTRACE("quantum");
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley task->state = task_state_ready;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley requeue = ISC_TRUE;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley done = ISC_TRUE;
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley }
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley }
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley UNLOCK(&task->lock);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley if (free_task)
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley task_free(task);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley LOCK(&manager->lock);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley if (requeue) {
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley /*
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * We know we're awake, so we don't have
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * to wakeup any sleeping threads if the
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * ready queue is empty before we requeue.
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley *
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * A possible optimization if the queue is
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * empty is to 'goto' the 'if (task != NULL)'
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * block, avoiding the ENQUEUE of the task
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * and the subsequent immediate DEQUEUE
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * (since it is the only executable task).
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * We don't do this because then we'd be
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * skipping the exit_requested check. The
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * cost of ENQUEUE is low anyway, especially
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * when you consider that we'd have to do
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * an extra EMPTY check to see if we could
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * do the optimization. If the ready queue
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley * were usually nonempty, the 'optimization'
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley * might even hurt rather than help.
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley */
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley ENQUEUE(manager->ready_tasks, task,
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley ready_link);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley }
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley }
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley }
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley UNLOCK(&manager->lock);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley XTRACE("exit");
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley return ((isc_threadresult_t)0);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley}
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halleystatic void
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halleymanager_free(isc_taskmgr_t *manager) {
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley (void)isc_condition_destroy(&manager->work_available);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley (void)isc_mutex_destroy(&manager->lock);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley isc_mem_put(manager->mctx, manager->threads,
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley manager->workers * sizeof (isc_thread_t));
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley manager->magic = 0;
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley isc_mem_put(manager->mctx, manager, sizeof *manager);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley}
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halleyisc_result_t
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halleyisc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley unsigned int default_quantum, isc_taskmgr_t **managerp)
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley{
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley unsigned int i, started = 0;
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley isc_taskmgr_t *manager;
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley isc_thread_t *threads;
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley REQUIRE(workers > 0);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley REQUIRE(managerp != NULL && *managerp == NULL);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley manager = isc_mem_get(mctx, sizeof *manager);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley if (manager == NULL)
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley return (ISC_R_NOMEMORY);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley manager->magic = TASK_MANAGER_MAGIC;
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley manager->mctx = mctx;
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley threads = isc_mem_get(mctx, workers * sizeof (isc_thread_t));
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley if (threads == NULL) {
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley isc_mem_put(mctx, manager, sizeof *manager);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley return (ISC_R_NOMEMORY);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley }
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley manager->threads = threads;
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley manager->workers = 0;
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley if (isc_mutex_init(&manager->lock) != ISC_R_SUCCESS) {
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley isc_mem_put(mctx, threads, workers * sizeof (isc_thread_t));
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley isc_mem_put(mctx, manager, sizeof *manager);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley UNEXPECTED_ERROR(__FILE__, __LINE__,
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley "isc_mutex_init() failed");
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley return (ISC_R_UNEXPECTED);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley }
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley if (default_quantum == 0)
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley default_quantum = DEFAULT_DEFAULT_QUANTUM;
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley manager->default_quantum = default_quantum;
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley INIT_LIST(manager->tasks);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley INIT_LIST(manager->ready_tasks);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley if (isc_condition_init(&manager->work_available) != ISC_R_SUCCESS) {
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley (void)isc_mutex_destroy(&manager->lock);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley isc_mem_put(mctx, threads, workers * sizeof (isc_thread_t));
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley isc_mem_put(mctx, manager, sizeof *manager);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley UNEXPECTED_ERROR(__FILE__, __LINE__,
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley "isc_condition_init() failed");
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews return (ISC_R_UNEXPECTED);
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews }
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews manager->exiting = ISC_FALSE;
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews manager->workers = 0;
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews LOCK(&manager->lock);
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews /*
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews * Start workers.
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews */
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews for (i = 0; i < workers; i++) {
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews if (isc_thread_create(run, manager,
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews &manager->threads[manager->workers]) ==
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews ISC_R_SUCCESS) {
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews manager->workers++;
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews started++;
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews }
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews }
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews UNLOCK(&manager->lock);
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews if (started == 0) {
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews manager_free(manager);
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews return (ISC_R_NOTHREADS);
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews }
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews *managerp = manager;
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews return (ISC_R_SUCCESS);
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews}
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrewsvoid
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrewsisc_taskmgr_destroy(isc_taskmgr_t **managerp) {
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews isc_taskmgr_t *manager;
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews isc_task_t *task;
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews isc_event_t *event, *prev;
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews unsigned int i;
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews REQUIRE(managerp != NULL);
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews manager = *managerp;
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews REQUIRE(VALID_MANAGER(manager));
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews XTRACE("isc_taskmgr_destroy");
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews /*
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews * Only one non-worker thread may ever call this routine.
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews * If a worker thread wants to initiate shutdown of the
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews * task manager, it should ask some non-worker thread to call
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews * isc_taskmgr_destroy(), e.g. by signalling a condition variable
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews * that the startup thread is sleeping on.
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews */
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews /*
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews * Unlike elsewhere, we're going to hold this lock a long time.
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews * We need to do so, because otherwise the list of tasks could
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews * change while we were traversing it.
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews *
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews * This is also the only function where we will hold both the
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews * task manager lock and a task lock at the same time.
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews */
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews LOCK(&manager->lock);
6957b87f931bb110ba4d0adf495932691ba550b1Bob Halley
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews /*
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews * Make sure we only get called once.
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews */
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews INSIST(!manager->exiting);
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews manager->exiting = ISC_TRUE;
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews /*
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews * Post the shutdown event to every task (if it hasn't already been
aa8e34546c1e51e69f5a4935d28cb0c543e7401aAndreas Gustafsson * posted).
aa8e34546c1e51e69f5a4935d28cb0c543e7401aAndreas Gustafsson */
aa8e34546c1e51e69f5a4935d28cb0c543e7401aAndreas Gustafsson for (task = HEAD(manager->tasks);
aa8e34546c1e51e69f5a4935d28cb0c543e7401aAndreas Gustafsson task != NULL;
aa8e34546c1e51e69f5a4935d28cb0c543e7401aAndreas Gustafsson task = NEXT(task, link)) {
aa8e34546c1e51e69f5a4935d28cb0c543e7401aAndreas Gustafsson LOCK(&task->lock);
aa8e34546c1e51e69f5a4935d28cb0c543e7401aAndreas Gustafsson if (!task->shutting_down) {
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews /*
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews * Note that we post shutdown events LIFO.
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews */
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews for (event = TAIL(task->on_shutdown);
7c0539bea56022274da04263eb41fbb5b8835c38Mark Andrews event != NULL;
38d2d0e9326a2f70b5893302b89a26978b539405Bob Halley event = prev) {
3740b569ae76295b941d57a724a43beb75b533baBob Halley prev = PREV(event, link);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley DEQUEUE(task->on_shutdown, event, link);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley ENQUEUE(task->events, event, link);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley }
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley if (task->state == task_state_idle) {
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley task->state = task_state_ready;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley ENQUEUE(manager->ready_tasks, task,
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley ready_link);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley }
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley INSIST(task->state == task_state_ready ||
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley task->state == task_state_running);
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley task->enqueue_allowed = ISC_FALSE;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley task->shutting_down = ISC_TRUE;
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley }
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley UNLOCK(&task->lock);
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley }
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley /*
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * Wake up any sleeping workers. This ensures we get work done if
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley * there's work left to do, and if there are already no tasks left
29b487b0a458d655f0aad9257ca46021f4903d08Bob Halley * it will cause the workers to see manager->exiting.
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley */
c50fd34a4e0e6978f8ca5f6f3ad8545549c3cfeeBob Halley BROADCAST(&manager->work_available);
d2b77d720f1dcdc85a761b1de1a94d32fbdef81aBrian Wellington UNLOCK(&manager->lock);
d2b77d720f1dcdc85a761b1de1a94d32fbdef81aBrian Wellington
5d661f0bde49c68d33eb1146d60058782aca50a7Bob Halley /*
5d661f0bde49c68d33eb1146d60058782aca50a7Bob Halley * Wait for all the worker threads to exit.
d2b77d720f1dcdc85a761b1de1a94d32fbdef81aBrian Wellington */
d2b77d720f1dcdc85a761b1de1a94d32fbdef81aBrian Wellington for (i = 0; i < manager->workers; i++)
d2b77d720f1dcdc85a761b1de1a94d32fbdef81aBrian Wellington (void)isc_thread_join(manager->threads[i], NULL);
d2b77d720f1dcdc85a761b1de1a94d32fbdef81aBrian Wellington
d2b77d720f1dcdc85a761b1de1a94d32fbdef81aBrian Wellington manager_free(manager);
d2b77d720f1dcdc85a761b1de1a94d32fbdef81aBrian Wellington
d2b77d720f1dcdc85a761b1de1a94d32fbdef81aBrian Wellington *managerp = NULL;
d2b77d720f1dcdc85a761b1de1a94d32fbdef81aBrian Wellington}
d2b77d720f1dcdc85a761b1de1a94d32fbdef81aBrian Wellington