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:
Ondřej Surý
2021-05-05 14:25:42 +02:00
committed by Petr Špaček
parent 57364fd1a9
commit f6289afc97
3 changed files with 21 additions and 5 deletions

View File

@@ -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);
/*%<

View File

@@ -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;

View File

@@ -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);
}