* exclusive access by calling isc_task_spl().
*/
+void
+isc_task_pause(isc_task_t *task0);
+void
+isc_task_unpause(isc_task_t *task0);
+/*%<
+ * Pause/unpause this task. Pausing a task removes it from the ready
+ * queue if it is present there; this ensures that the task will not
+ * run again until unpaused. This is necessary when the libuv network
+ * thread executes a function which schedules task manager events; this
+ * prevents the task manager from executing the next event in a task
+ * before the network thread has finished.
+ *
+ * Requires:
+ *\li 'task' is a valid task, and is not already paused or shutting down.
+ */
+
void
isc_task_getcurrenttime(isc_task_t *task, isc_stdtime_t *t);
void
***/
typedef enum {
- task_state_idle, task_state_ready, task_state_running,
- task_state_done
+ task_state_idle, task_state_ready, task_state_paused,
+ task_state_running, task_state_done
} task_state_t;
#if defined(HAVE_LIBXML2) || defined(HAVE_JSON_C)
was_idle = true;
}
INSIST(task->state == task_state_ready ||
+ task->state == task_state_paused ||
task->state == task_state_running);
/*
task->state = task_state_ready;
}
INSIST(task->state == task_state_ready ||
- task->state == task_state_running);
+ task->state == task_state_running ||
+ task->state == task_state_paused);
ENQUEUE(task->events, event, ev_link);
task->nevents++;
*eventp = NULL;
event);
LOCK(&task->lock);
}
+ XTRACE("execution complete");
dispatch_count++;
}
- if (isc_refcount_current(&task->references) == 0 &&
+ if (isc_refcount_current(
+ &task->references) == 0 &&
EMPTY(task->events) &&
- !TASK_SHUTTINGDOWN(task)) {
+ !TASK_SHUTTINGDOWN(task))
+ {
bool was_idle;
/*
* right now.
*/
XTRACE("empty");
- if (isc_refcount_current(&task->references) == 0 &&
- TASK_SHUTTINGDOWN(task)) {
+ if (isc_refcount_current(
+ &task->references) == 0 &&
+ TASK_SHUTTINGDOWN(task))
+ {
/*
* The task is done.
*/
XTRACE("done");
finished = true;
task->state = task_state_done;
- } else
+ } else {
task->state = task_state_idle;
+ }
done = true;
} else if (dispatch_count >= task->quantum) {
/*
UNLOCK(&manager->halt_lock);
}
+void
+isc_task_pause(isc_task_t *task0) {
+ REQUIRE(ISCAPI_TASK_VALID(task0));
+ isc__task_t *task = (isc__task_t *)task0;
+ isc__taskmgr_t *manager = task->manager;
+ bool running = false;
+
+ LOCK(&task->lock);
+ INSIST(task->state == task_state_idle ||
+ task->state == task_state_ready ||
+ task->state == task_state_running);
+ running = (task->state == task_state_running);
+ task->state = task_state_paused;
+ UNLOCK(&task->lock);
+
+ if (running) {
+ return;
+ }
+
+ LOCK(&manager->queues[task->threadid].lock);
+ if (ISC_LINK_LINKED(task, ready_link)) {
+ DEQUEUE(manager->queues[task->threadid].ready_tasks,
+ task, ready_link);
+ }
+ UNLOCK(&manager->queues[task->threadid].lock);
+}
+
+void
+isc_task_unpause(isc_task_t *task0) {
+ isc__task_t *task = (isc__task_t *)task0;
+ bool was_idle = false;
+
+ REQUIRE(ISCAPI_TASK_VALID(task0));
+
+ LOCK(&task->lock);
+ INSIST(task->state == task_state_paused);
+ if (!EMPTY(task->events)) {
+ task->state = task_state_ready;
+ was_idle = true;
+ } else {
+ task->state = task_state_idle;
+ }
+ UNLOCK(&task->lock);
+
+ if (was_idle) {
+ task_ready(task);
+ }
+}
+
void
isc_task_setprivilege(isc_task_t *task0, bool priv) {
REQUIRE(ISCAPI_TASK_VALID(task0));