Skip to content

Commit 7c3004c

Browse files
author
vladlosev
committed
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
1 parent e0e93e5 commit 7c3004c

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

src/gtest-death-test.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@
4343
# include <errno.h>
4444
# include <fcntl.h>
4545
# include <limits.h>
46+
47+
# if GTEST_OS_LINUX
48+
# include <signal.h>
49+
# endif // GTEST_OS_LINUX
50+
4651
# include <stdarg.h>
4752

4853
# if GTEST_OS_WINDOWS
@@ -998,6 +1003,18 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
9981003
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));
9991004

10001005
# else // GTEST_OS_QNX
1006+
# if GTEST_OS_LINUX
1007+
// When a SIGPROF signal is received while fork() or clone() are executing,
1008+
// the process may hang. To avoid this, we ignore SIGPROF here and re-enable
1009+
// it after the call to fork()/clone() is complete.
1010+
struct sigaction saved_sigprof_action;
1011+
struct sigaction ignore_sigprof_action;
1012+
memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action));
1013+
sigemptyset(&ignore_sigprof_action.sa_mask);
1014+
ignore_sigprof_action.sa_handler = SIG_IGN;
1015+
GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction(
1016+
SIGPROF, &ignore_sigprof_action, &saved_sigprof_action));
1017+
# endif // GTEST_OS_LINUX
10011018

10021019
# if GTEST_HAS_CLONE
10031020
const bool use_fork = GTEST_FLAG(death_test_use_fork);
@@ -1025,6 +1042,10 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
10251042
_exit(0);
10261043
}
10271044
# endif // GTEST_OS_QNX
1045+
# if GTEST_OS_LINUX
1046+
GTEST_DEATH_TEST_CHECK_SYSCALL_(
1047+
sigaction(SIGPROF, &saved_sigprof_action, NULL));
1048+
# endif // GTEST_OS_LINUX
10281049

10291050
GTEST_DEATH_TEST_CHECK_(child_pid != -1);
10301051
return child_pid;

test/gtest-death-test_test.cc

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ using testing::internal::AlwaysTrue;
5252
# include <signal.h>
5353
# include <stdio.h>
5454

55+
# if GTEST_OS_LINUX
56+
# include <sys/time.h>
57+
# endif // GTEST_OS_LINUX
58+
5559
# include "gtest/gtest-spi.h"
5660

5761
// Indicates that this translation unit is part of Google Test's
@@ -372,6 +376,57 @@ TEST_F(TestForDeathTest, FastDeathTestInChangedDir) {
372376
ASSERT_DEATH(_exit(1), "");
373377
}
374378

379+
# if GTEST_OS_LINUX
380+
void SigprofAction(int, siginfo_t*, void*) { /* no op */ }
381+
382+
// Sets SIGPROF action and ITIMER_PROF timer (interval: 1ms).
383+
void SetSigprofActionAndTimer() {
384+
struct itimerval timer;
385+
timer.it_interval.tv_sec = 0;
386+
timer.it_interval.tv_usec = 1;
387+
timer.it_value = timer.it_interval;
388+
ASSERT_EQ(0, setitimer(ITIMER_PROF, &timer, NULL));
389+
struct sigaction signal_action;
390+
memset(&signal_action, 0, sizeof(signal_action));
391+
sigemptyset(&signal_action.sa_mask);
392+
signal_action.sa_sigaction = SigprofAction;
393+
signal_action.sa_flags = SA_RESTART | SA_SIGINFO;
394+
ASSERT_EQ(0, sigaction(SIGPROF, &signal_action, NULL));
395+
}
396+
397+
// Disables ITIMER_PROF timer and ignores SIGPROF signal.
398+
void DisableSigprofActionAndTimer(struct sigaction* old_signal_action) {
399+
struct itimerval timer;
400+
timer.it_interval.tv_usec = 0;
401+
timer.it_value.tv_usec = 0;
402+
ASSERT_EQ(0, setitimer(ITIMER_PROF, &timer, NULL));
403+
struct sigaction signal_action;
404+
memset(&signal_action, 0, sizeof(signal_action));
405+
sigemptyset(&signal_action.sa_mask);
406+
signal_action.sa_handler = SIG_IGN;
407+
ASSERT_EQ(0, sigaction(SIGPROF, &signal_action, old_signal_action));
408+
}
409+
410+
// Tests that death tests work when SIGPROF handler and timer are set.
411+
TEST_F(TestForDeathTest, FastSigprofActionSet) {
412+
testing::GTEST_FLAG(death_test_style) = "fast";
413+
SetSigprofActionAndTimer();
414+
EXPECT_DEATH(_exit(1), "");
415+
struct sigaction old_signal_action;
416+
DisableSigprofActionAndTimer(&old_signal_action);
417+
EXPECT_TRUE(old_signal_action.sa_sigaction == SigprofAction);
418+
}
419+
420+
TEST_F(TestForDeathTest, ThreadSafeSigprofActionSet) {
421+
testing::GTEST_FLAG(death_test_style) = "threadsafe";
422+
SetSigprofActionAndTimer();
423+
EXPECT_DEATH(_exit(1), "");
424+
struct sigaction old_signal_action;
425+
DisableSigprofActionAndTimer(&old_signal_action);
426+
EXPECT_TRUE(old_signal_action.sa_sigaction == SigprofAction);
427+
}
428+
# endif // GTEST_OS_LINUX
429+
375430
// Repeats a representative sample of death tests in the "threadsafe" style:
376431

377432
TEST_F(TestForDeathTest, StaticMemberFunctionThreadsafeStyle) {

0 commit comments

Comments
 (0)