summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvladlosev <vladlosev@861a406c-534a-0410-8894-cb66d6ee9925>2011-09-09 05:42:09 +0000
committervladlosev <vladlosev@861a406c-534a-0410-8894-cb66d6ee9925>2011-09-09 05:42:09 +0000
commit7c3004c3013fe4adf5e0447d37ee2d0501c2b227 (patch)
tree4423fe5ca3a26ee734cbe8a8dc9c589570bd4a31
parente0e93e5547c71906b6c70eb06e781ced1dae0407 (diff)
downloadgoogletest-7c3004c3013fe4adf5e0447d37ee2d0501c2b227.tar.gz
Ignore SIGPROF signal during clone()/fork() call. clone()/fork() call hangs permanently if it consumes more cpu than the SIGPROF signal timer interval (by Nabeel Mian).
git-svn-id: http://googletest.googlecode.com/svn/trunk@592 861a406c-534a-0410-8894-cb66d6ee9925
-rw-r--r--src/gtest-death-test.cc21
-rw-r--r--test/gtest-death-test_test.cc55
2 files changed, 76 insertions, 0 deletions
diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc
index fb4a9f9..2f0b0e3 100644
--- a/src/gtest-death-test.cc
+++ b/src/gtest-death-test.cc
@@ -43,6 +43,11 @@
# include <errno.h>
# include <fcntl.h>
# include <limits.h>
+
+# if GTEST_OS_LINUX
+# include <signal.h>
+# endif // GTEST_OS_LINUX
+
# include <stdarg.h>
# if GTEST_OS_WINDOWS
@@ -998,6 +1003,18 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));
# else // GTEST_OS_QNX
+# if GTEST_OS_LINUX
+ // When a SIGPROF signal is received while fork() or clone() are executing,
+ // the process may hang. To avoid this, we ignore SIGPROF here and re-enable
+ // it after the call to fork()/clone() is complete.
+ struct sigaction saved_sigprof_action;
+ struct sigaction ignore_sigprof_action;
+ memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action));
+ sigemptyset(&ignore_sigprof_action.sa_mask);
+ ignore_sigprof_action.sa_handler = SIG_IGN;
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction(
+ SIGPROF, &ignore_sigprof_action, &saved_sigprof_action));
+# endif // GTEST_OS_LINUX
# if GTEST_HAS_CLONE
const bool use_fork = GTEST_FLAG(death_test_use_fork);
@@ -1025,6 +1042,10 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
_exit(0);
}
# endif // GTEST_OS_QNX
+# if GTEST_OS_LINUX
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(
+ sigaction(SIGPROF, &saved_sigprof_action, NULL));
+# endif // GTEST_OS_LINUX
GTEST_DEATH_TEST_CHECK_(child_pid != -1);
return child_pid;
diff --git a/test/gtest-death-test_test.cc b/test/gtest-death-test_test.cc
index bcf8e2a..afbdf8a 100644
--- a/test/gtest-death-test_test.cc
+++ b/test/gtest-death-test_test.cc
@@ -52,6 +52,10 @@ using testing::internal::AlwaysTrue;
# include <signal.h>
# include <stdio.h>
+# if GTEST_OS_LINUX
+# include <sys/time.h>
+# endif // GTEST_OS_LINUX
+
# include "gtest/gtest-spi.h"
// Indicates that this translation unit is part of Google Test's
@@ -372,6 +376,57 @@ TEST_F(TestForDeathTest, FastDeathTestInChangedDir) {
ASSERT_DEATH(_exit(1), "");
}
+# if GTEST_OS_LINUX
+void SigprofAction(int, siginfo_t*, void*) { /* no op */ }
+
+// Sets SIGPROF action and ITIMER_PROF timer (interval: 1ms).
+void SetSigprofActionAndTimer() {
+ struct itimerval timer;
+ timer.it_interval.tv_sec = 0;
+ timer.it_interval.tv_usec = 1;
+ timer.it_value = timer.it_interval;
+ ASSERT_EQ(0, setitimer(ITIMER_PROF, &timer, NULL));
+ struct sigaction signal_action;
+ memset(&signal_action, 0, sizeof(signal_action));
+ sigemptyset(&signal_action.sa_mask);
+ signal_action.sa_sigaction = SigprofAction;
+ signal_action.sa_flags = SA_RESTART | SA_SIGINFO;
+ ASSERT_EQ(0, sigaction(SIGPROF, &signal_action, NULL));
+}
+
+// Disables ITIMER_PROF timer and ignores SIGPROF signal.
+void DisableSigprofActionAndTimer(struct sigaction* old_signal_action) {
+ struct itimerval timer;
+ timer.it_interval.tv_usec = 0;
+ timer.it_value.tv_usec = 0;
+ ASSERT_EQ(0, setitimer(ITIMER_PROF, &timer, NULL));
+ struct sigaction signal_action;
+ memset(&signal_action, 0, sizeof(signal_action));
+ sigemptyset(&signal_action.sa_mask);
+ signal_action.sa_handler = SIG_IGN;
+ ASSERT_EQ(0, sigaction(SIGPROF, &signal_action, old_signal_action));
+}
+
+// Tests that death tests work when SIGPROF handler and timer are set.
+TEST_F(TestForDeathTest, FastSigprofActionSet) {
+ testing::GTEST_FLAG(death_test_style) = "fast";
+ SetSigprofActionAndTimer();
+ EXPECT_DEATH(_exit(1), "");
+ struct sigaction old_signal_action;
+ DisableSigprofActionAndTimer(&old_signal_action);
+ EXPECT_TRUE(old_signal_action.sa_sigaction == SigprofAction);
+}
+
+TEST_F(TestForDeathTest, ThreadSafeSigprofActionSet) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ SetSigprofActionAndTimer();
+ EXPECT_DEATH(_exit(1), "");
+ struct sigaction old_signal_action;
+ DisableSigprofActionAndTimer(&old_signal_action);
+ EXPECT_TRUE(old_signal_action.sa_sigaction == SigprofAction);
+}
+# endif // GTEST_OS_LINUX
+
// Repeats a representative sample of death tests in the "threadsafe" style:
TEST_F(TestForDeathTest, StaticMemberFunctionThreadsafeStyle) {