task.c revision ad555ae689d3bb4fb76426dee43946686e7e3621
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * Copyright (C) 1998, 1999 Internet Software Consortium.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * Permission to use, copy, modify, and distribute this software for any
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley * purpose with or without fee is hereby granted, provided that the above
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley * copyright notice and this permission notice appear in all copies.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
9c3531d72aeaad6c5f01efe6a1c82023e1379e4dDavid Lawrence * Principal Author: Bob Halley
364a82f7c25b62967678027043425201a5e5171aBob Halley * XXXRTH Need to document the states a task can be in, and the rules
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley * for changing states.
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley#define XTRACE(m) printf("task %p thread %lu: %s\n", \
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley#define XTTRACE(t, m) printf("task %p thread %lu: %s\n", \
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley#define XTHREADTRACE(m) printf("thread %lu: %s\n", \
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halleytypedef enum {
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley detach_result_ok, detach_result_finished, detach_result_wasidle
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halleytypedef enum {
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley task_state_idle, task_state_ready, task_state_running,
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley /* Not locked. */
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley unsigned int magic;
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley /* Locked by task lock. */
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley unsigned int references;
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley unsigned int quantum;
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley unsigned int flags;
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley /* Locked by task manager lock. */
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley#define DONE_FLAGS (TASK_F_DONEOK|TASK_F_SHUTTINGDOWN)
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley#define TASK_WANTDONE(t) (((t)->flags & DONE_FLAGS) == \
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley#define TASK_SHUTTINGDOWN(t) (((t)->flags & TASK_F_SHUTTINGDOWN) \
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley#define TASK_MANAGER_MAGIC 0x54534B4DU /* TSKM. */
55254a46f91419b92eee0d20dfb958e8dd52526cBob Halley /* Not locked. */
55254a46f91419b92eee0d20dfb958e8dd52526cBob Halley unsigned int magic;
948eabe2a254a8a278ef6325f3790e75329ee656Bob Halley unsigned int workers;
948eabe2a254a8a278ef6325f3790e75329ee656Bob Halley /* Locked by task manager lock. */
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley#define FINISHED(m) ((m)->exiting && EMPTY((m)->tasks))
e0df061f35a26d2bbd0986aa889f88b3710b32d4Bob Halley * All tasks have completed and the
93d6dfaf66258337985427c86181f01fc51f0bb4Mark Andrews * task manager is exiting. Wake up
e0df061f35a26d2bbd0986aa889f88b3710b32d4Bob Halley * any idle worker threads so they
e0df061f35a26d2bbd0986aa889f88b3710b32d4Bob Halleyisc_task_create(isc_taskmgr_t *manager, isc_mem_t *mctx, unsigned int quantum,
e0df061f35a26d2bbd0986aa889f88b3710b32d4Bob Halley if (isc_mutex_init(&task->lock) != ISC_R_SUCCESS) {
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley "isc_mutex_init() failed");
55254a46f91419b92eee0d20dfb958e8dd52526cBob Halley /* XXX Should disallow if task manager is exiting. */
55254a46f91419b92eee0d20dfb958e8dd52526cBob Halleyisc_task_attach(isc_task_t *source, isc_task_t **targetp) {
55254a46f91419b92eee0d20dfb958e8dd52526cBob Halley * Attach *targetp to source.
55254a46f91419b92eee0d20dfb958e8dd52526cBob Halley * Caller must be holding the task's lock.
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halley * Note that we post shutdown events LIFO.
421e4cf66e4cba0b0751a34a9c027e39fe0474f9Mark Andrewsstatic inline void
948eabe2a254a8a278ef6325f3790e75329ee656Bob Halley * Caller must be holding the task lock.
948eabe2a254a8a278ef6325f3790e75329ee656Bob Halley * There are no references to this task, and no
948eabe2a254a8a278ef6325f3790e75329ee656Bob Halley * pending events. We initiate shutdown, since
948eabe2a254a8a278ef6325f3790e75329ee656Bob Halley * otherwise this task would just sit around until
948eabe2a254a8a278ef6325f3790e75329ee656Bob Halley * the task manager was destroyed.
948eabe2a254a8a278ef6325f3790e75329ee656Bob Halley * Detach *taskp from its task.
948eabe2a254a8a278ef6325f3790e75329ee656Bob Halley * Get the task's memory context.
948eabe2a254a8a278ef6325f3790e75329ee656Bob Halleytask_send(isc_task_t *task, isc_event_t **eventp, isc_boolean_t *was_idlep) {
948eabe2a254a8a278ef6325f3790e75329ee656Bob Halley * Caller must be holding the task lock.
948eabe2a254a8a278ef6325f3790e75329ee656Bob Halley * Note: we require that task->state == task_state_done implies
948eabe2a254a8a278ef6325f3790e75329ee656Bob Halley * (task->flags & TASK_F_SENDOK) == 0.
4e142a5bccd2944174ad9ae58d86cf03e170054dBob Halleyisc_task_send(isc_task_t *task, isc_event_t **eventp) {
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * Send '*event' to 'task'.
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * We're trying hard to hold locks for as short a time as possible.
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * We're also trying to hold as few locks as possible. This is why
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * some processing is deferred until after the lock is released.
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * We need to add this task to the ready queue.
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * We've waited until now to do it because making a task
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * ready requires locking the manager. If we tried to do
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * this while holding the task lock, we could deadlock.
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * We've changed the state to ready, so no one else will
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * be trying to add this task to the ready queue. The
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * only way to leave the ready state is by executing the
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * task. It thus doesn't matter if events are added,
80b782f356f0692c11b4e52e8dd46ec41704e5a2Mark Andrews * removed, or a shutdown is started in the interval
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * between the time we released the task lock, and the time
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * we add the task to the ready queue.
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrewsisc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) {
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * Send '*event' to '*taskp' and then detach '*taskp' from its
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * If was_idle is true, then the task is ready with at least
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * one event in the queue, and nothing will happen until
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * we call task_ready(). In particular, the task cannot
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * be executing or have entered the done state, so if
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * dresult is detach_result_finished, was_idle must have been
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * false. We INSIST on it.
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * If was_idle, then dresult shouldn't be
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * detach_result_wasidle, since that would mean someone else
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * changed the task's state from ready back to idle, which
7ac0df532272d803c3f72ff7a109587e92622f5aMark Andrews * should never happen. We INSIST on it.
d0eb2cc33c5db3366a16b1cb0abcca6ec7c8ee3cTatuya JINMEI 神明達哉 INSIST(!(was_idle && dresult == detach_result_wasidle));
d0eb2cc33c5db3366a16b1cb0abcca6ec7c8ee3cTatuya JINMEI 神明達哉 if (was_idle || dresult == detach_result_wasidle)
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews#define PURGE_OK(event) (((event)->attributes & ISC_EVENTATTR_NOPURGE) == 0)
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrewsstatic unsigned int
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrewsdequeue_events(isc_task_t *task, void *sender, isc_eventtype_t first,
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews isc_eventlist_t *events, isc_boolean_t purging)
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews unsigned int count = 0;
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * Events matching 'sender', whose type is >= first and <= last, and
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * whose tag is 'tag' will be dequeued. If 'purging', matching events
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * which are marked as unpurgable will not be dequeued.
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * sender == NULL means "any sender", and tag == NULL means "any tag".
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews for (event = HEAD(task->events); event != NULL; event = next_event) {
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews if (event->type >= first && event->type <= last &&
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrewsisc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first,
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews unsigned int count;
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * Purge events from a task's event queue.
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews count = dequeue_events(task, sender, first, last, tag, &events,
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews for (event = HEAD(events); event != NULL; event = next_event) {
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * Note that purging never changes the state of the task.
void *tag)
return (ISC_FALSE);
return (ISC_TRUE);
ISC_FALSE));
ISC_FALSE));
if (allowed)
return (result);
if (allowed) {
if (was_idle)
return (result);
NULL,
arg,
sizeof *event);
return (ISC_R_NOMEMORY);
if (disallowed)
return (result);
if (was_idle)
static isc_threadresult_t
#ifdef _WIN32
unsigned int dispatch_count = 0;
} while (!done);
if (finished)
if (requeue) {
return ((isc_threadresult_t)0);
unsigned int i, started = 0;
return (ISC_R_NOMEMORY);
return (ISC_R_NOMEMORY);
return (ISC_R_UNEXPECTED);
if (default_quantum == 0)
return (ISC_R_UNEXPECTED);
for (i = 0; i < workers; i++) {
started++;
if (started == 0) {
return (ISC_R_NOTHREADS);
return (ISC_R_SUCCESS);