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).
This commit is contained in:
parent
294f69f957
commit
4b07d73f4e
@ -43,6 +43,11 @@
|
|||||||
# include <errno.h>
|
# include <errno.h>
|
||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
# include <limits.h>
|
# include <limits.h>
|
||||||
|
|
||||||
|
# if GTEST_OS_LINUX
|
||||||
|
# include <signal.h>
|
||||||
|
# endif // GTEST_OS_LINUX
|
||||||
|
|
||||||
# include <stdarg.h>
|
# include <stdarg.h>
|
||||||
|
|
||||||
# if GTEST_OS_WINDOWS
|
# 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));
|
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));
|
||||||
|
|
||||||
# else // GTEST_OS_QNX
|
# 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
|
# if GTEST_HAS_CLONE
|
||||||
const bool use_fork = GTEST_FLAG(death_test_use_fork);
|
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);
|
_exit(0);
|
||||||
}
|
}
|
||||||
# endif // GTEST_OS_QNX
|
# 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);
|
GTEST_DEATH_TEST_CHECK_(child_pid != -1);
|
||||||
return child_pid;
|
return child_pid;
|
||||||
|
@ -52,6 +52,10 @@ using testing::internal::AlwaysTrue;
|
|||||||
# include <signal.h>
|
# include <signal.h>
|
||||||
# include <stdio.h>
|
# include <stdio.h>
|
||||||
|
|
||||||
|
# if GTEST_OS_LINUX
|
||||||
|
# include <sys/time.h>
|
||||||
|
# endif // GTEST_OS_LINUX
|
||||||
|
|
||||||
# include "gtest/gtest-spi.h"
|
# include "gtest/gtest-spi.h"
|
||||||
|
|
||||||
// Indicates that this translation unit is part of Google Test's
|
// Indicates that this translation unit is part of Google Test's
|
||||||
@ -372,6 +376,57 @@ TEST_F(TestForDeathTest, FastDeathTestInChangedDir) {
|
|||||||
ASSERT_DEATH(_exit(1), "");
|
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:
|
// Repeats a representative sample of death tests in the "threadsafe" style:
|
||||||
|
|
||||||
TEST_F(TestForDeathTest, StaticMemberFunctionThreadsafeStyle) {
|
TEST_F(TestForDeathTest, StaticMemberFunctionThreadsafeStyle) {
|
||||||
|
Loading…
Reference in New Issue
Block a user