gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/timerfd.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 <errno.h> 16 #include <poll.h> 17 #include <sys/timerfd.h> 18 #include <time.h> 19 20 #include "absl/time/clock.h" 21 #include "absl/time/time.h" 22 #include "test/util/file_descriptor.h" 23 #include "test/util/posix_error.h" 24 #include "test/util/test_util.h" 25 26 namespace gvisor { 27 namespace testing { 28 29 namespace { 30 31 // Wrapper around timerfd_create(2) that returns a FileDescriptor. 32 PosixErrorOr<FileDescriptor> TimerfdCreate(int clockid, int flags) { 33 int fd = timerfd_create(clockid, flags); 34 MaybeSave(); 35 if (fd < 0) { 36 return PosixError(errno, "timerfd_create failed"); 37 } 38 return FileDescriptor(fd); 39 } 40 41 // In tests that race a timerfd with a sleep, some slack is required because: 42 // 43 // - Timerfd expirations are asynchronous with respect to nanosleeps. 44 // 45 // - Because clock_gettime(CLOCK_MONOTONIC) is implemented through the VDSO, 46 // it technically uses a closely-related, but distinct, time domain from the 47 // CLOCK_MONOTONIC used to trigger timerfd expirations. The same applies to 48 // CLOCK_BOOTTIME which is an alias for CLOCK_MONOTONIC. 49 absl::Duration TimerSlack() { return absl::Milliseconds(500); } 50 51 class TimerfdTest : public ::testing::TestWithParam<int> {}; 52 53 TEST_P(TimerfdTest, IsInitiallyStopped) { 54 auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), 0)); 55 struct itimerspec its = {}; 56 ASSERT_THAT(timerfd_gettime(tfd.get(), &its), SyscallSucceeds()); 57 EXPECT_EQ(0, its.it_value.tv_sec); 58 EXPECT_EQ(0, its.it_value.tv_nsec); 59 } 60 61 TEST_P(TimerfdTest, SingleShot) { 62 constexpr absl::Duration kDelay = absl::Seconds(1); 63 64 auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), 0)); 65 struct itimerspec its = {}; 66 its.it_value = absl::ToTimespec(kDelay); 67 ASSERT_THAT(timerfd_settime(tfd.get(), /* flags = */ 0, &its, nullptr), 68 SyscallSucceeds()); 69 70 // The timer should fire exactly once since the interval is zero. 71 absl::SleepFor(kDelay + TimerSlack()); 72 uint64_t val = 0; 73 ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)), 74 SyscallSucceedsWithValue(sizeof(uint64_t))); 75 EXPECT_EQ(1, val); 76 } 77 78 TEST_P(TimerfdTest, Periodic) { 79 constexpr absl::Duration kDelay = absl::Seconds(1); 80 constexpr int kPeriods = 3; 81 82 auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), 0)); 83 struct itimerspec its = {}; 84 its.it_value = absl::ToTimespec(kDelay); 85 its.it_interval = absl::ToTimespec(kDelay); 86 ASSERT_THAT(timerfd_settime(tfd.get(), /* flags = */ 0, &its, nullptr), 87 SyscallSucceeds()); 88 89 // Expect to see at least kPeriods expirations. More may occur due to the 90 // timer slack, or due to delays from scheduling or save/restore. 91 absl::SleepFor(kPeriods * kDelay + TimerSlack()); 92 uint64_t val = 0; 93 ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)), 94 SyscallSucceedsWithValue(sizeof(uint64_t))); 95 EXPECT_GE(val, kPeriods); 96 } 97 98 TEST_P(TimerfdTest, BlockingRead) { 99 constexpr absl::Duration kDelay = absl::Seconds(3); 100 101 auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), 0)); 102 struct itimerspec its = {}; 103 its.it_value.tv_sec = absl::ToInt64Seconds(kDelay); 104 auto const start_time = absl::Now(); 105 ASSERT_THAT(timerfd_settime(tfd.get(), /* flags = */ 0, &its, nullptr), 106 SyscallSucceeds()); 107 108 // read should block until the timer fires. 109 uint64_t val = 0; 110 ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)), 111 SyscallSucceedsWithValue(sizeof(uint64_t))); 112 auto const end_time = absl::Now(); 113 EXPECT_EQ(1, val); 114 EXPECT_GE((end_time - start_time) + TimerSlack(), kDelay); 115 } 116 117 TEST_P(TimerfdTest, NonblockingRead) { 118 constexpr absl::Duration kDelay = absl::Seconds(5); 119 120 auto const tfd = 121 ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), TFD_NONBLOCK)); 122 123 // Since the timer is initially disabled and has never fired, read should 124 // return EAGAIN. 125 uint64_t val = 0; 126 ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)), 127 SyscallFailsWithErrno(EAGAIN)); 128 129 DisableSave ds; // Timing-sensitive. 130 131 // Arm the timer. 132 struct itimerspec its = {}; 133 its.it_value.tv_sec = absl::ToInt64Seconds(kDelay); 134 ASSERT_THAT(timerfd_settime(tfd.get(), /* flags = */ 0, &its, nullptr), 135 SyscallSucceeds()); 136 137 // Since the timer has not yet fired, read should return EAGAIN. 138 ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)), 139 SyscallFailsWithErrno(EAGAIN)); 140 141 ds.reset(); // No longer timing-sensitive. 142 143 // After the timer fires, read should indicate 1 expiration. 144 absl::SleepFor(kDelay + TimerSlack()); 145 ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)), 146 SyscallSucceedsWithValue(sizeof(uint64_t))); 147 EXPECT_EQ(1, val); 148 149 // The successful read should have reset the number of expirations. 150 ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)), 151 SyscallFailsWithErrno(EAGAIN)); 152 } 153 154 TEST_P(TimerfdTest, BlockingPoll_SetTimeResetsExpirations) { 155 constexpr absl::Duration kDelay = absl::Seconds(3); 156 157 auto const tfd = 158 ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), TFD_NONBLOCK)); 159 struct itimerspec its = {}; 160 its.it_value.tv_sec = absl::ToInt64Seconds(kDelay); 161 auto const start_time = absl::Now(); 162 ASSERT_THAT(timerfd_settime(tfd.get(), /* flags = */ 0, &its, nullptr), 163 SyscallSucceeds()); 164 165 // poll should block until the timer fires. 166 struct pollfd pfd = {}; 167 pfd.fd = tfd.get(); 168 pfd.events = POLLIN; 169 ASSERT_THAT(poll(&pfd, /* nfds = */ 1, 170 /* timeout = */ 2 * absl::ToInt64Seconds(kDelay) * 1000), 171 SyscallSucceedsWithValue(1)); 172 auto const end_time = absl::Now(); 173 EXPECT_EQ(POLLIN, pfd.revents); 174 EXPECT_GE((end_time - start_time) + TimerSlack(), kDelay); 175 176 // Call timerfd_settime again with a value of 0. This should reset the number 177 // of expirations to 0, causing read to return EAGAIN since the timerfd is 178 // non-blocking. 179 its.it_value.tv_sec = 0; 180 ASSERT_THAT(timerfd_settime(tfd.get(), /* flags = */ 0, &its, nullptr), 181 SyscallSucceeds()); 182 uint64_t val = 0; 183 ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)), 184 SyscallFailsWithErrno(EAGAIN)); 185 } 186 187 TEST_P(TimerfdTest, SetAbsoluteTime) { 188 constexpr absl::Duration kDelay = absl::Seconds(3); 189 190 // Use a non-blocking timerfd so that if TFD_TIMER_ABSTIME is incorrectly 191 // non-functional, we get EAGAIN rather than a test timeout. 192 auto const tfd = 193 ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), TFD_NONBLOCK)); 194 struct itimerspec its = {}; 195 ASSERT_THAT(clock_gettime(GetParam(), &its.it_value), SyscallSucceeds()); 196 its.it_value.tv_sec += absl::ToInt64Seconds(kDelay); 197 ASSERT_THAT(timerfd_settime(tfd.get(), TFD_TIMER_ABSTIME, &its, nullptr), 198 SyscallSucceeds()); 199 200 absl::SleepFor(kDelay + TimerSlack()); 201 uint64_t val = 0; 202 ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)), 203 SyscallSucceedsWithValue(sizeof(uint64_t))); 204 EXPECT_EQ(1, val); 205 } 206 207 TEST_P(TimerfdTest, SetToPastExpiresEventually) { 208 auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), 0)); 209 struct itimerspec its = {}; 210 its.it_value.tv_nsec = 1; 211 ASSERT_THAT(timerfd_settime(tfd.get(), TFD_TIMER_ABSTIME, &its, nullptr), 212 SyscallSucceeds()); 213 214 uint64_t val = 0; 215 ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)), 216 SyscallSucceedsWithValue(sizeof(uint64_t))); 217 ASSERT_EQ(val, 1); 218 } 219 220 TEST_P(TimerfdTest, IllegalSeek) { 221 // TODO: b/298787679 - this test fails on 6.0+ kernels. 222 SKIP_IF(!IsRunningOnGvisor()); 223 224 auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), 0)); 225 EXPECT_THAT(lseek(tfd.get(), 0, SEEK_SET), SyscallFailsWithErrno(ESPIPE)); 226 } 227 228 TEST_P(TimerfdTest, IllegalPread) { 229 auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), 0)); 230 int val; 231 EXPECT_THAT(pread(tfd.get(), &val, sizeof(val), 0), 232 SyscallFailsWithErrno(ESPIPE)); 233 } 234 235 TEST_P(TimerfdTest, IllegalPwrite) { 236 auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), 0)); 237 EXPECT_THAT(pwrite(tfd.get(), "x", 1, 0), SyscallFailsWithErrno(ESPIPE)); 238 } 239 240 TEST_P(TimerfdTest, IllegalWrite) { 241 auto const tfd = 242 ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), TFD_NONBLOCK)); 243 uint64_t val = 0; 244 EXPECT_THAT(write(tfd.get(), &val, sizeof(val)), 245 SyscallFailsWithErrno(EINVAL)); 246 } 247 248 std::string PrintClockId(::testing::TestParamInfo<int> info) { 249 switch (info.param) { 250 case CLOCK_MONOTONIC: 251 return "CLOCK_MONOTONIC"; 252 case CLOCK_BOOTTIME: 253 return "CLOCK_BOOTTIME"; 254 default: 255 return absl::StrCat(info.param); 256 } 257 } 258 259 INSTANTIATE_TEST_SUITE_P(AllTimerTypes, TimerfdTest, 260 ::testing::Values(CLOCK_MONOTONIC, CLOCK_BOOTTIME), 261 PrintClockId); 262 263 TEST(TimerfdClockRealtimeTest, ClockRealtime) { 264 // Since CLOCK_REALTIME can, by definition, change, we can't make any 265 // non-flaky assertions about the amount of time it takes for a 266 // CLOCK_REALTIME-based timer to expire. Just check that it expires at all, 267 // and hope it happens before the test times out. 268 constexpr int kDelaySecs = 1; 269 270 auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(CLOCK_REALTIME, 0)); 271 struct itimerspec its = {}; 272 its.it_value.tv_sec = kDelaySecs; 273 ASSERT_THAT(timerfd_settime(tfd.get(), /* flags = */ 0, &its, nullptr), 274 SyscallSucceeds()); 275 276 uint64_t val = 0; 277 ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)), 278 SyscallSucceedsWithValue(sizeof(uint64_t))); 279 EXPECT_EQ(1, val); 280 } 281 282 // Same as the above ClockRealtime test but expresses the input as an absolute 283 // time value rather than an interval. 284 TEST(TimerfdClockRealtimeTest, ClockAbsoluteRealtime) { 285 constexpr int kDelaySecs = 1; 286 287 struct itimerspec its = {}; 288 ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &its.it_value)); 289 its.it_value.tv_sec += kDelaySecs; 290 291 auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(CLOCK_REALTIME, 0)); 292 ASSERT_THAT(timerfd_settime(tfd.get(), TFD_TIMER_ABSTIME, &its, nullptr), 293 SyscallSucceeds()); 294 295 uint64_t val = 0; 296 ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)), 297 SyscallSucceedsWithValue(sizeof(uint64_t))); 298 EXPECT_EQ(1, val); 299 } 300 301 } // namespace 302 303 } // namespace testing 304 } // namespace gvisor