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