Browse Source

[master] Merged trac4065 (block all signals in child threads)

Francis Dupont 9 years ago
parent
commit
a4a8e422e6

+ 2 - 1
src/lib/util/signal_set.h

@@ -89,7 +89,8 @@ typedef boost::function<bool(int signum)> BoolSignalHandler;
 ///
 ///
 /// @note This class is not thread safe. It uses static variables and
 /// @note This class is not thread safe. It uses static variables and
 /// functions to track a global state of signal registration and received
 /// functions to track a global state of signal registration and received
-/// signals' queue.
+/// signals' queue. But the thread library is signal safe as new threads
+/// are created with all signals blocked.
 class SignalSet : public boost::noncopyable {
 class SignalSet : public boost::noncopyable {
 public:
 public:
     /// @brief Constructor installing one signal.
     /// @brief Constructor installing one signal.

+ 19 - 0
src/lib/util/threads/tests/thread_unittest.cc

@@ -21,6 +21,8 @@
 
 
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
+#include <signal.h>
+
 // This file tests the Thread class. It's hard to test an actual thread is
 // This file tests the Thread class. It's hard to test an actual thread is
 // started, but we at least check the function is run and exceptions are
 // started, but we at least check the function is run and exceptions are
 // propagated as they should.
 // propagated as they should.
@@ -106,4 +108,21 @@ TEST(ThreadTest, exception) {
     }
     }
 }
 }
 
 
+// Returns signal mask set for a thread.
+void
+getSignalMask(sigset_t* mask) {
+    pthread_sigmask(SIG_SETMASK, 0, mask);
+}
+
+// Verify that all signals are blocked.
+TEST(ThreadTest, sigmask) {
+    sigset_t mask;
+    sigemptyset(&mask);
+    Thread thread(boost::bind(getSignalMask, &mask));
+    ASSERT_NO_THROW(thread.wait());
+    EXPECT_EQ(1, sigismember(&mask, SIGHUP));
+    EXPECT_EQ(1, sigismember(&mask, SIGINT));
+    EXPECT_EQ(1, sigismember(&mask, SIGTERM));
+}
+
 }
 }

+ 27 - 0
src/lib/util/threads/thread.cc

@@ -21,7 +21,9 @@
 #include <cerrno>
 #include <cerrno>
 
 
 #include <pthread.h>
 #include <pthread.h>
+#include <signal.h>
 
 
+#include <boost/noncopyable.hpp>
 #include <boost/scoped_ptr.hpp>
 #include <boost/scoped_ptr.hpp>
 
 
 using std::string;
 using std::string;
@@ -33,6 +35,30 @@ namespace isc {
 namespace util {
 namespace util {
 namespace thread {
 namespace thread {
 
 
+namespace {
+
+// Signal blocker class.
+class Blocker : boost::noncopyable {
+public:
+    // Constructor blocks all signals
+    Blocker() {
+        sigset_t new_mask;
+        sigfillset(&new_mask);
+        pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_);
+    }
+
+    // Destructor restores the previous signal mask
+    ~Blocker() {
+        pthread_sigmask(SIG_SETMASK, &old_mask_, 0);
+    }
+
+private:
+    // The previous signal mask
+    sigset_t old_mask_;
+};
+
+}
+
 // The implementation of the Thread class.
 // The implementation of the Thread class.
 //
 //
 // This internal state is not deleted until the thread terminates and is either
 // This internal state is not deleted until the thread terminates and is either
@@ -105,6 +131,7 @@ Thread::Thread(const boost::function<void ()>& main) :
     impl_(NULL)
     impl_(NULL)
 {
 {
     auto_ptr<Impl> impl(new Impl(main));
     auto_ptr<Impl> impl(new Impl(main));
+    Blocker blocker;
     const int result = pthread_create(&impl->tid_, NULL, &Impl::run,
     const int result = pthread_create(&impl->tid_, NULL, &Impl::run,
                                       impl.get());
                                       impl.get());
     // Any error here?
     // Any error here?