]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Switch from privileged to un-privileged mode under lock
authorWitold Kręcicki <wpk@isc.org>
Thu, 25 Oct 2018 12:41:59 +0000 (12:41 +0000)
committerWitold Kręcicki <wpk@isc.org>
Tue, 6 Nov 2018 08:19:50 +0000 (08:19 +0000)
lib/isc/task.c

index e2124dd53c81fdadb81a46635f89e18913bad93f..3862f14c531cec6d2ac9c57acd59e6d34901171a 100644 (file)
@@ -1211,22 +1211,34 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) {
                                         memory_order_acquire) == 0 &&
                    manager->mode != isc_taskmgrmode_normal)
                {
-                       bool empty = true;
-                       for (unsigned i=0; i<manager->workers && empty; i++) {
-                               if (i != threadid) {
+                       UNLOCK(&manager->queues[threadid].lock);
+                       LOCK(&manager->lock);
+                       /*
+                        * Check once again, under lock. Mode can only
+                        * change from privileged to normal anyway, and
+                        * if we enter this loop twice at the same time
+                        * we'll end up in a deadlock over queue locks.
+                        *
+                        */
+                       if (atomic_load_explicit(&manager->tasks_running,
+                                                memory_order_acquire) == 0 &&
+                           manager->mode != isc_taskmgrmode_normal)
+                       {
+                               bool empty = true;
+                               for (unsigned i=0; i<manager->workers && empty; i++) {
                                        LOCK(&manager->queues[i].lock);
-                               }
-                               empty &= empty_readyq(manager, i);
-                               if (i != threadid) {
+                                       empty &= empty_readyq(manager, i);
                                        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);
+                               if (empty) {
+                                       manager->mode = isc_taskmgrmode_normal;
+                                       for (unsigned i=0; i < manager->workers; i++) {
+                                               BROADCAST(&manager->queues[i].work_available);
+                                       }
                                }
                        }
+                       UNLOCK(&manager->lock);
+                       LOCK(&manager->queues[threadid].lock);
                }
        }
        UNLOCK(&manager->queues[threadid].lock);