]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1657] mask SIGCHILD when creating new threads (only main thread handles it)
authorRazvan Becheriu <razvan@isc.org>
Mon, 1 Feb 2021 14:40:24 +0000 (16:40 +0200)
committerRazvan Becheriu <razvan@isc.org>
Mon, 22 Feb 2021 16:02:57 +0000 (16:02 +0000)
src/lib/asiolink/process_spawn.cc
src/lib/util/tests/thread_pool_unittest.cc
src/lib/util/tests/watched_thread_unittest.cc
src/lib/util/thread_pool.h
src/lib/util/watched_thread.cc

index 696f560e66c42879fc00364e43c268fa7403e05e..3394eddc27579a0a1739ecab82e56cd35829ac51 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2015-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2021 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -247,10 +247,6 @@ ProcessSpawnImpl::spawn(bool dismiss) {
     sigemptyset(&sset);
     sigaddset(&sset, SIGCHLD);
     pthread_sigmask(SIG_BLOCK, &sset, &osset);
-    if (sigismember(&osset, SIGCHLD)) {
-        isc_throw(ProcessSpawnError,
-                  "spawn() called from a thread where SIGCHLD is blocked");
-    }
 
     // Create the child
     pid_t pid = fork();
@@ -260,6 +256,7 @@ ProcessSpawnImpl::spawn(bool dismiss) {
 
     } else if (pid == 0) {
         // We're in the child process.
+        // Restore signal mask.
         sigprocmask(SIG_SETMASK, &osset, 0);
         // Run the executable.
         if (execve(executable_.c_str(), args_.get(), vars_.get()) != 0) {
@@ -278,10 +275,12 @@ ProcessSpawnImpl::spawn(bool dismiss) {
             store_ = true;
             process_collection_[this].insert(std::pair<pid_t, ProcessStatePtr>(pid, ProcessStatePtr(new ProcessState())));
         } catch(...) {
+            // Restore signal mask.
             pthread_sigmask(SIG_SETMASK, &osset, 0);
             throw;
         }
     }
+    // Restore signal mask.
     pthread_sigmask(SIG_SETMASK, &osset, 0);
     return (pid);
 }
index f22e5e2df1aa71777997173c33f350081890e2e3..8a346bbca211a9912bf0b29fd725a682de547e52 100644 (file)
@@ -62,6 +62,9 @@ public:
         EXPECT_THROW(thread_pool->reset(), InvalidOperation);
         EXPECT_THROW(thread_pool->wait(), InvalidOperation);
         EXPECT_THROW(thread_pool->wait(0), InvalidOperation);
+        sigset_t nsset;
+        pthread_sigmask(SIG_SETMASK, 0, &nsset);
+        EXPECT_EQ(1, sigismember(&nsset, SIGCHLD));
         EXPECT_NO_THROW(runAndWait());
     }
 
index 9ac67f219613c0801d718ee4b020befae8280c94..f4027f03cf19327e2f853527d6728e689f7f66bc 100644 (file)
@@ -49,6 +49,9 @@ public:
     ///
     /// @param watch_type type of event that should occur
     void worker(WatchedThread::WatchType watch_type) {
+        sigset_t nsset;
+        pthread_sigmask(SIG_SETMASK, 0, &nsset);
+        EXPECT_EQ(1, sigismember(&nsset, SIGCHLD));
         for (passes_ = 1; passes_ < WORKER_MAX_PASSES; ++passes_) {
 
             // Stop if we're told to do it.
index cc92a1a8d8981a28e5523b0f9509ad96ca04250a..c6ba8febd04b89263125fe8219ad252cb112d4c9 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2018-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2018-2021 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -20,6 +20,8 @@
 #include <queue>
 #include <thread>
 
+#include <signal.h>
+
 namespace isc {
 namespace util {
 
@@ -174,10 +176,24 @@ private:
     /// @param thread_count specifies the number of threads to be created and
     /// started
     void startInternal(uint32_t thread_count) {
+        // Protect us against SIGCHLD signals
+        sigset_t sset;
+        sigset_t osset;
+        sigemptyset(&sset);
+        sigaddset(&sset, SIGCHLD);
+        pthread_sigmask(SIG_BLOCK, &sset, &osset);
         queue_.enable(thread_count);
-        for (uint32_t i = 0; i < thread_count; ++i) {
-            threads_.push_back(boost::make_shared<std::thread>(&ThreadPool::run, this));
+        try {
+            for (uint32_t i = 0; i < thread_count; ++i) {
+                threads_.push_back(boost::make_shared<std::thread>(&ThreadPool::run, this));
+            }
+        } catch (...) {
+            // Restore signal mask.
+            pthread_sigmask(SIG_SETMASK, &osset, 0);
+            throw;
         }
+        // Restore signal mask.
+        pthread_sigmask(SIG_SETMASK, &osset, 0);
     }
 
     /// @brief stop all the threads
index c01594b64e4dcbe84029e25e7fff75c704ba29cb..ce85c539939afd50c9b066a8c89a1f808ad830ae 100644 (file)
@@ -1,11 +1,13 @@
-// Copyright (C) 2018-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2018-2021 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 #include <config.h>
+
 #include <util/watched_thread.h>
+#include <signal.h>
 
 namespace isc {
 namespace util {
@@ -16,7 +18,21 @@ WatchedThread::start(const std::function<void()>& thread_main) {
     clearReady(READY);
     clearReady(TERMINATE);
     setErrorInternal("no error");
-    thread_.reset(new std::thread(thread_main));
+    // Protect us against SIGCHLD signals
+    sigset_t sset;
+    sigset_t osset;
+    sigemptyset(&sset);
+    sigaddset(&sset, SIGCHLD);
+    pthread_sigmask(SIG_BLOCK, &sset, &osset);
+    try {
+        thread_.reset(new std::thread(thread_main));
+    } catch (...) {
+        // Restore signal mask.
+        pthread_sigmask(SIG_SETMASK, &osset, 0);
+        throw;
+    }
+    // Restore signal mask.
+    pthread_sigmask(SIG_SETMASK, &osset, 0);
 }
 
 int