From: Razvan Becheriu Date: Mon, 1 Feb 2021 14:40:24 +0000 (+0200) Subject: [#1657] mask SIGCHILD when creating new threads (only main thread handles it) X-Git-Tag: Kea-1.9.5~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d752eb5c7ab7aba4874a43facabdf89fb741b8fe;p=thirdparty%2Fkea.git [#1657] mask SIGCHILD when creating new threads (only main thread handles it) --- diff --git a/src/lib/asiolink/process_spawn.cc b/src/lib/asiolink/process_spawn.cc index 696f560e66..3394eddc27 100644 --- a/src/lib/asiolink/process_spawn.cc +++ b/src/lib/asiolink/process_spawn.cc @@ -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, 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); } diff --git a/src/lib/util/tests/thread_pool_unittest.cc b/src/lib/util/tests/thread_pool_unittest.cc index f22e5e2df1..8a346bbca2 100644 --- a/src/lib/util/tests/thread_pool_unittest.cc +++ b/src/lib/util/tests/thread_pool_unittest.cc @@ -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()); } diff --git a/src/lib/util/tests/watched_thread_unittest.cc b/src/lib/util/tests/watched_thread_unittest.cc index 9ac67f2196..f4027f03cf 100644 --- a/src/lib/util/tests/watched_thread_unittest.cc +++ b/src/lib/util/tests/watched_thread_unittest.cc @@ -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. diff --git a/src/lib/util/thread_pool.h b/src/lib/util/thread_pool.h index cc92a1a8d8..c6ba8febd0 100644 --- a/src/lib/util/thread_pool.h +++ b/src/lib/util/thread_pool.h @@ -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 #include +#include + 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(&ThreadPool::run, this)); + try { + for (uint32_t i = 0; i < thread_count; ++i) { + threads_.push_back(boost::make_shared(&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 diff --git a/src/lib/util/watched_thread.cc b/src/lib/util/watched_thread.cc index c01594b64e..ce85c53993 100644 --- a/src/lib/util/watched_thread.cc +++ b/src/lib/util/watched_thread.cc @@ -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 + #include +#include namespace isc { namespace util { @@ -16,7 +18,21 @@ WatchedThread::start(const std::function& 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