Add reference counting for enqueued tasks
Previously, taskmgr was using ISC_LIST for keeping the enqueued tasks and the ISC_LIST have an inherent property that the task would not get enqueued twice. When taskmgr switched to using netmgr, we are using isc_queue_t which can enqueue same item multiple times, and this was causing problem when the previous isc_task_run() would find the task to be empty and shutting down. It would directly destroy the task and leave the following netievents with already freed task. This commit adds references counting around task_ready(++) and task_run(--) and adds isc_task_ready() public API wrapper around task_ready, so we can call it from netmgr when the event quantum would be reached.
This commit is contained in:
@@ -136,6 +136,12 @@ isc_task_create_bound(isc_taskmgr_t *manager, unsigned int quantum,
|
||||
*\li #ISC_R_SHUTTINGDOWN
|
||||
*/
|
||||
|
||||
void
|
||||
isc_task_ready(isc_task_t *task);
|
||||
/*%<
|
||||
* Enqueue the task onto netmgr queue.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_task_run(isc_task_t *task);
|
||||
/*%<
|
||||
|
||||
@@ -800,8 +800,7 @@ isc__nm_async_task(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
|
||||
switch (result) {
|
||||
case ISC_R_QUOTA:
|
||||
isc_nm_task_enqueue(worker->mgr, (isc_task_t *)ievent->task,
|
||||
isc_nm_tid());
|
||||
isc_task_ready(ievent->task);
|
||||
return;
|
||||
case ISC_R_SUCCESS:
|
||||
return;
|
||||
|
||||
@@ -103,6 +103,7 @@ struct isc_task {
|
||||
task_state_t state;
|
||||
int pause_cnt;
|
||||
isc_refcount_t references;
|
||||
isc_refcount_t running;
|
||||
isc_eventlist_t events;
|
||||
isc_eventlist_t on_shutdown;
|
||||
unsigned int nevents;
|
||||
@@ -179,6 +180,7 @@ task_finished(isc_task_t *task) {
|
||||
|
||||
XTRACE("task_finished");
|
||||
|
||||
isc_refcount_destroy(&task->running);
|
||||
isc_refcount_destroy(&task->references);
|
||||
|
||||
LOCK(&manager->lock);
|
||||
@@ -237,6 +239,7 @@ isc_task_create_bound(isc_taskmgr_t *manager, unsigned int quantum,
|
||||
task->pause_cnt = 0;
|
||||
|
||||
isc_refcount_init(&task->references, 1);
|
||||
isc_refcount_init(&task->running, 0);
|
||||
INIT_LIST(task->events);
|
||||
INIT_LIST(task->on_shutdown);
|
||||
task->nevents = 0;
|
||||
@@ -337,9 +340,16 @@ task_ready(isc_task_t *task) {
|
||||
REQUIRE(VALID_MANAGER(manager));
|
||||
|
||||
XTRACE("task_ready");
|
||||
|
||||
isc_refcount_increment0(&task->running);
|
||||
isc_nm_task_enqueue(manager->netmgr, task, task->threadid);
|
||||
}
|
||||
|
||||
void
|
||||
isc_task_ready(isc_task_t *task) {
|
||||
task_ready(task);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
task_detach(isc_task_t *task) {
|
||||
/*
|
||||
@@ -868,13 +878,13 @@ task_run(isc_task_t *task) {
|
||||
*/
|
||||
XTRACE("empty");
|
||||
if (isc_refcount_current(&task->references) == 0 &&
|
||||
TASK_SHUTTINGDOWN(task)) {
|
||||
TASK_SHUTTINGDOWN(task))
|
||||
{
|
||||
/*
|
||||
* The task is done.
|
||||
*/
|
||||
XTRACE("done");
|
||||
finished = true;
|
||||
task->state = task_state_done;
|
||||
} else {
|
||||
if (task->state == task_state_running) {
|
||||
XTRACE("idling");
|
||||
@@ -909,7 +919,8 @@ task_run(isc_task_t *task) {
|
||||
}
|
||||
UNLOCK(&task->lock);
|
||||
|
||||
if (finished) {
|
||||
if (isc_refcount_decrement(&task->running) == 1 && finished) {
|
||||
task->state = task_state_done;
|
||||
task_finished(task);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user