void isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) { isc_boolean_t idle1, idle2; isc_task_t *task; /* * Send '*event' to '*taskp' and then detach '*taskp' from its * task. */ REQUIRE(taskp != NULL); task = *taskp; REQUIRE(VALID_TASK(task)); XTRACE("isc_task_sendanddetach"); LOCK(&task->lock); idle1 = task_send(task, eventp); idle2 = task_detach(task); UNLOCK(&task->lock); /* * If idle1, then idle2 shouldn't be true as well since we're holding * the task lock, and thus the task cannot switch from ready back to * idle. */ INSIST(!(idle1 && idle2)); if (idle1 || idle2) task_ready(task); *taskp = NULL; }
ISC_TASKFUNC_SCOPE void isc__task_send(isc_task_t *task0, isc_event_t **eventp) { isc__task_t *task = (isc__task_t *)task0; isc_boolean_t was_idle; /* * Send '*event' to 'task'. */ REQUIRE(VALID_TASK(task)); XTRACE("isc_task_send"); /* * We're trying hard to hold locks for as short a time as possible. * We're also trying to hold as few locks as possible. This is why * some processing is deferred until after the lock is released. */ LOCK(&task->lock); was_idle = task_send(task, eventp); UNLOCK(&task->lock); if (was_idle) { /* * We need to add this task to the ready queue. * * We've waited until now to do it because making a task * ready requires locking the manager. If we tried to do * this while holding the task lock, we could deadlock. * * We've changed the state to ready, so no one else will * be trying to add this task to the ready queue. The * only way to leave the ready state is by executing the * task. It thus doesn't matter if events are added, * removed, or a shutdown is started in the interval * between the time we released the task lock, and the time * we add the task to the ready queue. */ task_ready(task); } }