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  }