summaryrefslogtreecommitdiffhomepage
path: root/test/util
diff options
context:
space:
mode:
Diffstat (limited to 'test/util')
-rw-r--r--test/util/BUILD4
-rw-r--r--test/util/posix_error.cc2
-rw-r--r--test/util/posix_error.h34
-rw-r--r--test/util/save_util.cc52
-rw-r--r--test/util/save_util.h20
-rw-r--r--test/util/save_util_linux.cc24
-rw-r--r--test/util/save_util_other.cc8
-rw-r--r--test/util/timer_util.cc18
-rw-r--r--test/util/timer_util.h94
9 files changed, 181 insertions, 75 deletions
diff --git a/test/util/BUILD b/test/util/BUILD
index 26c2b6a2f..1b028a477 100644
--- a/test/util/BUILD
+++ b/test/util/BUILD
@@ -155,6 +155,10 @@ cc_library(
],
hdrs = ["save_util.h"],
defines = select_system(),
+ deps = [
+ ":logging",
+ "@com_google_absl//absl/types:optional",
+ ],
)
cc_library(
diff --git a/test/util/posix_error.cc b/test/util/posix_error.cc
index cebf7e0ac..deed0c05b 100644
--- a/test/util/posix_error.cc
+++ b/test/util/posix_error.cc
@@ -87,7 +87,7 @@ bool PosixErrorIsMatcherCommonImpl::MatchAndExplain(
return false;
}
- if (!message_matcher_.Matches(error.error_message())) {
+ if (!message_matcher_.Matches(error.message())) {
return false;
}
diff --git a/test/util/posix_error.h b/test/util/posix_error.h
index ad666bce0..b634a7f78 100644
--- a/test/util/posix_error.h
+++ b/test/util/posix_error.h
@@ -26,11 +26,6 @@
namespace gvisor {
namespace testing {
-class PosixErrorIsMatcherCommonImpl;
-
-template <typename T>
-class PosixErrorOr;
-
class ABSL_MUST_USE_RESULT PosixError {
public:
PosixError() {}
@@ -49,7 +44,8 @@ class ABSL_MUST_USE_RESULT PosixError {
// PosixErrorOr.
const PosixError& error() const { return *this; }
- std::string error_message() const { return msg_; }
+ int errno_value() const { return errno_; }
+ std::string message() const { return msg_; }
// ToString produces a full string representation of this posix error
// including the printable representation of the errno and the error message.
@@ -61,14 +57,8 @@ class ABSL_MUST_USE_RESULT PosixError {
void IgnoreError() const {}
private:
- int errno_value() const { return errno_; }
int errno_ = 0;
std::string msg_;
-
- friend class PosixErrorIsMatcherCommonImpl;
-
- template <typename T>
- friend class PosixErrorOr;
};
template <typename T>
@@ -94,15 +84,12 @@ class ABSL_MUST_USE_RESULT PosixErrorOr {
template <typename U>
PosixErrorOr& operator=(PosixErrorOr<U> other);
- // Return a reference to the error or NoError().
- PosixError error() const;
-
- // Returns this->error().error_message();
- std::string error_message() const;
-
// Returns true if this PosixErrorOr contains some T.
bool ok() const;
+ // Return a copy of the contained PosixError or NoError().
+ PosixError error() const;
+
// Returns a reference to our current value, or CHECK-fails if !this->ok().
const T& ValueOrDie() const&;
T& ValueOrDie() &;
@@ -115,7 +102,6 @@ class ABSL_MUST_USE_RESULT PosixErrorOr {
void IgnoreError() const {}
private:
- int errno_value() const;
absl::variant<T, PosixError> value_;
friend class PosixErrorIsMatcherCommonImpl;
@@ -171,16 +157,6 @@ PosixError PosixErrorOr<T>::error() const {
}
template <typename T>
-int PosixErrorOr<T>::errno_value() const {
- return error().errno_value();
-}
-
-template <typename T>
-std::string PosixErrorOr<T>::error_message() const {
- return error().error_message();
-}
-
-template <typename T>
bool PosixErrorOr<T>::ok() const {
return absl::holds_alternative<T>(value_);
}
diff --git a/test/util/save_util.cc b/test/util/save_util.cc
index 384d626f0..59d47e06e 100644
--- a/test/util/save_util.cc
+++ b/test/util/save_util.cc
@@ -21,35 +21,47 @@
#include <atomic>
#include <cerrno>
-#define GVISOR_COOPERATIVE_SAVE_TEST "GVISOR_COOPERATIVE_SAVE_TEST"
+#include "absl/types/optional.h"
namespace gvisor {
namespace testing {
namespace {
-enum class CooperativeSaveMode {
- kUnknown = 0, // cooperative_save_mode is statically-initialized to 0
- kAvailable,
- kNotAvailable,
-};
-
-std::atomic<CooperativeSaveMode> cooperative_save_mode;
-
-bool CooperativeSaveEnabled() {
- auto mode = cooperative_save_mode.load();
- if (mode == CooperativeSaveMode::kUnknown) {
- mode = (getenv(GVISOR_COOPERATIVE_SAVE_TEST) != nullptr)
- ? CooperativeSaveMode::kAvailable
- : CooperativeSaveMode::kNotAvailable;
- cooperative_save_mode.store(mode);
+std::atomic<absl::optional<bool>> cooperative_save_present;
+std::atomic<absl::optional<bool>> random_save_present;
+
+bool CooperativeSavePresent() {
+ auto present = cooperative_save_present.load();
+ if (!present.has_value()) {
+ present = getenv("GVISOR_COOPERATIVE_SAVE_TEST") != nullptr;
+ cooperative_save_present.store(present);
+ }
+ return present.value();
+}
+
+bool RandomSavePresent() {
+ auto present = random_save_present.load();
+ if (!present.has_value()) {
+ present = getenv("GVISOR_RANDOM_SAVE_TEST") != nullptr;
+ random_save_present.store(present);
}
- return mode == CooperativeSaveMode::kAvailable;
+ return present.value();
}
std::atomic<int> save_disable;
} // namespace
+bool IsRunningWithSaveRestore() {
+ return CooperativeSavePresent() || RandomSavePresent();
+}
+
+void MaybeSave() {
+ if (CooperativeSavePresent() && save_disable.load() == 0) {
+ internal::DoCooperativeSave();
+ }
+}
+
DisableSave::DisableSave() { save_disable++; }
DisableSave::~DisableSave() { reset(); }
@@ -61,11 +73,5 @@ void DisableSave::reset() {
}
}
-namespace internal {
-bool ShouldSave() {
- return CooperativeSaveEnabled() && (save_disable.load() == 0);
-}
-} // namespace internal
-
} // namespace testing
} // namespace gvisor
diff --git a/test/util/save_util.h b/test/util/save_util.h
index bddad6120..e7218ae88 100644
--- a/test/util/save_util.h
+++ b/test/util/save_util.h
@@ -17,9 +17,17 @@
namespace gvisor {
namespace testing {
-// Disable save prevents saving while the given function executes.
+
+// Returns true if the environment in which the calling process is executing
+// allows the test to be checkpointed and restored during execution.
+bool IsRunningWithSaveRestore();
+
+// May perform a co-operative save cycle.
//
-// This lasts the duration of the object, unless reset is called.
+// errno is guaranteed to be preserved.
+void MaybeSave();
+
+// Causes MaybeSave to become a no-op until destroyed or reset.
class DisableSave {
public:
DisableSave();
@@ -37,13 +45,13 @@ class DisableSave {
bool reset_ = false;
};
-// May perform a co-operative save cycle.
+namespace internal {
+
+// Causes a co-operative save cycle to occur.
//
// errno is guaranteed to be preserved.
-void MaybeSave();
+void DoCooperativeSave();
-namespace internal {
-bool ShouldSave();
} // namespace internal
} // namespace testing
diff --git a/test/util/save_util_linux.cc b/test/util/save_util_linux.cc
index d0aea8e6a..57431b3ea 100644
--- a/test/util/save_util_linux.cc
+++ b/test/util/save_util_linux.cc
@@ -30,20 +30,20 @@
namespace gvisor {
namespace testing {
-
-void MaybeSave() {
- if (internal::ShouldSave()) {
- int orig_errno = errno;
- // We use it to trigger saving the sentry state
- // when this syscall is called.
- // Notice: this needs to be a valid syscall
- // that is not used in any of the syscall tests.
- syscall(SYS_TRIGGER_SAVE, nullptr, 0);
- errno = orig_errno;
- }
+namespace internal {
+
+void DoCooperativeSave() {
+ int orig_errno = errno;
+ // We use it to trigger saving the sentry state
+ // when this syscall is called.
+ // Notice: this needs to be a valid syscall
+ // that is not used in any of the syscall tests.
+ syscall(SYS_TRIGGER_SAVE, nullptr, 0);
+ errno = orig_errno;
}
+} // namespace internal
} // namespace testing
} // namespace gvisor
-#endif
+#endif // __linux__
diff --git a/test/util/save_util_other.cc b/test/util/save_util_other.cc
index 931af2c29..7749ded76 100644
--- a/test/util/save_util_other.cc
+++ b/test/util/save_util_other.cc
@@ -14,13 +14,17 @@
#ifndef __linux__
+#include "test/util/logging.h"
+
namespace gvisor {
namespace testing {
+namespace internal {
-void MaybeSave() {
- // Saving is never available in a non-linux environment.
+void DoCooperativeSave() {
+ TEST_CHECK_MSG(false, "DoCooperativeSave not implemented");
}
+} // namespace internal
} // namespace testing
} // namespace gvisor
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