summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux/timerfd.cc
diff options
context:
space:
mode:
Diffstat (limited to 'test/syscalls/linux/timerfd.cc')
-rw-r--r--test/syscalls/linux/timerfd.cc238
1 files changed, 0 insertions, 238 deletions
diff --git a/test/syscalls/linux/timerfd.cc b/test/syscalls/linux/timerfd.cc
deleted file mode 100644
index 9df53612f..000000000
--- a/test/syscalls/linux/timerfd.cc
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright 2018 The gVisor Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <poll.h>
-#include <sys/timerfd.h>
-#include <time.h>
-
-#include "absl/time/clock.h"
-#include "absl/time/time.h"
-#include "test/util/file_descriptor.h"
-#include "test/util/posix_error.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-// Wrapper around timerfd_create(2) that returns a FileDescriptor.
-PosixErrorOr<FileDescriptor> TimerfdCreate(int clockid, int flags) {
- int fd = timerfd_create(clockid, flags);
- MaybeSave();
- if (fd < 0) {
- return PosixError(errno, "timerfd_create failed");
- }
- return FileDescriptor(fd);
-}
-
-// In tests that race a timerfd with a sleep, some slack is required because:
-//
-// - Timerfd expirations are asynchronous with respect to nanosleeps.
-//
-// - Because clock_gettime(CLOCK_MONOTONIC) is implemented through the VDSO,
-// it technically uses a closely-related, but distinct, time domain from the
-// CLOCK_MONOTONIC used to trigger timerfd expirations.
-absl::Duration TimerSlack() { return absl::Milliseconds(500); }
-
-TEST(TimerfdTest, IsInitiallyStopped) {
- auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(CLOCK_MONOTONIC, 0));
- struct itimerspec its = {};
- ASSERT_THAT(timerfd_gettime(tfd.get(), &its), SyscallSucceeds());
- EXPECT_EQ(0, its.it_value.tv_sec);
- EXPECT_EQ(0, its.it_value.tv_nsec);
-}
-
-TEST(TimerfdTest, SingleShot) {
- constexpr absl::Duration kDelay = absl::Seconds(1);
-
- auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(CLOCK_MONOTONIC, 0));
- struct itimerspec its = {};
- its.it_value = absl::ToTimespec(kDelay);
- ASSERT_THAT(timerfd_settime(tfd.get(), /* flags = */ 0, &its, nullptr),
- SyscallSucceeds());
-
- // The timer should fire exactly once since the interval is zero.
- absl::SleepFor(kDelay + TimerSlack());
- uint64_t val = 0;
- ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)),
- SyscallSucceedsWithValue(sizeof(uint64_t)));
- EXPECT_EQ(1, val);
-}
-
-TEST(TimerfdTest, Periodic) {
- constexpr absl::Duration kDelay = absl::Seconds(1);
- constexpr int kPeriods = 3;
-
- auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(CLOCK_MONOTONIC, 0));
- struct itimerspec its = {};
- its.it_value = absl::ToTimespec(kDelay);
- its.it_interval = absl::ToTimespec(kDelay);
- ASSERT_THAT(timerfd_settime(tfd.get(), /* flags = */ 0, &its, nullptr),
- SyscallSucceeds());
-
- // Expect to see at least kPeriods expirations. More may occur due to the
- // timer slack, or due to delays from scheduling or save/restore.
- absl::SleepFor(kPeriods * kDelay + TimerSlack());
- uint64_t val = 0;
- ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)),
- SyscallSucceedsWithValue(sizeof(uint64_t)));
- EXPECT_GE(val, kPeriods);
-}
-
-TEST(TimerfdTest, BlockingRead) {
- constexpr absl::Duration kDelay = absl::Seconds(3);
-
- auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(CLOCK_MONOTONIC, 0));
- struct itimerspec its = {};
- its.it_value.tv_sec = absl::ToInt64Seconds(kDelay);
- auto const start_time = absl::Now();
- ASSERT_THAT(timerfd_settime(tfd.get(), /* flags = */ 0, &its, nullptr),
- SyscallSucceeds());
-
- // read should block until the timer fires.
- uint64_t val = 0;
- ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)),
- SyscallSucceedsWithValue(sizeof(uint64_t)));
- auto const end_time = absl::Now();
- EXPECT_EQ(1, val);
- EXPECT_GE((end_time - start_time) + TimerSlack(), kDelay);
-}
-
-TEST(TimerfdTest, NonblockingRead_NoRandomSave) {
- constexpr absl::Duration kDelay = absl::Seconds(5);
-
- auto const tfd =
- ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(CLOCK_MONOTONIC, TFD_NONBLOCK));
-
- // Since the timer is initially disabled and has never fired, read should
- // return EAGAIN.
- uint64_t val = 0;
- ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)),
- SyscallFailsWithErrno(EAGAIN));
-
- DisableSave ds; // Timing-sensitive.
-
- // Arm the timer.
- struct itimerspec its = {};
- its.it_value.tv_sec = absl::ToInt64Seconds(kDelay);
- ASSERT_THAT(timerfd_settime(tfd.get(), /* flags = */ 0, &its, nullptr),
- SyscallSucceeds());
-
- // Since the timer has not yet fired, read should return EAGAIN.
- ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)),
- SyscallFailsWithErrno(EAGAIN));
-
- ds.reset(); // No longer timing-sensitive.
-
- // After the timer fires, read should indicate 1 expiration.
- absl::SleepFor(kDelay + TimerSlack());
- ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)),
- SyscallSucceedsWithValue(sizeof(uint64_t)));
- EXPECT_EQ(1, val);
-
- // The successful read should have reset the number of expirations.
- ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)),
- SyscallFailsWithErrno(EAGAIN));
-}
-
-TEST(TimerfdTest, BlockingPoll_SetTimeResetsExpirations) {
- constexpr absl::Duration kDelay = absl::Seconds(3);
-
- auto const tfd =
- ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(CLOCK_MONOTONIC, TFD_NONBLOCK));
- struct itimerspec its = {};
- its.it_value.tv_sec = absl::ToInt64Seconds(kDelay);
- auto const start_time = absl::Now();
- ASSERT_THAT(timerfd_settime(tfd.get(), /* flags = */ 0, &its, nullptr),
- SyscallSucceeds());
-
- // poll should block until the timer fires.
- struct pollfd pfd = {};
- pfd.fd = tfd.get();
- pfd.events = POLLIN;
- ASSERT_THAT(poll(&pfd, /* nfds = */ 1,
- /* timeout = */ 2 * absl::ToInt64Seconds(kDelay) * 1000),
- SyscallSucceedsWithValue(1));
- auto const end_time = absl::Now();
- EXPECT_EQ(POLLIN, pfd.revents);
- EXPECT_GE((end_time - start_time) + TimerSlack(), kDelay);
-
- // Call timerfd_settime again with a value of 0. This should reset the number
- // of expirations to 0, causing read to return EAGAIN since the timerfd is
- // non-blocking.
- its.it_value.tv_sec = 0;
- ASSERT_THAT(timerfd_settime(tfd.get(), /* flags = */ 0, &its, nullptr),
- SyscallSucceeds());
- uint64_t val = 0;
- ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)),
- SyscallFailsWithErrno(EAGAIN));
-}
-
-TEST(TimerfdTest, SetAbsoluteTime) {
- constexpr absl::Duration kDelay = absl::Seconds(3);
-
- // Use a non-blocking timerfd so that if TFD_TIMER_ABSTIME is incorrectly
- // non-functional, we get EAGAIN rather than a test timeout.
- auto const tfd =
- ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(CLOCK_MONOTONIC, TFD_NONBLOCK));
- struct itimerspec its = {};
- ASSERT_THAT(clock_gettime(CLOCK_MONOTONIC, &its.it_value), SyscallSucceeds());
- its.it_value.tv_sec += absl::ToInt64Seconds(kDelay);
- ASSERT_THAT(timerfd_settime(tfd.get(), TFD_TIMER_ABSTIME, &its, nullptr),
- SyscallSucceeds());
-
- absl::SleepFor(kDelay + TimerSlack());
- uint64_t val = 0;
- ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)),
- SyscallSucceedsWithValue(sizeof(uint64_t)));
- EXPECT_EQ(1, val);
-}
-
-TEST(TimerfdTest, ClockRealtime) {
- // Since CLOCK_REALTIME can, by definition, change, we can't make any
- // non-flaky assertions about the amount of time it takes for a
- // CLOCK_REALTIME-based timer to expire. Just check that it expires at all,
- // and hope it happens before the test times out.
- constexpr int kDelaySecs = 1;
-
- auto const tfd = ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(CLOCK_REALTIME, 0));
- struct itimerspec its = {};
- its.it_value.tv_sec = kDelaySecs;
- ASSERT_THAT(timerfd_settime(tfd.get(), /* flags = */ 0, &its, nullptr),
- SyscallSucceeds());
-
- uint64_t val = 0;
- ASSERT_THAT(ReadFd(tfd.get(), &val, sizeof(uint64_t)),
- SyscallSucceedsWithValue(sizeof(uint64_t)));
- EXPECT_EQ(1, val);
-}
-
-TEST(TimerfdTest, IllegalReadWrite) {
- auto const tfd =
- ASSERT_NO_ERRNO_AND_VALUE(TimerfdCreate(CLOCK_MONOTONIC, TFD_NONBLOCK));
- uint64_t val = 0;
- EXPECT_THAT(PreadFd(tfd.get(), &val, sizeof(val), 0),
- SyscallFailsWithErrno(ESPIPE));
- EXPECT_THAT(WriteFd(tfd.get(), &val, sizeof(val)),
- SyscallFailsWithErrno(EINVAL));
- EXPECT_THAT(PwriteFd(tfd.get(), &val, sizeof(val), 0),
- SyscallFailsWithErrno(ESPIPE));
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor