tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

FailureLatch.h (10345B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 // This header contains an interface `FailureLatch`, and some implementation
      8 // helpers that may be used across a range of classes and functions to handle
      9 // failures at any point during a process, and share that failure state so that
     10 // the process may gracefully stop quickly and report the first error.
     11 //
     12 // It could be thought as a replacement for C++ exceptions, but it's less strong
     13 // (cancellations may be delayed).
     14 // Now, if possible, mozilla::Result may be a better option as C++ exceptions
     15 // replacement, as it is more visible in all affected functions.
     16 // Consider FailureLatch if failures may happen in different places, but where
     17 // `return`ing this potential failure from all functions would be too arduous.
     18 
     19 #ifndef mozilla_FailureLatch_h
     20 #define mozilla_FailureLatch_h
     21 
     22 #include <mozilla/Assertions.h>
     23 
     24 #include <string>
     25 
     26 namespace mozilla {
     27 
     28 // ----------------------------------------------------------------------------
     29 // Main interface
     30 // ----------------------------------------------------------------------------
     31 
     32 // Interface handling a failure latch (starting in a successful state, the first
     33 // failure gets recorded, subsequent failures are ignored.)
     34 class FailureLatch {
     35 public:
     36  virtual ~FailureLatch() = default;
     37 
     38  // Can this ever fail? (This may influence how some code deals with
     39  // failures, e.g., if infallible, OOMs should assert&crash.)
     40  [[nodiscard]] virtual bool Fallible() const = 0;
     41 
     42  // Set latch in its failed state because of an external cause.
     43  // The first call sets the reason, subsequent calls are ignored.
     44  virtual void SetFailure(std::string aReason) = 0;
     45 
     46  // Has there been any failure so far?
     47  [[nodiscard]] virtual bool Failed() const = 0;
     48 
     49  // Return first failure string, may be null if not failed yet.
     50  [[nodiscard]] virtual const char* GetFailure() const = 0;
     51 
     52  // Retrieve the one source FailureLatch. It could reference `*this`!
     53  // This may be used by dependent proxy FailureLatch'es to find where to
     54  // redirect calls.
     55  [[nodiscard]] virtual const FailureLatch& SourceFailureLatch() const = 0;
     56  [[nodiscard]] virtual FailureLatch& SourceFailureLatch() = 0;
     57 
     58  // Non-virtual helpers.
     59 
     60  // Transfer any failure from another FailureLatch.
     61  void SetFailureFrom(const FailureLatch& aOther) {
     62    if (Failed()) {
     63      return;
     64    }
     65    if (const char* otherFailure = aOther.GetFailure(); otherFailure) {
     66      SetFailure(otherFailure);
     67    }
     68  }
     69 };
     70 
     71 // ----------------------------------------------------------------------------
     72 // Concrete implementations
     73 // ----------------------------------------------------------------------------
     74 
     75 // Concrete infallible FailureLatch class.
     76 // Any `SetFailure` leads to an assert-crash, so the final runtime result can
     77 // always be assumed to be succesful.
     78 class FailureLatchInfallibleSource final : public FailureLatch {
     79 public:
     80  [[nodiscard]] bool Fallible() const final { return false; }
     81 
     82  void SetFailure(std::string aReason) final {
     83    MOZ_RELEASE_ASSERT(false,
     84                       "SetFailure in infallible FailureLatchInfallibleSource");
     85  }
     86 
     87  [[nodiscard]] bool Failed() const final { return false; }
     88 
     89  [[nodiscard]] const char* GetFailure() const final { return nullptr; }
     90 
     91  [[nodiscard]] const ::mozilla::FailureLatch& SourceFailureLatch()
     92      const final {
     93    return *this;
     94  }
     95 
     96  [[nodiscard]] ::mozilla::FailureLatch& SourceFailureLatch() final {
     97    return *this;
     98  }
     99 
    100  // Singleton FailureLatchInfallibleSource that may be used as default
    101  // FailureLatch proxy.
    102  static FailureLatchInfallibleSource& Singleton() {
    103    static FailureLatchInfallibleSource singleton;
    104    return singleton;
    105  }
    106 };
    107 
    108 // Concrete FailureLatch class, intended to be intantiated as an object shared
    109 // between classes and functions that are part of a long operation, so that
    110 // failures can happen anywhere and be visible everywhere.
    111 // Not thread-safe.
    112 class FailureLatchSource final : public FailureLatch {
    113 public:
    114  [[nodiscard]] bool Fallible() const final { return true; }
    115 
    116  void SetFailure(std::string aReason) final {
    117    if (!mFailed) {
    118      mFailed = true;
    119      mReason = std::move(aReason);
    120    }
    121  }
    122 
    123  [[nodiscard]] bool Failed() const final { return mFailed; }
    124 
    125  [[nodiscard]] const char* GetFailure() const final {
    126    return mFailed ? mReason.c_str() : nullptr;
    127  }
    128 
    129  [[nodiscard]] const FailureLatch& SourceFailureLatch() const final {
    130    return *this;
    131  }
    132 
    133  [[nodiscard]] FailureLatch& SourceFailureLatch() final { return *this; }
    134 
    135 private:
    136  bool mFailed = false;
    137  std::string mReason;
    138 };
    139 
    140 // ----------------------------------------------------------------------------
    141 // Helper macros, to be used in FailureLatch-derived classes
    142 // ----------------------------------------------------------------------------
    143 
    144 // Classes deriving from FailureLatch can use this to forward virtual calls to
    145 // another FailureLatch.
    146 #define FAILURELATCH_IMPL_PROXY(FAILURELATCH_REF)                        \
    147  [[nodiscard]] bool Fallible() const final {                            \
    148    return static_cast<const ::mozilla::FailureLatch&>(FAILURELATCH_REF) \
    149        .Fallible();                                                     \
    150  }                                                                      \
    151  void SetFailure(std::string aReason) final {                           \
    152    static_cast<::mozilla::FailureLatch&>(FAILURELATCH_REF)              \
    153        .SetFailure(std::move(aReason));                                 \
    154  }                                                                      \
    155  [[nodiscard]] bool Failed() const final {                              \
    156    return static_cast<const ::mozilla::FailureLatch&>(FAILURELATCH_REF) \
    157        .Failed();                                                       \
    158  }                                                                      \
    159  [[nodiscard]] const char* GetFailure() const final {                   \
    160    return static_cast<const ::mozilla::FailureLatch&>(FAILURELATCH_REF) \
    161        .GetFailure();                                                   \
    162  }                                                                      \
    163  [[nodiscard]] const FailureLatch& SourceFailureLatch() const final {   \
    164    return static_cast<const ::mozilla::FailureLatch&>(FAILURELATCH_REF) \
    165        .SourceFailureLatch();                                           \
    166  }                                                                      \
    167  [[nodiscard]] FailureLatch& SourceFailureLatch() final {               \
    168    return static_cast<::mozilla::FailureLatch&>(FAILURELATCH_REF)       \
    169        .SourceFailureLatch();                                           \
    170  }
    171 
    172 // Classes deriving from FailureLatch can use this to forward virtual calls to
    173 // another FailureLatch through a pointer, unless it's null in which case act
    174 // like an infallible FailureLatch.
    175 #define FAILURELATCH_IMPL_PROXY_OR_INFALLIBLE(FAILURELATCH_PTR, CLASS_NAME)    \
    176  [[nodiscard]] bool Fallible() const final {                                  \
    177    return FAILURELATCH_PTR                                                    \
    178               ? static_cast<const ::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
    179                     ->Fallible()                                              \
    180               : false;                                                        \
    181  }                                                                            \
    182  void SetFailure(std::string aReason) final {                                 \
    183    if (FAILURELATCH_PTR) {                                                    \
    184      static_cast<::mozilla::FailureLatch*>(FAILURELATCH_PTR)                  \
    185          ->SetFailure(std::move(aReason));                                    \
    186    } else {                                                                   \
    187      MOZ_RELEASE_ASSERT(false, "SetFailure in infallible " #CLASS_NAME);      \
    188    }                                                                          \
    189  }                                                                            \
    190  [[nodiscard]] bool Failed() const final {                                    \
    191    return FAILURELATCH_PTR                                                    \
    192               ? static_cast<const ::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
    193                     ->Failed()                                                \
    194               : false;                                                        \
    195  }                                                                            \
    196  [[nodiscard]] const char* GetFailure() const final {                         \
    197    return FAILURELATCH_PTR                                                    \
    198               ? static_cast<const ::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
    199                     ->GetFailure()                                            \
    200               : nullptr;                                                      \
    201  }                                                                            \
    202  [[nodiscard]] const FailureLatch& SourceFailureLatch() const final {         \
    203    return FAILURELATCH_PTR                                                    \
    204               ? static_cast<const ::mozilla::FailureLatch*>(FAILURELATCH_PTR) \
    205                     ->SourceFailureLatch()                                    \
    206               : ::mozilla::FailureLatchInfallibleSource::Singleton();         \
    207  }                                                                            \
    208  [[nodiscard]] FailureLatch& SourceFailureLatch() final {                     \
    209    return FAILURELATCH_PTR                                                    \
    210               ? static_cast<::mozilla::FailureLatch*>(FAILURELATCH_PTR)       \
    211                     ->SourceFailureLatch()                                    \
    212               : ::mozilla::FailureLatchInfallibleSource::Singleton();         \
    213  }
    214 
    215 }  // namespace mozilla
    216 
    217 #endif /* mozilla_FailureLatch_h */