Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //===--- CrashRecoveryContext.h - Crash Recovery ----------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8.  
  9. #ifndef LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
  10. #define LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
  11.  
  12. #include "llvm/ADT/STLFunctionalExtras.h"
  13.  
  14. namespace llvm {
  15. class CrashRecoveryContextCleanup;
  16.  
  17. /// Crash recovery helper object.
  18. ///
  19. /// This class implements support for running operations in a safe context so
  20. /// that crashes (memory errors, stack overflow, assertion violations) can be
  21. /// detected and control restored to the crashing thread. Crash detection is
  22. /// purely "best effort", the exact set of failures which can be recovered from
  23. /// is platform dependent.
  24. ///
  25. /// Clients make use of this code by first calling
  26. /// CrashRecoveryContext::Enable(), and then executing unsafe operations via a
  27. /// CrashRecoveryContext object. For example:
  28. ///
  29. /// \code
  30. ///    void actual_work(void *);
  31. ///
  32. ///    void foo() {
  33. ///      CrashRecoveryContext CRC;
  34. ///
  35. ///      if (!CRC.RunSafely(actual_work, 0)) {
  36. ///         ... a crash was detected, report error to user ...
  37. ///      }
  38. ///
  39. ///      ... no crash was detected ...
  40. ///    }
  41. /// \endcode
  42. ///
  43. /// To assist recovery the class allows specifying set of actions that will be
  44. /// executed in any case, whether crash occurs or not. These actions may be used
  45. /// to reclaim resources in the case of crash.
  46. class CrashRecoveryContext {
  47.   void *Impl = nullptr;
  48.   CrashRecoveryContextCleanup *head = nullptr;
  49.  
  50. public:
  51.   CrashRecoveryContext();
  52.   ~CrashRecoveryContext();
  53.  
  54.   /// Register cleanup handler, which is used when the recovery context is
  55.   /// finished.
  56.   /// The recovery context owns the handler.
  57.   void registerCleanup(CrashRecoveryContextCleanup *cleanup);
  58.  
  59.   void unregisterCleanup(CrashRecoveryContextCleanup *cleanup);
  60.  
  61.   /// Enable crash recovery.
  62.   static void Enable();
  63.  
  64.   /// Disable crash recovery.
  65.   static void Disable();
  66.  
  67.   /// Return the active context, if the code is currently executing in a
  68.   /// thread which is in a protected context.
  69.   static CrashRecoveryContext *GetCurrent();
  70.  
  71.   /// Return true if the current thread is recovering from a crash.
  72.   static bool isRecoveringFromCrash();
  73.  
  74.   /// Execute the provided callback function (with the given arguments) in
  75.   /// a protected context.
  76.   ///
  77.   /// \return True if the function completed successfully, and false if the
  78.   /// function crashed (or HandleCrash was called explicitly). Clients should
  79.   /// make as little assumptions as possible about the program state when
  80.   /// RunSafely has returned false.
  81.   bool RunSafely(function_ref<void()> Fn);
  82.   bool RunSafely(void (*Fn)(void*), void *UserData) {
  83.     return RunSafely([&]() { Fn(UserData); });
  84.   }
  85.  
  86.   /// Execute the provide callback function (with the given arguments) in
  87.   /// a protected context which is run in another thread (optionally with a
  88.   /// requested stack size).
  89.   ///
  90.   /// See RunSafely().
  91.   ///
  92.   /// On Darwin, if PRIO_DARWIN_BG is set on the calling thread, it will be
  93.   /// propagated to the new thread as well.
  94.   bool RunSafelyOnThread(function_ref<void()>, unsigned RequestedStackSize = 0);
  95.   bool RunSafelyOnThread(void (*Fn)(void*), void *UserData,
  96.                          unsigned RequestedStackSize = 0) {
  97.     return RunSafelyOnThread([&]() { Fn(UserData); }, RequestedStackSize);
  98.   }
  99.  
  100.   /// Explicitly trigger a crash recovery in the current process, and
  101.   /// return failure from RunSafely(). This function does not return.
  102.   [[noreturn]] void HandleExit(int RetCode);
  103.  
  104.   /// Return true if RetCode indicates that a signal or an exception occurred.
  105.   static bool isCrash(int RetCode);
  106.  
  107.   /// Throw again a signal or an exception, after it was catched once by a
  108.   /// CrashRecoveryContext.
  109.   static bool throwIfCrash(int RetCode);
  110.  
  111.   /// In case of a crash, this is the crash identifier.
  112.   int RetCode = 0;
  113.  
  114.   /// Selects whether handling of failures should be done in the same way as
  115.   /// for regular crashes. When this is active, a crash would print the
  116.   /// callstack, clean-up any temporary files and create a coredump/minidump.
  117.   bool DumpStackAndCleanupOnFailure = false;
  118. };
  119.  
  120. /// Abstract base class of cleanup handlers.
  121. ///
  122. /// Derived classes override method recoverResources, which makes actual work on
  123. /// resource recovery.
  124. ///
  125. /// Cleanup handlers are stored in a double list, which is owned and managed by
  126. /// a crash recovery context.
  127. class CrashRecoveryContextCleanup {
  128. protected:
  129.   CrashRecoveryContext *context = nullptr;
  130.   CrashRecoveryContextCleanup(CrashRecoveryContext *context)
  131.       : context(context) {}
  132.  
  133. public:
  134.   bool cleanupFired = false;
  135.  
  136.   virtual ~CrashRecoveryContextCleanup();
  137.   virtual void recoverResources() = 0;
  138.  
  139.   CrashRecoveryContext *getContext() const {
  140.     return context;
  141.   }
  142.  
  143. private:
  144.   friend class CrashRecoveryContext;
  145.   CrashRecoveryContextCleanup *prev = nullptr, *next = nullptr;
  146. };
  147.  
  148. /// Base class of cleanup handler that controls recovery of resources of the
  149. /// given type.
  150. ///
  151. /// \tparam Derived Class that uses this class as a base.
  152. /// \tparam T Type of controlled resource.
  153. ///
  154. /// This class serves as a base for its template parameter as implied by
  155. /// Curiously Recurring Template Pattern.
  156. ///
  157. /// This class factors out creation of a cleanup handler. The latter requires
  158. /// knowledge of the current recovery context, which is provided by this class.
  159. template<typename Derived, typename T>
  160. class CrashRecoveryContextCleanupBase : public CrashRecoveryContextCleanup {
  161. protected:
  162.   T *resource;
  163.   CrashRecoveryContextCleanupBase(CrashRecoveryContext *context, T *resource)
  164.       : CrashRecoveryContextCleanup(context), resource(resource) {}
  165.  
  166. public:
  167.   /// Creates cleanup handler.
  168.   /// \param x Pointer to the resource recovered by this handler.
  169.   /// \return New handler or null if the method was called outside a recovery
  170.   ///         context.
  171.   static Derived *create(T *x) {
  172.     if (x) {
  173.       if (CrashRecoveryContext *context = CrashRecoveryContext::GetCurrent())
  174.         return new Derived(context, x);
  175.     }
  176.     return nullptr;
  177.   }
  178. };
  179.  
  180. /// Cleanup handler that reclaims resource by calling destructor on it.
  181. template <typename T>
  182. class CrashRecoveryContextDestructorCleanup : public
  183.   CrashRecoveryContextCleanupBase<CrashRecoveryContextDestructorCleanup<T>, T> {
  184. public:
  185.   CrashRecoveryContextDestructorCleanup(CrashRecoveryContext *context,
  186.                                         T *resource)
  187.       : CrashRecoveryContextCleanupBase<
  188.             CrashRecoveryContextDestructorCleanup<T>, T>(context, resource) {}
  189.  
  190.   void recoverResources() override {
  191.     this->resource->~T();
  192.   }
  193. };
  194.  
  195. /// Cleanup handler that reclaims resource by calling 'delete' on it.
  196. template <typename T>
  197. class CrashRecoveryContextDeleteCleanup : public
  198.   CrashRecoveryContextCleanupBase<CrashRecoveryContextDeleteCleanup<T>, T> {
  199. public:
  200.   CrashRecoveryContextDeleteCleanup(CrashRecoveryContext *context, T *resource)
  201.     : CrashRecoveryContextCleanupBase<
  202.         CrashRecoveryContextDeleteCleanup<T>, T>(context, resource) {}
  203.  
  204.   void recoverResources() override { delete this->resource; }
  205. };
  206.  
  207. /// Cleanup handler that reclaims resource by calling its method 'Release'.
  208. template <typename T>
  209. class CrashRecoveryContextReleaseRefCleanup : public
  210.   CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, T> {
  211. public:
  212.   CrashRecoveryContextReleaseRefCleanup(CrashRecoveryContext *context,
  213.                                         T *resource)
  214.     : CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>,
  215.           T>(context, resource) {}
  216.  
  217.   void recoverResources() override { this->resource->Release(); }
  218. };
  219.  
  220. /// Helper class for managing resource cleanups.
  221. ///
  222. /// \tparam T Type of resource been reclaimed.
  223. /// \tparam Cleanup Class that defines how the resource is reclaimed.
  224. ///
  225. /// Clients create objects of this type in the code executed in a crash recovery
  226. /// context to ensure that the resource will be reclaimed even in the case of
  227. /// crash. For example:
  228. ///
  229. /// \code
  230. ///    void actual_work(void *) {
  231. ///      ...
  232. ///      std::unique_ptr<Resource> R(new Resource());
  233. ///      CrashRecoveryContextCleanupRegistrar D(R.get());
  234. ///      ...
  235. ///    }
  236. ///
  237. ///    void foo() {
  238. ///      CrashRecoveryContext CRC;
  239. ///
  240. ///      if (!CRC.RunSafely(actual_work, 0)) {
  241. ///         ... a crash was detected, report error to user ...
  242. ///      }
  243. /// \endcode
  244. ///
  245. /// If the code of `actual_work` in the example above does not crash, the
  246. /// destructor of CrashRecoveryContextCleanupRegistrar removes cleanup code from
  247. /// the current CrashRecoveryContext and the resource is reclaimed by the
  248. /// destructor of std::unique_ptr. If crash happens, destructors are not called
  249. /// and the resource is reclaimed by cleanup object registered in the recovery
  250. /// context by the constructor of CrashRecoveryContextCleanupRegistrar.
  251. template <typename T, typename Cleanup = CrashRecoveryContextDeleteCleanup<T> >
  252. class CrashRecoveryContextCleanupRegistrar {
  253.   CrashRecoveryContextCleanup *cleanup;
  254.  
  255. public:
  256.   CrashRecoveryContextCleanupRegistrar(T *x)
  257.     : cleanup(Cleanup::create(x)) {
  258.     if (cleanup)
  259.       cleanup->getContext()->registerCleanup(cleanup);
  260.   }
  261.  
  262.   ~CrashRecoveryContextCleanupRegistrar() { unregister(); }
  263.  
  264.   void unregister() {
  265.     if (cleanup && !cleanup->cleanupFired)
  266.       cleanup->getContext()->unregisterCleanup(cleanup);
  267.     cleanup = nullptr;
  268.   }
  269. };
  270. } // end namespace llvm
  271.  
  272. #endif // LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
  273.