Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

200 lines
6.2 KiB

  1. //===--- CrashRecoveryContext.h - Crash Recovery ----------------*- C++ -*-===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #ifndef LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
  10. #define LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
  11. #include <string>
  12. namespace llvm {
  13. class StringRef;
  14. class CrashRecoveryContextCleanup;
  15. /// \brief Crash recovery helper object.
  16. ///
  17. /// This class implements support for running operations in a safe context so
  18. /// that crashes (memory errors, stack overflow, assertion violations) can be
  19. /// detected and control restored to the crashing thread. Crash detection is
  20. /// purely "best effort", the exact set of failures which can be recovered from
  21. /// is platform dependent.
  22. ///
  23. /// Clients make use of this code by first calling
  24. /// CrashRecoveryContext::Enable(), and then executing unsafe operations via a
  25. /// CrashRecoveryContext object. For example:
  26. ///
  27. /// void actual_work(void *);
  28. ///
  29. /// void foo() {
  30. /// CrashRecoveryContext CRC;
  31. ///
  32. /// if (!CRC.RunSafely(actual_work, 0)) {
  33. /// ... a crash was detected, report error to user ...
  34. /// }
  35. ///
  36. /// ... no crash was detected ...
  37. /// }
  38. ///
  39. /// Crash recovery contexts may not be nested.
  40. class CrashRecoveryContext {
  41. void *Impl;
  42. CrashRecoveryContextCleanup *head;
  43. public:
  44. CrashRecoveryContext() : Impl(0), head(0) {}
  45. ~CrashRecoveryContext();
  46. void registerCleanup(CrashRecoveryContextCleanup *cleanup);
  47. void unregisterCleanup(CrashRecoveryContextCleanup *cleanup);
  48. /// \brief Enable crash recovery.
  49. static void Enable();
  50. /// \brief Disable crash recovery.
  51. static void Disable();
  52. /// \brief Return the active context, if the code is currently executing in a
  53. /// thread which is in a protected context.
  54. static CrashRecoveryContext *GetCurrent();
  55. /// \brief Return true if the current thread is recovering from a
  56. /// crash.
  57. static bool isRecoveringFromCrash();
  58. /// \brief Execute the provide callback function (with the given arguments) in
  59. /// a protected context.
  60. ///
  61. /// \return True if the function completed successfully, and false if the
  62. /// function crashed (or HandleCrash was called explicitly). Clients should
  63. /// make as little assumptions as possible about the program state when
  64. /// RunSafely has returned false. Clients can use getBacktrace() to retrieve
  65. /// the backtrace of the crash on failures.
  66. bool RunSafely(void (*Fn)(void*), void *UserData);
  67. /// \brief Execute the provide callback function (with the given arguments) in
  68. /// a protected context which is run in another thread (optionally with a
  69. /// requested stack size).
  70. ///
  71. /// See RunSafely() and llvm_execute_on_thread().
  72. bool RunSafelyOnThread(void (*Fn)(void*), void *UserData,
  73. unsigned RequestedStackSize = 0);
  74. /// \brief Explicitly trigger a crash recovery in the current process, and
  75. /// return failure from RunSafely(). This function does not return.
  76. void HandleCrash();
  77. /// \brief Return a string containing the backtrace where the crash was
  78. /// detected; or empty if the backtrace wasn't recovered.
  79. ///
  80. /// This function is only valid when a crash has been detected (i.e.,
  81. /// RunSafely() has returned false.
  82. const std::string &getBacktrace() const;
  83. };
  84. class CrashRecoveryContextCleanup {
  85. protected:
  86. CrashRecoveryContext *context;
  87. CrashRecoveryContextCleanup(CrashRecoveryContext *context)
  88. : context(context), cleanupFired(false) {}
  89. public:
  90. bool cleanupFired;
  91. virtual ~CrashRecoveryContextCleanup();
  92. virtual void recoverResources() = 0;
  93. CrashRecoveryContext *getContext() const {
  94. return context;
  95. }
  96. private:
  97. friend class CrashRecoveryContext;
  98. CrashRecoveryContextCleanup *prev, *next;
  99. };
  100. template<typename DERIVED, typename T>
  101. class CrashRecoveryContextCleanupBase : public CrashRecoveryContextCleanup {
  102. protected:
  103. T *resource;
  104. CrashRecoveryContextCleanupBase(CrashRecoveryContext *context, T* resource)
  105. : CrashRecoveryContextCleanup(context), resource(resource) {}
  106. public:
  107. static DERIVED *create(T *x) {
  108. if (x) {
  109. if (CrashRecoveryContext *context = CrashRecoveryContext::GetCurrent())
  110. return new DERIVED(context, x);
  111. }
  112. return 0;
  113. }
  114. };
  115. template <typename T>
  116. class CrashRecoveryContextDestructorCleanup : public
  117. CrashRecoveryContextCleanupBase<CrashRecoveryContextDestructorCleanup<T>, T> {
  118. public:
  119. CrashRecoveryContextDestructorCleanup(CrashRecoveryContext *context,
  120. T *resource)
  121. : CrashRecoveryContextCleanupBase<
  122. CrashRecoveryContextDestructorCleanup<T>, T>(context, resource) {}
  123. virtual void recoverResources() {
  124. this->resource->~T();
  125. }
  126. };
  127. template <typename T>
  128. class CrashRecoveryContextDeleteCleanup : public
  129. CrashRecoveryContextCleanupBase<CrashRecoveryContextDeleteCleanup<T>, T> {
  130. public:
  131. CrashRecoveryContextDeleteCleanup(CrashRecoveryContext *context, T *resource)
  132. : CrashRecoveryContextCleanupBase<
  133. CrashRecoveryContextDeleteCleanup<T>, T>(context, resource) {}
  134. virtual void recoverResources() {
  135. delete this->resource;
  136. }
  137. };
  138. template <typename T>
  139. class CrashRecoveryContextReleaseRefCleanup : public
  140. CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, T>
  141. {
  142. public:
  143. CrashRecoveryContextReleaseRefCleanup(CrashRecoveryContext *context,
  144. T *resource)
  145. : CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>,
  146. T>(context, resource) {}
  147. virtual void recoverResources() {
  148. this->resource->Release();
  149. }
  150. };
  151. template <typename T, typename Cleanup = CrashRecoveryContextDeleteCleanup<T> >
  152. class CrashRecoveryContextCleanupRegistrar {
  153. CrashRecoveryContextCleanup *cleanup;
  154. public:
  155. CrashRecoveryContextCleanupRegistrar(T *x)
  156. : cleanup(Cleanup::create(x)) {
  157. if (cleanup)
  158. cleanup->getContext()->registerCleanup(cleanup);
  159. }
  160. ~CrashRecoveryContextCleanupRegistrar() {
  161. unregister();
  162. }
  163. void unregister() {
  164. if (cleanup && !cleanup->cleanupFired)
  165. cleanup->getContext()->unregisterCleanup(cleanup);
  166. cleanup = 0;
  167. }
  168. };
  169. }
  170. #endif