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