]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Make sure all priority tasks are done before entering normal execution
authorWitold Kręcicki <wpk@isc.org>
Mon, 22 Oct 2018 10:57:05 +0000 (10:57 +0000)
committerWitold Kręcicki <wpk@isc.org>
Wed, 24 Oct 2018 07:06:57 +0000 (07:06 +0000)
lib/isc/task.c

index 9c1f769b8b3a56f115c89e7e043f3fe08c377df9..f6a4dc003ff22225684357e52c6efa34ade40b08 100644 (file)
 #include <openssl/err.h>
 #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; i<manager->workers && 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);
+                               }
                        }
                }
        }