LLVM API Documentation
00001 //===--- CrashRecoveryContext.h - Crash Recovery ----------------*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 00010 #ifndef LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H 00011 #define LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H 00012 00013 #include <string> 00014 00015 #include "llvm/ADT/STLExtras.h" 00016 00017 namespace llvm { 00018 class StringRef; 00019 00020 class CrashRecoveryContextCleanup; 00021 00022 /// \brief Crash recovery helper object. 00023 /// 00024 /// This class implements support for running operations in a safe context so 00025 /// that crashes (memory errors, stack overflow, assertion violations) can be 00026 /// detected and control restored to the crashing thread. Crash detection is 00027 /// purely "best effort", the exact set of failures which can be recovered from 00028 /// is platform dependent. 00029 /// 00030 /// Clients make use of this code by first calling 00031 /// CrashRecoveryContext::Enable(), and then executing unsafe operations via a 00032 /// CrashRecoveryContext object. For example: 00033 /// 00034 /// void actual_work(void *); 00035 /// 00036 /// void foo() { 00037 /// CrashRecoveryContext CRC; 00038 /// 00039 /// if (!CRC.RunSafely(actual_work, 0)) { 00040 /// ... a crash was detected, report error to user ... 00041 /// } 00042 /// 00043 /// ... no crash was detected ... 00044 /// } 00045 /// 00046 /// Crash recovery contexts may not be nested. 00047 class CrashRecoveryContext { 00048 void *Impl; 00049 CrashRecoveryContextCleanup *head; 00050 00051 public: 00052 CrashRecoveryContext() : Impl(nullptr), head(nullptr) {} 00053 ~CrashRecoveryContext(); 00054 00055 void registerCleanup(CrashRecoveryContextCleanup *cleanup); 00056 void unregisterCleanup(CrashRecoveryContextCleanup *cleanup); 00057 00058 /// \brief Enable crash recovery. 00059 static void Enable(); 00060 00061 /// \brief Disable crash recovery. 00062 static void Disable(); 00063 00064 /// \brief Return the active context, if the code is currently executing in a 00065 /// thread which is in a protected context. 00066 static CrashRecoveryContext *GetCurrent(); 00067 00068 /// \brief Return true if the current thread is recovering from a 00069 /// crash. 00070 static bool isRecoveringFromCrash(); 00071 00072 /// \brief Execute the provide callback function (with the given arguments) in 00073 /// a protected context. 00074 /// 00075 /// \return True if the function completed successfully, and false if the 00076 /// function crashed (or HandleCrash was called explicitly). Clients should 00077 /// make as little assumptions as possible about the program state when 00078 /// RunSafely has returned false. Clients can use getBacktrace() to retrieve 00079 /// the backtrace of the crash on failures. 00080 bool RunSafely(function_ref<void()> Fn); 00081 bool RunSafely(void (*Fn)(void*), void *UserData) { 00082 return RunSafely([&]() { Fn(UserData); }); 00083 } 00084 00085 /// \brief Execute the provide callback function (with the given arguments) in 00086 /// a protected context which is run in another thread (optionally with a 00087 /// requested stack size). 00088 /// 00089 /// See RunSafely() and llvm_execute_on_thread(). 00090 /// 00091 /// On Darwin, if PRIO_DARWIN_BG is set on the calling thread, it will be 00092 /// propagated to the new thread as well. 00093 bool RunSafelyOnThread(function_ref<void()>, unsigned RequestedStackSize = 0); 00094 bool RunSafelyOnThread(void (*Fn)(void*), void *UserData, 00095 unsigned RequestedStackSize = 0) { 00096 return RunSafelyOnThread([&]() { Fn(UserData); }, RequestedStackSize); 00097 } 00098 00099 /// \brief Explicitly trigger a crash recovery in the current process, and 00100 /// return failure from RunSafely(). This function does not return. 00101 void HandleCrash(); 00102 00103 /// \brief Return a string containing the backtrace where the crash was 00104 /// detected; or empty if the backtrace wasn't recovered. 00105 /// 00106 /// This function is only valid when a crash has been detected (i.e., 00107 /// RunSafely() has returned false. 00108 const std::string &getBacktrace() const; 00109 }; 00110 00111 class CrashRecoveryContextCleanup { 00112 protected: 00113 CrashRecoveryContext *context; 00114 CrashRecoveryContextCleanup(CrashRecoveryContext *context) 00115 : context(context), cleanupFired(false) {} 00116 public: 00117 bool cleanupFired; 00118 00119 virtual ~CrashRecoveryContextCleanup(); 00120 virtual void recoverResources() = 0; 00121 00122 CrashRecoveryContext *getContext() const { 00123 return context; 00124 } 00125 00126 private: 00127 friend class CrashRecoveryContext; 00128 CrashRecoveryContextCleanup *prev, *next; 00129 }; 00130 00131 template<typename DERIVED, typename T> 00132 class CrashRecoveryContextCleanupBase : public CrashRecoveryContextCleanup { 00133 protected: 00134 T *resource; 00135 CrashRecoveryContextCleanupBase(CrashRecoveryContext *context, T* resource) 00136 : CrashRecoveryContextCleanup(context), resource(resource) {} 00137 public: 00138 static DERIVED *create(T *x) { 00139 if (x) { 00140 if (CrashRecoveryContext *context = CrashRecoveryContext::GetCurrent()) 00141 return new DERIVED(context, x); 00142 } 00143 return 0; 00144 } 00145 }; 00146 00147 template <typename T> 00148 class CrashRecoveryContextDestructorCleanup : public 00149 CrashRecoveryContextCleanupBase<CrashRecoveryContextDestructorCleanup<T>, T> { 00150 public: 00151 CrashRecoveryContextDestructorCleanup(CrashRecoveryContext *context, 00152 T *resource) 00153 : CrashRecoveryContextCleanupBase< 00154 CrashRecoveryContextDestructorCleanup<T>, T>(context, resource) {} 00155 00156 virtual void recoverResources() { 00157 this->resource->~T(); 00158 } 00159 }; 00160 00161 template <typename T> 00162 class CrashRecoveryContextDeleteCleanup : public 00163 CrashRecoveryContextCleanupBase<CrashRecoveryContextDeleteCleanup<T>, T> { 00164 public: 00165 CrashRecoveryContextDeleteCleanup(CrashRecoveryContext *context, T *resource) 00166 : CrashRecoveryContextCleanupBase< 00167 CrashRecoveryContextDeleteCleanup<T>, T>(context, resource) {} 00168 00169 void recoverResources() override { delete this->resource; } 00170 }; 00171 00172 template <typename T> 00173 class CrashRecoveryContextReleaseRefCleanup : public 00174 CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, T> 00175 { 00176 public: 00177 CrashRecoveryContextReleaseRefCleanup(CrashRecoveryContext *context, 00178 T *resource) 00179 : CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, 00180 T>(context, resource) {} 00181 00182 void recoverResources() override { this->resource->Release(); } 00183 }; 00184 00185 template <typename T, typename Cleanup = CrashRecoveryContextDeleteCleanup<T> > 00186 class CrashRecoveryContextCleanupRegistrar { 00187 CrashRecoveryContextCleanup *cleanup; 00188 public: 00189 CrashRecoveryContextCleanupRegistrar(T *x) 00190 : cleanup(Cleanup::create(x)) { 00191 if (cleanup) 00192 cleanup->getContext()->registerCleanup(cleanup); 00193 } 00194 00195 ~CrashRecoveryContextCleanupRegistrar() { 00196 unregister(); 00197 } 00198 00199 void unregister() { 00200 if (cleanup && !cleanup->cleanupFired) 00201 cleanup->getContext()->unregisterCleanup(cleanup); 00202 cleanup = 0; 00203 } 00204 }; 00205 } 00206 00207 #endif