gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/clock_nanosleep.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 <time.h>
    16  
    17  #include <atomic>
    18  #include <utility>
    19  
    20  #include "gtest/gtest.h"
    21  #include "absl/time/time.h"
    22  #include "test/util/cleanup.h"
    23  #include "test/util/posix_error.h"
    24  #include "test/util/signal_util.h"
    25  #include "test/util/test_util.h"
    26  #include "test/util/thread_util.h"
    27  #include "test/util/timer_util.h"
    28  
    29  namespace gvisor {
    30  namespace testing {
    31  
    32  namespace {
    33  
    34  // sys_clock_nanosleep is defined because the glibc clock_nanosleep returns
    35  // error numbers directly and does not set errno. This makes our Syscall
    36  // matchers look a little weird when expecting failure:
    37  // "SyscallSucceedsWithValue(ERRNO)".
    38  int sys_clock_nanosleep(clockid_t clkid, int flags,
    39                          const struct timespec* request,
    40                          struct timespec* remain) {
    41    return syscall(SYS_clock_nanosleep, clkid, flags, request, remain);
    42  }
    43  
    44  PosixErrorOr<absl::Time> GetTime(clockid_t clk) {
    45    struct timespec ts = {};
    46    const int rc = clock_gettime(clk, &ts);
    47    MaybeSave();
    48    if (rc < 0) {
    49      return PosixError(errno, "clock_gettime");
    50    }
    51    return absl::TimeFromTimespec(ts);
    52  }
    53  
    54  class WallClockNanosleepTest : public ::testing::TestWithParam<clockid_t> {};
    55  
    56  TEST_P(WallClockNanosleepTest, InvalidValues) {
    57    const struct timespec invalid[] = {
    58        {.tv_sec = -1, .tv_nsec = -1},       {.tv_sec = 0, .tv_nsec = INT32_MIN},
    59        {.tv_sec = 0, .tv_nsec = INT32_MAX}, {.tv_sec = 0, .tv_nsec = -1},
    60        {.tv_sec = -1, .tv_nsec = 0},
    61    };
    62  
    63    for (auto const ts : invalid) {
    64      EXPECT_THAT(sys_clock_nanosleep(GetParam(), 0, &ts, nullptr),
    65                  SyscallFailsWithErrno(EINVAL));
    66    }
    67  }
    68  
    69  TEST_P(WallClockNanosleepTest, SleepOneSecond) {
    70    constexpr absl::Duration kSleepDuration = absl::Seconds(1);
    71    struct timespec duration = absl::ToTimespec(kSleepDuration);
    72  
    73    const absl::Time before = ASSERT_NO_ERRNO_AND_VALUE(GetTime(GetParam()));
    74    EXPECT_THAT(
    75        RetryEINTR(sys_clock_nanosleep)(GetParam(), 0, &duration, &duration),
    76        SyscallSucceeds());
    77    const absl::Time after = ASSERT_NO_ERRNO_AND_VALUE(GetTime(GetParam()));
    78  
    79    EXPECT_GE(after - before, kSleepDuration);
    80  }
    81  
    82  TEST_P(WallClockNanosleepTest, InterruptedNanosleep) {
    83    constexpr absl::Duration kSleepDuration = absl::Seconds(60);
    84    struct timespec duration = absl::ToTimespec(kSleepDuration);
    85  
    86    // Install no-op signal handler for SIGALRM.
    87    struct sigaction sa = {};
    88    sigfillset(&sa.sa_mask);
    89    sa.sa_handler = +[](int signo) {};
    90    const auto cleanup_sa =
    91        ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGALRM, sa));
    92  
    93    // Measure time since setting the alarm, since the alarm will interrupt the
    94    // sleep and hence determine how long we sleep.
    95    const absl::Time before = ASSERT_NO_ERRNO_AND_VALUE(GetTime(GetParam()));
    96  
    97    // Set an alarm to go off while sleeping.
    98    struct itimerval timer = {};
    99    timer.it_value.tv_sec = 1;
   100    timer.it_value.tv_usec = 0;
   101    timer.it_interval.tv_sec = 1;
   102    timer.it_interval.tv_usec = 0;
   103    const auto cleanup =
   104        ASSERT_NO_ERRNO_AND_VALUE(ScopedItimer(ITIMER_REAL, timer));
   105  
   106    EXPECT_THAT(sys_clock_nanosleep(GetParam(), 0, &duration, &duration),
   107                SyscallFailsWithErrno(EINTR));
   108    const absl::Time after = ASSERT_NO_ERRNO_AND_VALUE(GetTime(GetParam()));
   109  
   110    // Remaining time updated.
   111    const absl::Duration remaining = absl::DurationFromTimespec(duration);
   112    EXPECT_GE(after - before + remaining, kSleepDuration);
   113  }
   114  
   115  // Remaining time is *not* updated if nanosleep completes uninterrupted.
   116  TEST_P(WallClockNanosleepTest, UninterruptedNanosleep) {
   117    constexpr absl::Duration kSleepDuration = absl::Milliseconds(10);
   118    const struct timespec duration = absl::ToTimespec(kSleepDuration);
   119  
   120    while (true) {
   121      constexpr int kRemainingMagic = 42;
   122      struct timespec remaining;
   123      remaining.tv_sec = kRemainingMagic;
   124      remaining.tv_nsec = kRemainingMagic;
   125  
   126      int ret = sys_clock_nanosleep(GetParam(), 0, &duration, &remaining);
   127      if (ret == EINTR) {
   128        // Retry from beginning. We want a single uninterrupted call.
   129        continue;
   130      }
   131  
   132      EXPECT_THAT(ret, SyscallSucceeds());
   133      EXPECT_EQ(remaining.tv_sec, kRemainingMagic);
   134      EXPECT_EQ(remaining.tv_nsec, kRemainingMagic);
   135      break;
   136    }
   137  }
   138  
   139  TEST_P(WallClockNanosleepTest, SleepUntil) {
   140    const absl::Time now = ASSERT_NO_ERRNO_AND_VALUE(GetTime(GetParam()));
   141    const absl::Time until = now + absl::Seconds(2);
   142    const struct timespec ts = absl::ToTimespec(until);
   143  
   144    EXPECT_THAT(
   145        RetryEINTR(sys_clock_nanosleep)(GetParam(), TIMER_ABSTIME, &ts, nullptr),
   146        SyscallSucceeds());
   147    const absl::Time after = ASSERT_NO_ERRNO_AND_VALUE(GetTime(GetParam()));
   148  
   149    EXPECT_GE(after, until);
   150  }
   151  
   152  INSTANTIATE_TEST_SUITE_P(Sleepers, WallClockNanosleepTest,
   153                           ::testing::Values(CLOCK_REALTIME, CLOCK_MONOTONIC));
   154  
   155  TEST(ClockNanosleepProcessTest, SleepFiveSeconds) {
   156    const absl::Duration kSleepDuration = absl::Seconds(5);
   157    struct timespec duration = absl::ToTimespec(kSleepDuration);
   158  
   159    // Ensure that CLOCK_PROCESS_CPUTIME_ID advances.
   160    std::atomic<bool> done(false);
   161    ScopedThread t([&] {
   162      while (!done.load()) {
   163      }
   164    });
   165    const auto cleanup_done = Cleanup([&] { done.store(true); });
   166  
   167    const absl::Time before =
   168        ASSERT_NO_ERRNO_AND_VALUE(GetTime(CLOCK_PROCESS_CPUTIME_ID));
   169    EXPECT_THAT(RetryEINTR(sys_clock_nanosleep)(CLOCK_PROCESS_CPUTIME_ID, 0,
   170                                                &duration, &duration),
   171                SyscallSucceeds());
   172    const absl::Time after =
   173        ASSERT_NO_ERRNO_AND_VALUE(GetTime(CLOCK_PROCESS_CPUTIME_ID));
   174    EXPECT_GE(after - before, kSleepDuration);
   175  }
   176  }  // namespace
   177  
   178  }  // namespace testing
   179  }  // namespace gvisor