github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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, IllegalSeek) { 208 auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), 0)); 209 if (!IsRunningWithVFS1()) { 210 EXPECT_THAT(lseek(tfd.get(), 0, SEEK_SET), SyscallFailsWithErrno(ESPIPE)); 211 } 212 } 213 214 TEST_P(TimerfdTest, IllegalPread) { 215 auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), 0)); 216 int val; 217 EXPECT_THAT(pread(tfd.get(), &val, sizeof(val), 0), 218 SyscallFailsWithErrno(ESPIPE)); 219 } 220 221 TEST_P(TimerfdTest, IllegalPwrite) { 222 auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), 0)); 223 EXPECT_THAT(pwrite(tfd.get(), "x", 1, 0), SyscallFailsWithErrno(ESPIPE)); 224 if (!IsRunningWithVFS1()) { 225 } 226 } 227 228 TEST_P(TimerfdTest, IllegalWrite) { 229 auto const tfd = 230 ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(GetParam(), TFD_NONBLOCK)); 231 uint64_t val = 0; 232 EXPECT_THAT(write(tfd.get(), &val, sizeof(val)), 233 SyscallFailsWithErrno(EINVAL)); 234 } 235 236 std::string PrintClockId(::testing::TestParamInfo<int> info) { 237 switch (info.param) { 238 case CLOCK_MONOTONIC: 239 return "CLOCK_MONOTONIC"; 240 case CLOCK_BOOTTIME: 241 return "CLOCK_BOOTTIME"; 242 default: 243 return absl::StrCat(info.param); 244 } 245 } 246 247 INSTANTIATE_TEST_SUITE_P(AllTimerTypes, TimerfdTest, 248 ::testing::Values(CLOCK_MONOTONIC, CLOCK_BOOTTIME), 249 PrintClockId); 250 251 TEST(TimerfdClockRealtimeTest, ClockRealtime) { 252 // Since CLOCK_REALTIME can, by definition, change, we can't make any 253 // non-flaky assertions about the amount of time it takes for a 254 // CLOCK_REALTIME-based timer to expire. Just check that it expires at all, 255 // and hope it happens before the test times out. 256 constexpr int kDelaySecs = 1; 257 258 auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(CLOCK_REALTIME, 0)); 259 struct itimerspec its = {}; 260 its.it_value.tv_sec = kDelaySecs; 261 ASSERT_THAT(timerfd_settime(tfd.get(), /* flags = */ 0, &its, nullptr), 262 SyscallSucceeds()); 263 264 uint64_t val = 0; 265 ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)), 266 SyscallSucceedsWithValue(sizeof(uint64_t))); 267 EXPECT_EQ(1, val); 268 } 269 270 } // namespace 271 272 } // namespace testing 273 } // namespace gvisor