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