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