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