summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux
diff options
context:
space:
mode:
Diffstat (limited to 'test/syscalls/linux')
-rw-r--r--test/syscalls/linux/BUILD1
-rw-r--r--test/syscalls/linux/flock.cc46
-rw-r--r--test/syscalls/linux/timers.cc94
3 files changed, 40 insertions, 101 deletions
diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD
index 36b7f1b97..572f39a5d 100644
--- a/test/syscalls/linux/BUILD
+++ b/test/syscalls/linux/BUILD
@@ -3624,6 +3624,7 @@ cc_binary(
"//test/util:signal_util",
"//test/util:test_util",
"//test/util:thread_util",
+ "//test/util:timer_util",
],
)
diff --git a/test/syscalls/linux/flock.cc b/test/syscalls/linux/flock.cc
index 549141cbb..b286e84fe 100644
--- a/test/syscalls/linux/flock.cc
+++ b/test/syscalls/linux/flock.cc
@@ -216,14 +216,29 @@ TEST_F(FlockTest, TestSharedLockFailExclusiveHolderBlocking_NoRandomSave) {
const FileDescriptor fd =
ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
- // Register a signal handler for SIGALRM and set an alarm that will go off
- // while blocking in the subsequent flock() call. This will interrupt flock()
- // and cause it to return EINTR.
+ // Make sure that a blocking flock() call will return EINTR when interrupted
+ // by a signal. Create a timer that will go off while blocking on flock(), and
+ // register the corresponding signal handler.
+ auto timer = ASSERT_NO_ERRNO_AND_VALUE(
+ TimerCreate(CLOCK_MONOTONIC, sigevent_t{
+ .sigev_signo = SIGALRM,
+ .sigev_notify = SIGEV_SIGNAL,
+ }));
+
struct sigaction act = {};
act.sa_handler = trivial_handler;
ASSERT_THAT(sigaction(SIGALRM, &act, NULL), SyscallSucceeds());
- ASSERT_THAT(ualarm(10000, 0), SyscallSucceeds());
+
+ // Now that the signal handler is registered, set the timer. Set an interval
+ // so that it's ok if the timer goes off before we call flock.
+ ASSERT_NO_ERRNO(
+ timer.Set(0, itimerspec{
+ .it_interval = absl::ToTimespec(absl::Milliseconds(10)),
+ .it_value = absl::ToTimespec(absl::Milliseconds(10)),
+ }));
+
ASSERT_THAT(flock(fd.get(), LOCK_SH), SyscallFailsWithErrno(EINTR));
+ timer.reset();
// Unlock
ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
@@ -258,14 +273,29 @@ TEST_F(FlockTest, TestExclusiveLockFailExclusiveHolderBlocking_NoRandomSave) {
const FileDescriptor fd =
ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
- // Register a signal handler for SIGALRM and set an alarm that will go off
- // while blocking in the subsequent flock() call. This will interrupt flock()
- // and cause it to return EINTR.
+ // Make sure that a blocking flock() call will return EINTR when interrupted
+ // by a signal. Create a timer that will go off while blocking on flock(), and
+ // register the corresponding signal handler.
+ auto timer = ASSERT_NO_ERRNO_AND_VALUE(
+ TimerCreate(CLOCK_MONOTONIC, sigevent_t{
+ .sigev_signo = SIGALRM,
+ .sigev_notify = SIGEV_SIGNAL,
+ }));
+
struct sigaction act = {};
act.sa_handler = trivial_handler;
ASSERT_THAT(sigaction(SIGALRM, &act, NULL), SyscallSucceeds());
- ASSERT_THAT(ualarm(10000, 0), SyscallSucceeds());
+
+ // Now that the signal handler is registered, set the timer. Set an interval
+ // so that it's ok if the timer goes off before we call flock.
+ ASSERT_NO_ERRNO(
+ timer.Set(0, itimerspec{
+ .it_interval = absl::ToTimespec(absl::Milliseconds(10)),
+ .it_value = absl::ToTimespec(absl::Milliseconds(10)),
+ }));
+
ASSERT_THAT(flock(fd.get(), LOCK_EX), SyscallFailsWithErrno(EINTR));
+ timer.reset();
// Unlock
ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
diff --git a/test/syscalls/linux/timers.cc b/test/syscalls/linux/timers.cc
index 4b3c44527..cac94d9e1 100644
--- a/test/syscalls/linux/timers.cc
+++ b/test/syscalls/linux/timers.cc
@@ -33,6 +33,7 @@
#include "test/util/signal_util.h"
#include "test/util/test_util.h"
#include "test/util/thread_util.h"
+#include "test/util/timer_util.h"
ABSL_FLAG(bool, timers_test_sleep, false,
"If true, sleep forever instead of running tests.");
@@ -215,99 +216,6 @@ TEST(TimerTest, ProcessKilledOnCPUHardLimit) {
EXPECT_GE(cpu, kHardLimit);
}
-// RAII type for a kernel "POSIX" interval timer. (The kernel provides system
-// calls such as timer_create that behave very similarly, but not identically,
-// to those described by timer_create(2); in particular, the kernel does not
-// implement SIGEV_THREAD. glibc builds POSIX-compliant interval timers based on
-// these kernel interval timers.)
-//
-// Compare implementation to FileDescriptor.
-class IntervalTimer {
- public:
- IntervalTimer() = default;
-
- explicit IntervalTimer(int id) { set_id(id); }
-
- IntervalTimer(IntervalTimer&& orig) : id_(orig.release()) {}
-
- IntervalTimer& operator=(IntervalTimer&& orig) {
- if (this == &orig) return *this;
- reset(orig.release());
- return *this;
- }
-
- IntervalTimer(const IntervalTimer& other) = delete;
- IntervalTimer& operator=(const IntervalTimer& other) = delete;
-
- ~IntervalTimer() { reset(); }
-
- int get() const { return id_; }
-
- int release() {
- int const id = id_;
- id_ = -1;
- return id;
- }
-
- void reset() { reset(-1); }
-
- void reset(int id) {
- if (id_ >= 0) {
- TEST_PCHECK(syscall(SYS_timer_delete, id_) == 0);
- MaybeSave();
- }
- set_id(id);
- }
-
- PosixErrorOr<struct itimerspec> Set(
- int flags, const struct itimerspec& new_value) const {
- struct itimerspec old_value = {};
- if (syscall(SYS_timer_settime, id_, flags, &new_value, &old_value) < 0) {
- return PosixError(errno, "timer_settime");
- }
- MaybeSave();
- return old_value;
- }
-
- PosixErrorOr<struct itimerspec> Get() const {
- struct itimerspec curr_value = {};
- if (syscall(SYS_timer_gettime, id_, &curr_value) < 0) {
- return PosixError(errno, "timer_gettime");
- }
- MaybeSave();
- return curr_value;
- }
-
- PosixErrorOr<int> Overruns() const {
- int rv = syscall(SYS_timer_getoverrun, id_);
- if (rv < 0) {
- return PosixError(errno, "timer_getoverrun");
- }
- MaybeSave();
- return rv;
- }
-
- private:
- void set_id(int id) { id_ = std::max(id, -1); }
-
- // Kernel timer_t is int; glibc timer_t is void*.
- int id_ = -1;
-};
-
-PosixErrorOr<IntervalTimer> TimerCreate(clockid_t clockid,
- const struct sigevent& sev) {
- int timerid;
- int ret = syscall(SYS_timer_create, clockid, &sev, &timerid);
- if (ret < 0) {
- return PosixError(errno, "timer_create");
- }
- if (ret > 0) {
- return PosixError(EINVAL, "timer_create should never return positive");
- }
- MaybeSave();
- return IntervalTimer(timerid);
-}
-
// See timerfd.cc:TimerSlack() for rationale.
constexpr absl::Duration kTimerSlack = absl::Milliseconds(500);