From: Witold Kręcicki Date: Mon, 22 Oct 2018 10:57:05 +0000 (+0000) Subject: Make sure all priority tasks are done before entering normal execution X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0e1e295ddbdd4e2605a8a15a7dc441eb8cb34818;p=thirdparty%2Fbind9.git Make sure all priority tasks are done before entering normal execution --- diff --git a/lib/isc/task.c b/lib/isc/task.c index 9c1f769b8b3..f6a4dc003ff 100644 --- a/lib/isc/task.c +++ b/lib/isc/task.c @@ -43,6 +43,14 @@ #include #endif +/* + * Task manager is built around 'as little locking as possible' concept. + * Each thread has his own queue of tasks to be run, if a task is in running + * state it will stay on the runner it's currently on, if a task is in idle + * state it can be woken up on a specific runner with isc_task_sendto - that + * helps with data locality on CPU. + */ + #ifdef ISC_TASK_TRACE #define XTRACE(m) fprintf(stderr, "task %p thread %lu: %s\n", \ task, isc_thread_self(), (m)) @@ -95,7 +103,7 @@ struct isc__task { isc_time_t tnow; char name[16]; void * tag; - int threadid; + unsigned int threadid; /* Locked by task manager lock. */ LINK(isc__task_t) link; LINK(isc__task_t) ready_link; @@ -911,7 +919,7 @@ push_readyq(isc__taskmgr_t *manager, isc__task_t *task, int c) { } static void -dispatch(isc__taskmgr_t *manager, int threadid) { +dispatch(isc__taskmgr_t *manager, unsigned int threadid) { isc__task_t *task; REQUIRE(VALID_MANAGER(manager)); @@ -1191,10 +1199,22 @@ dispatch(isc__taskmgr_t *manager, int threadid) { * we're stuck. Automatically drop privileges at that * point and continue with the regular ready queue. */ - if (manager->tasks_running == 0 && empty_readyq(manager, threadid)) { - manager->mode = isc_taskmgrmode_normal; - for (unsigned i=0; i < manager->workers; i++) { - BROADCAST(&manager->queues[i].work_available); + if (atomic_load(&manager->tasks_running) == 0 && manager->mode != isc_taskmgrmode_normal) { + bool empty = true; + for (unsigned i=0; iworkers && empty; i++) { + if (i != threadid) { + LOCK(&manager->queues[i].lock); + } + empty &= empty_readyq(manager, i); + if (i != threadid) { + UNLOCK(&manager->queues[i].lock); + } + } + if (empty) { + manager->mode = isc_taskmgrmode_normal; + for (unsigned i=0; i < manager->workers; i++) { + BROADCAST(&manager->queues[i].work_available); + } } } }