github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/sigstop.cc (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <signal.h> 16 #include <stdlib.h> 17 #include <sys/select.h> 18 19 #include "gtest/gtest.h" 20 #include "absl/flags/flag.h" 21 #include "absl/time/clock.h" 22 #include "absl/time/time.h" 23 #include "test/util/multiprocess_util.h" 24 #include "test/util/posix_error.h" 25 #include "test/util/test_util.h" 26 #include "test/util/thread_util.h" 27 28 ABSL_FLAG(bool, sigstop_test_child, false, 29 "If true, run the SigstopTest child workload."); 30 31 namespace gvisor { 32 namespace testing { 33 34 namespace { 35 36 constexpr absl::Duration kChildStartupDelay = absl::Seconds(5); 37 constexpr absl::Duration kChildMainThreadDelay = absl::Seconds(10); 38 constexpr absl::Duration kChildExtraThreadDelay = absl::Seconds(15); 39 constexpr absl::Duration kPostSIGSTOPDelay = absl::Seconds(20); 40 41 // Comparisons on absl::Duration aren't yet constexpr (2017-07-14), so we 42 // can't just use static_assert. 43 TEST(SigstopTest, TimesAreRelativelyConsistent) { 44 EXPECT_LT(kChildStartupDelay, kChildMainThreadDelay) 45 << "Child process will exit before the parent process attempts to stop " 46 "it"; 47 EXPECT_LT(kChildMainThreadDelay, kChildExtraThreadDelay) 48 << "Secondary thread in child process will exit before main thread, " 49 "causing it to exit with the wrong code"; 50 EXPECT_LT(kChildExtraThreadDelay, kPostSIGSTOPDelay) 51 << "Parent process stops waiting before child process may exit if " 52 "improperly stopped, rendering the test ineffective"; 53 } 54 55 // Exit codes communicated from the child workload to the parent test process. 56 constexpr int kChildMainThreadExitCode = 10; 57 constexpr int kChildExtraThreadExitCode = 11; 58 59 TEST(SigstopTest, Correctness) { 60 pid_t child_pid = -1; 61 int execve_errno = 0; 62 auto cleanup = ASSERT_NO_ERRNO_AND_VALUE( 63 ForkAndExec("/proc/self/exe", {"/proc/self/exe", "--sigstop_test_child"}, 64 {}, nullptr, &child_pid, &execve_errno)); 65 66 ASSERT_GT(child_pid, 0); 67 ASSERT_EQ(execve_errno, 0); 68 69 // Wait for the child subprocess to start the second thread before stopping 70 // it. 71 absl::SleepFor(kChildStartupDelay); 72 ASSERT_THAT(kill(child_pid, SIGSTOP), SyscallSucceeds()); 73 int status; 74 EXPECT_THAT(RetryEINTR(waitpid)(child_pid, &status, WUNTRACED), 75 SyscallSucceedsWithValue(child_pid)); 76 EXPECT_TRUE(WIFSTOPPED(status)); 77 EXPECT_EQ(SIGSTOP, WSTOPSIG(status)); 78 79 // Sleep for longer than either of the sleeps in the child subprocess, 80 // expecting the child to stay alive because it's stopped. 81 absl::SleepFor(kPostSIGSTOPDelay); 82 ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, WNOHANG), 83 SyscallSucceedsWithValue(0)); 84 85 // Resume the child. 86 ASSERT_THAT(kill(child_pid, SIGCONT), SyscallSucceeds()); 87 88 EXPECT_THAT(RetryEINTR(waitpid)(child_pid, &status, WCONTINUED), 89 SyscallSucceedsWithValue(child_pid)); 90 EXPECT_TRUE(WIFCONTINUED(status)); 91 92 // Expect it to die. 93 ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0), SyscallSucceeds()); 94 ASSERT_TRUE(WIFEXITED(status)); 95 ASSERT_EQ(WEXITSTATUS(status), kChildMainThreadExitCode); 96 } 97 98 // Like base:SleepFor, but tries to avoid counting time spent stopped due to a 99 // stop signal toward the sleep. 100 // 101 // This is required due to an inconsistency in how nanosleep(2) and stop signals 102 // interact on Linux. When nanosleep is interrupted, it writes the remaining 103 // time back to its second timespec argument, so that if nanosleep is 104 // interrupted by a signal handler then userspace can immediately call nanosleep 105 // again with that timespec. However, if nanosleep is automatically restarted 106 // (because it's interrupted by a signal that is not delivered to a handler, 107 // such as a stop signal), it's restarted based on the timer's former *absolute* 108 // expiration time (via ERESTART_RESTARTBLOCK => SYS_restart_syscall => 109 // hrtimer_nanosleep_restart). This means that time spent stopped is effectively 110 // counted as time spent sleeping, resulting in less time spent sleeping than 111 // expected. 112 // 113 // Dividing the sleep into multiple smaller sleeps limits the impact of this 114 // effect to the length of each sleep during which a stop occurs; for example, 115 // if a sleeping process is only stopped once, SleepIgnoreStopped can 116 // under-sleep by at most 100ms. 117 void SleepIgnoreStopped(absl::Duration d) { 118 absl::Duration const max_sleep = absl::Milliseconds(100); 119 while (d > absl::ZeroDuration()) { 120 absl::Duration to_sleep = std::min(d, max_sleep); 121 absl::SleepFor(to_sleep); 122 d -= to_sleep; 123 } 124 } 125 126 TEST(SigstopTest, RestartSyscall) { 127 pid_t pid; 128 constexpr absl::Duration kStopDelay = absl::Seconds(5); 129 constexpr absl::Duration kSleepDelay = absl::Seconds(15); 130 constexpr absl::Duration kStartupDelay = absl::Seconds(5); 131 constexpr absl::Duration kErrorDelay = absl::Seconds(3); 132 133 const DisableSave ds; // Timing-related. 134 135 pid = fork(); 136 if (pid == 0) { 137 struct timespec ts = {.tv_sec = kSleepDelay / absl::Seconds(1)}; 138 auto start = absl::Now(); 139 TEST_CHECK(nanosleep(&ts, nullptr) == 0); 140 auto finish = absl::Now(); 141 // Check that time spent stopped is counted as time spent sleeping. 142 TEST_CHECK(finish - start >= kSleepDelay); 143 TEST_CHECK(finish - start < kSleepDelay + kErrorDelay); 144 _exit(kChildMainThreadExitCode); 145 } 146 ASSERT_THAT(pid, SyscallSucceeds()); 147 148 // Wait for the child subprocess to start sleeping before stopping it. 149 absl::SleepFor(kStartupDelay); 150 ASSERT_THAT(kill(pid, SIGSTOP), SyscallSucceeds()); 151 int status; 152 EXPECT_THAT(RetryEINTR(waitpid)(pid, &status, WUNTRACED), 153 SyscallSucceedsWithValue(pid)); 154 EXPECT_TRUE(WIFSTOPPED(status)); 155 EXPECT_EQ(SIGSTOP, WSTOPSIG(status)); 156 157 // Sleep for shorter than the sleep in the child subprocess. 158 absl::SleepFor(kStopDelay); 159 ASSERT_THAT(RetryEINTR(waitpid)(pid, &status, WNOHANG), 160 SyscallSucceedsWithValue(0)); 161 162 // Resume the child. 163 ASSERT_THAT(kill(pid, SIGCONT), SyscallSucceeds()); 164 165 EXPECT_THAT(RetryEINTR(waitpid)(pid, &status, WCONTINUED), 166 SyscallSucceedsWithValue(pid)); 167 EXPECT_TRUE(WIFCONTINUED(status)); 168 169 // Expect it to die. 170 ASSERT_THAT(RetryEINTR(waitpid)(pid, &status, 0), SyscallSucceeds()); 171 ASSERT_TRUE(WIFEXITED(status)); 172 ASSERT_EQ(WEXITSTATUS(status), kChildMainThreadExitCode); 173 } 174 175 void RunChild() { 176 // Start another thread that attempts to call exit_group with a different 177 // error code, in order to verify that SIGSTOP stops this thread as well. 178 ScopedThread t([] { 179 SleepIgnoreStopped(kChildExtraThreadDelay); 180 exit(kChildExtraThreadExitCode); 181 }); 182 SleepIgnoreStopped(kChildMainThreadDelay); 183 exit(kChildMainThreadExitCode); 184 } 185 186 } // namespace 187 188 } // namespace testing 189 } // namespace gvisor 190 191 int main(int argc, char** argv) { 192 gvisor::testing::TestInit(&argc, &argv); 193 194 if (absl::GetFlag(FLAGS_sigstop_test_child)) { 195 gvisor::testing::RunChild(); 196 return 1; 197 } 198 199 return gvisor::testing::RunAllTests(); 200 }