add isc_task_pause() and isc_task_unpause() functions
This allows a task to be temporary disabled so that objects won't be processed simultaneously by libuv events and isc_task events. When a task is paused, currently running events may complete, but no further event will added to the run queue will be executed until the task is unpaused.
This commit is contained in:
@@ -571,6 +571,22 @@ isc_task_endexclusive(isc_task_t *task);
|
||||
* 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
|
||||
|
||||
@@ -78,8 +78,8 @@
|
||||
***/
|
||||
|
||||
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)
|
||||
@@ -371,6 +371,7 @@ task_shutdown(isc__task_t *task) {
|
||||
was_idle = true;
|
||||
}
|
||||
INSIST(task->state == task_state_ready ||
|
||||
task->state == task_state_paused ||
|
||||
task->state == task_state_running);
|
||||
|
||||
/*
|
||||
@@ -491,7 +492,8 @@ task_send(isc__task_t *task, isc_event_t **eventp, int c) {
|
||||
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;
|
||||
@@ -1134,12 +1136,15 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) {
|
||||
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;
|
||||
|
||||
/*
|
||||
@@ -1174,16 +1179,19 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) {
|
||||
* 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) {
|
||||
/*
|
||||
@@ -1643,6 +1651,55 @@ isc_task_endexclusive(isc_task_t *task0) {
|
||||
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));
|
||||
|
||||
Reference in New Issue
Block a user