summaryrefslogtreecommitdiffstats
path: root/mozglue/baseprofiler/public/FailureLatch.h
diff options
context:
space:
mode:
Diffstat (limited to 'mozglue/baseprofiler/public/FailureLatch.h')
-rw-r--r--mozglue/baseprofiler/public/FailureLatch.h217
1 files changed, 217 insertions, 0 deletions
diff --git a/mozglue/baseprofiler/public/FailureLatch.h b/mozglue/baseprofiler/public/FailureLatch.h
new file mode 100644
index 0000000000..10205e009b
--- /dev/null
+++ b/mozglue/baseprofiler/public/FailureLatch.h
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// This header contains an interface `FailureLatch`, and some implementation
+// helpers that may be used across a range of classes and functions to handle
+// failures at any point during a process, and share that failure state so that
+// the process may gracefully stop quickly and report the first error.
+//
+// It could be thought as a replacement for C++ exceptions, but it's less strong
+// (cancellations may be delayed).
+// Now, if possible, mozilla::Result may be a better option as C++ exceptions
+// replacement, as it is more visible in all affected functions.
+// Consider FailureLatch if failures may happen in different places, but where
+// `return`ing this potential failure from all functions would be too arduous.
+
+#ifndef mozilla_FailureLatch_h
+#define mozilla_FailureLatch_h
+
+#include <mozilla/Assertions.h>
+
+#include <string>
+
+namespace mozilla {
+
+// ----------------------------------------------------------------------------
+// Main interface
+// ----------------------------------------------------------------------------
+
+// Interface handling a failure latch (starting in a successful state, the first
+// failure gets recorded, subsequent failures are ignored.)
+class FailureLatch {
+ public:
+ virtual ~FailureLatch() = default;
+
+ // Can this ever fail? (This may influence how some code deals with
+ // failures, e.g., if infallible, OOMs should assert&crash.)
+ [[nodiscard]] virtual bool Fallible() const = 0;
+
+ // Set latch in its failed state because of an external cause.
+ // The first call sets the reason, subsequent calls are ignored.
+ virtual void SetFailure(std::string aReason) = 0;
+
+ // Has there been any failure so far?
+ [[nodiscard]] virtual bool Failed() const = 0;
+
+ // Return first failure string, may be null if not failed yet.
+ [[nodiscard]] virtual const char* GetFailure() const = 0;
+
+ // Retrieve the one source FailureLatch. It could reference `*this`!
+ // This may be used by dependent proxy FailureLatch'es to find where to
+ // redirect calls.
+ [[nodiscard]] virtual const FailureLatch& SourceFailureLatch() const = 0;
+ [[nodiscard]] virtual FailureLatch& SourceFailureLatch() = 0;
+
+ // Non-virtual helpers.
+
+ // Transfer any failure from another FailureLatch.
+ void SetFailureFrom(const FailureLatch& aOther) {
+ if (Failed()) {
+ return;
+ }
+ if (const char* otherFailure = aOther.GetFailure(); otherFailure) {
+ SetFailure(otherFailure);
+ }
+ }
+};
+
+// ----------------------------------------------------------------------------
+// Concrete implementations
+// ----------------------------------------------------------------------------
+
+// Concrete infallible FailureLatch class.
+// Any `SetFailure` leads to an assert-crash, so the final runtime result can
+// always be assumed to be succesful.
+class FailureLatchInfallibleSource final : public FailureLatch {
+ public:
+ [[nodiscard]] bool Fallible() const final { return false; }
+
+ void SetFailure(std::string aReason) final {
+ MOZ_RELEASE_ASSERT(false,
+ "SetFailure in infallible FailureLatchInfallibleSource");
+ }
+
+ [[nodiscard]] bool Failed() const final { return false; }
+
+ [[nodiscard]] const char* GetFailure() const final { return nullptr; }
+
+ [[nodiscard]] const ::mozilla::FailureLatch& SourceFailureLatch()
+ const final {
+ return *this;
+ }
+
+ [[nodiscard]] ::mozilla::FailureLatch& SourceFailureLatch() final {
+ return *this;
+ }
+
+ // Singleton FailureLatchInfallibleSource that may be used as default
+ // FailureLatch proxy.
+ static FailureLatchInfallibleSource& Singleton() {
+ static FailureLatchInfallibleSource singleton;
+ return singleton;
+ }
+};
+
+// Concrete FailureLatch class, intended to be intantiated as an object shared
+// between classes and functions that are part of a long operation, so that
+// failures can happen anywhere and be visible everywhere.
+// Not thread-safe.
+class FailureLatchSource final : public FailureLatch {
+ public:
+ [[nodiscard]] bool Fallible() const final { return true; }
+
+ void SetFailure(std::string aReason) final {
+ if (!mFailed) {
+ mFailed = true;
+ mReason = std::move(aReason);
+ }
+ }
+
+ [[nodiscard]] bool Failed() const final { return mFailed; }
+
+ [[nodiscard]] const char* GetFailure() const final {
+ return mFailed ? mReason.c_str() : nullptr;
+ }
+
+ [[nodiscard]] const FailureLatch& SourceFailureLatch() const final {
+ return *this;
+ }
+
+ [[nodiscard]] FailureLatch& SourceFailureLatch() final { return *this; }
+
+ private:
+ bool mFailed = false;
+ std::string mReason;
+};
+
+// ----------------------------------------------------------------------------
+// Helper macros, to be used in FailureLatch-derived classes
+// ----------------------------------------------------------------------------
+
+// Classes deriving from FailureLatch can use this to forward virtual calls to
+// another FailureLatch.
+#define FAILURELATCH_IMPL_PROXY(FAILURELATCH_REF) \
+ [[nodiscard]] bool Fallible() const final { \
+ return static_cast<const ::mozilla::FailureLatch&>(FAILURELATCH_REF) \
+ .Fallible(); \
+ } \
+ void SetFailure(std::string aReason) final { \
+ static_cast<::mozilla::FailureLatch&>(FAILURELATCH_REF) \
+ .SetFailure(std::move(aReason)); \
+ } \
+ [[nodiscard]] bool Failed() const final { \
+ return static_cast<const ::mozilla::FailureLatch&>(FAILURELATCH_REF) \
+ .Failed(); \
+ } \
+ [[nodiscard]] const char* GetFailure() const final { \
+ return static_cast<const ::mozilla::FailureLatch&>(FAILURELATCH_REF) \
+ .GetFailure(); \
+ } \
+ [[nodiscard]] const FailureLatch& SourceFailureLatch() const final { \
+ return static_cast<const ::mozilla::FailureLatch&>(FAILURELATCH_REF) \
+ .SourceFailureLatch(); \
+ } \
+ [[nodiscard]] FailureLatch& SourceFailureLatch() final { \
+ return static_cast<::mozilla::FailureLatch&>(FAILURELATCH_REF) \
+ .SourceFailureLatch(); \
+ }
+
+// Classes deriving from FailureLatch can use this to forward virtual calls to
+// another FailureLatch through a pointer, unless it's null in which case act
+// like an infallible FailureLatch.
+#define FAILURELATCH_IMPL_PROXY_OR_INFALLIBLE(FAILURELATCH_PTR, CLASS_NAME) \
+ [[nodiscard]] bool Fallible() const final { \
+ return FAILURELATCH_PTR \
+ ? static_cast<const ::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
+ ->Fallible() \
+ : false; \
+ } \
+ void SetFailure(std::string aReason) final { \
+ if (FAILURELATCH_PTR) { \
+ static_cast<::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
+ ->SetFailure(std::move(aReason)); \
+ } else { \
+ MOZ_RELEASE_ASSERT(false, "SetFailure in infallible " #CLASS_NAME); \
+ } \
+ } \
+ [[nodiscard]] bool Failed() const final { \
+ return FAILURELATCH_PTR \
+ ? static_cast<const ::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
+ ->Failed() \
+ : false; \
+ } \
+ [[nodiscard]] const char* GetFailure() const final { \
+ return FAILURELATCH_PTR \
+ ? static_cast<const ::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
+ ->GetFailure() \
+ : nullptr; \
+ } \
+ [[nodiscard]] const FailureLatch& SourceFailureLatch() const final { \
+ return FAILURELATCH_PTR \
+ ? static_cast<const ::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
+ ->SourceFailureLatch() \
+ : ::mozilla::FailureLatchInfallibleSource::Singleton(); \
+ } \
+ [[nodiscard]] FailureLatch& SourceFailureLatch() final { \
+ return FAILURELATCH_PTR \
+ ? static_cast<::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
+ ->SourceFailureLatch() \
+ : ::mozilla::FailureLatchInfallibleSource::Singleton(); \
+ }
+
+} // namespace mozilla
+
+#endif /* mozilla_FailureLatch_h */