summaryrefslogtreecommitdiffhomepage
path: root/test/util
diff options
context:
space:
mode:
authorDean Deng <deandeng@google.com>2020-10-16 14:30:19 -0700
committergVisor bot <gvisor-bot@google.com>2020-10-16 14:32:49 -0700
commit4ddb58f6efb3b0bfcce40f8d126973701db89c4b (patch)
tree4d9f4f2586b8c49a49bc9ba660c0d2efee188ea3 /test/util
parentdffa4c66909f034429e933f204cd49655c3e224f (diff)
Use POSIX interval timers in flock test.
ualarm(2) is obsolete. Move IntervalTimer into a test util, where it can be used by flock tests. These tests were flaky with TSAN, probably because it slowed the tests down enough that the alarm was expiring before flock() was called. Use an interval timer so that even if we miss the first alarm (or more), flock() is still guaranteed to be interrupted. PiperOrigin-RevId: 337578751
Diffstat (limited to 'test/util')
-rw-r--r--test/util/save_util_linux.cc2
-rw-r--r--test/util/timer_util.cc18
-rw-r--r--test/util/timer_util.h94
3 files changed, 111 insertions, 3 deletions
diff --git a/test/util/save_util_linux.cc b/test/util/save_util_linux.cc
index d0aea8e6a..fbac94912 100644
--- a/test/util/save_util_linux.cc
+++ b/test/util/save_util_linux.cc
@@ -46,4 +46,4 @@ void MaybeSave() {
} // namespace testing
} // namespace gvisor
-#endif
+#endif // __linux__
diff --git a/test/util/timer_util.cc b/test/util/timer_util.cc
index 43a26b0d3..75cfc4f40 100644
--- a/test/util/timer_util.cc
+++ b/test/util/timer_util.cc
@@ -23,5 +23,23 @@ absl::Time Now(clockid_t id) {
return absl::TimeFromTimespec(now);
}
+#ifdef __linux__
+
+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);
+}
+
+#endif // __linux__
+
} // namespace testing
} // namespace gvisor
diff --git a/test/util/timer_util.h b/test/util/timer_util.h
index 31aea4fc6..926e6632f 100644
--- a/test/util/timer_util.h
+++ b/test/util/timer_util.h
@@ -16,6 +16,9 @@
#define GVISOR_TEST_UTIL_TIMER_UTIL_H_
#include <errno.h>
+#ifdef __linux__
+#include <sys/syscall.h>
+#endif
#include <sys/time.h>
#include <functional>
@@ -30,6 +33,9 @@
namespace gvisor {
namespace testing {
+// Returns the current time.
+absl::Time Now(clockid_t id);
+
// MonotonicTimer is a simple timer that uses a monotonic clock.
class MonotonicTimer {
public:
@@ -65,8 +71,92 @@ inline PosixErrorOr<Cleanup> ScopedItimer(int which,
}));
}
-// Returns the current time.
-absl::Time Now(clockid_t id);
+#ifdef __linux__
+
+// 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;
+};
+
+// A wrapper around timer_create(2).
+PosixErrorOr<IntervalTimer> TimerCreate(clockid_t clockid,
+ const struct sigevent& sev);
+
+#endif // __linux__
} // namespace testing
} // namespace gvisor