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  }