1212793Sdim//===--- CrashRecoveryContext.h - Crash Recovery ----------------*- C++ -*-===// 2212793Sdim// 3212793Sdim// The LLVM Compiler Infrastructure 4212793Sdim// 5212793Sdim// This file is distributed under the University of Illinois Open Source 6212793Sdim// License. See LICENSE.TXT for details. 7212793Sdim// 8212793Sdim//===----------------------------------------------------------------------===// 9212793Sdim 10212793Sdim#ifndef LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H 11212793Sdim#define LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H 12212793Sdim 13212793Sdim#include <string> 14212793Sdim 15212793Sdimnamespace llvm { 16212793Sdimclass StringRef; 17212793Sdim 18221345Sdimclass CrashRecoveryContextCleanup; 19221345Sdim 20212793Sdim/// \brief Crash recovery helper object. 21212793Sdim/// 22212793Sdim/// This class implements support for running operations in a safe context so 23212793Sdim/// that crashes (memory errors, stack overflow, assertion violations) can be 24212793Sdim/// detected and control restored to the crashing thread. Crash detection is 25212793Sdim/// purely "best effort", the exact set of failures which can be recovered from 26212793Sdim/// is platform dependent. 27212793Sdim/// 28212793Sdim/// Clients make use of this code by first calling 29212793Sdim/// CrashRecoveryContext::Enable(), and then executing unsafe operations via a 30212793Sdim/// CrashRecoveryContext object. For example: 31212793Sdim/// 32212793Sdim/// void actual_work(void *); 33212793Sdim/// 34212793Sdim/// void foo() { 35212793Sdim/// CrashRecoveryContext CRC; 36212793Sdim/// 37212793Sdim/// if (!CRC.RunSafely(actual_work, 0)) { 38212793Sdim/// ... a crash was detected, report error to user ... 39212793Sdim/// } 40212793Sdim/// 41212793Sdim/// ... no crash was detected ... 42212793Sdim/// } 43212793Sdim/// 44212793Sdim/// Crash recovery contexts may not be nested. 45212793Sdimclass CrashRecoveryContext { 46212793Sdim void *Impl; 47221345Sdim CrashRecoveryContextCleanup *head; 48212793Sdim 49212793Sdimpublic: 50221345Sdim CrashRecoveryContext() : Impl(0), head(0) {} 51212793Sdim ~CrashRecoveryContext(); 52221345Sdim 53221345Sdim void registerCleanup(CrashRecoveryContextCleanup *cleanup); 54221345Sdim void unregisterCleanup(CrashRecoveryContextCleanup *cleanup); 55212793Sdim 56212793Sdim /// \brief Enable crash recovery. 57212793Sdim static void Enable(); 58212793Sdim 59212793Sdim /// \brief Disable crash recovery. 60212793Sdim static void Disable(); 61212793Sdim 62212793Sdim /// \brief Return the active context, if the code is currently executing in a 63212793Sdim /// thread which is in a protected context. 64212793Sdim static CrashRecoveryContext *GetCurrent(); 65212793Sdim 66221345Sdim /// \brief Return true if the current thread is recovering from a 67221345Sdim /// crash. 68221345Sdim static bool isRecoveringFromCrash(); 69221345Sdim 70212793Sdim /// \brief Execute the provide callback function (with the given arguments) in 71212793Sdim /// a protected context. 72212793Sdim /// 73212793Sdim /// \return True if the function completed successfully, and false if the 74212793Sdim /// function crashed (or HandleCrash was called explicitly). Clients should 75212793Sdim /// make as little assumptions as possible about the program state when 76212793Sdim /// RunSafely has returned false. Clients can use getBacktrace() to retrieve 77212793Sdim /// the backtrace of the crash on failures. 78212793Sdim bool RunSafely(void (*Fn)(void*), void *UserData); 79212793Sdim 80218893Sdim /// \brief Execute the provide callback function (with the given arguments) in 81218893Sdim /// a protected context which is run in another thread (optionally with a 82218893Sdim /// requested stack size). 83218893Sdim /// 84218893Sdim /// See RunSafely() and llvm_execute_on_thread(). 85218893Sdim bool RunSafelyOnThread(void (*Fn)(void*), void *UserData, 86218893Sdim unsigned RequestedStackSize = 0); 87218893Sdim 88212793Sdim /// \brief Explicitly trigger a crash recovery in the current process, and 89212793Sdim /// return failure from RunSafely(). This function does not return. 90212793Sdim void HandleCrash(); 91212793Sdim 92212793Sdim /// \brief Return a string containing the backtrace where the crash was 93212793Sdim /// detected; or empty if the backtrace wasn't recovered. 94212793Sdim /// 95212793Sdim /// This function is only valid when a crash has been detected (i.e., 96212793Sdim /// RunSafely() has returned false. 97212793Sdim const std::string &getBacktrace() const; 98212793Sdim}; 99212793Sdim 100221345Sdimclass CrashRecoveryContextCleanup { 101221345Sdimprotected: 102221345Sdim CrashRecoveryContext *context; 103221345Sdim CrashRecoveryContextCleanup(CrashRecoveryContext *context) 104221345Sdim : context(context), cleanupFired(false) {} 105221345Sdimpublic: 106221345Sdim bool cleanupFired; 107221345Sdim 108221345Sdim virtual ~CrashRecoveryContextCleanup(); 109221345Sdim virtual void recoverResources() = 0; 110221345Sdim 111221345Sdim CrashRecoveryContext *getContext() const { 112221345Sdim return context; 113221345Sdim } 114221345Sdim 115221345Sdimprivate: 116221345Sdim friend class CrashRecoveryContext; 117221345Sdim CrashRecoveryContextCleanup *prev, *next; 118221345Sdim}; 119221345Sdim 120221345Sdimtemplate<typename DERIVED, typename T> 121221345Sdimclass CrashRecoveryContextCleanupBase : public CrashRecoveryContextCleanup { 122221345Sdimprotected: 123221345Sdim T *resource; 124221345Sdim CrashRecoveryContextCleanupBase(CrashRecoveryContext *context, T* resource) 125221345Sdim : CrashRecoveryContextCleanup(context), resource(resource) {} 126221345Sdimpublic: 127221345Sdim static DERIVED *create(T *x) { 128221345Sdim if (x) { 129221345Sdim if (CrashRecoveryContext *context = CrashRecoveryContext::GetCurrent()) 130221345Sdim return new DERIVED(context, x); 131221345Sdim } 132221345Sdim return 0; 133221345Sdim } 134221345Sdim}; 135221345Sdim 136221345Sdimtemplate <typename T> 137221345Sdimclass CrashRecoveryContextDestructorCleanup : public 138221345Sdim CrashRecoveryContextCleanupBase<CrashRecoveryContextDestructorCleanup<T>, T> { 139221345Sdimpublic: 140221345Sdim CrashRecoveryContextDestructorCleanup(CrashRecoveryContext *context, 141221345Sdim T *resource) 142221345Sdim : CrashRecoveryContextCleanupBase< 143221345Sdim CrashRecoveryContextDestructorCleanup<T>, T>(context, resource) {} 144221345Sdim 145221345Sdim virtual void recoverResources() { 146221345Sdim this->resource->~T(); 147221345Sdim } 148221345Sdim}; 149221345Sdim 150221345Sdimtemplate <typename T> 151221345Sdimclass CrashRecoveryContextDeleteCleanup : public 152221345Sdim CrashRecoveryContextCleanupBase<CrashRecoveryContextDeleteCleanup<T>, T> { 153221345Sdimpublic: 154221345Sdim CrashRecoveryContextDeleteCleanup(CrashRecoveryContext *context, T *resource) 155221345Sdim : CrashRecoveryContextCleanupBase< 156221345Sdim CrashRecoveryContextDeleteCleanup<T>, T>(context, resource) {} 157221345Sdim 158221345Sdim virtual void recoverResources() { 159221345Sdim delete this->resource; 160221345Sdim } 161221345Sdim}; 162221345Sdim 163221345Sdimtemplate <typename T> 164221345Sdimclass CrashRecoveryContextReleaseRefCleanup : public 165221345Sdim CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, T> 166221345Sdim{ 167221345Sdimpublic: 168221345Sdim CrashRecoveryContextReleaseRefCleanup(CrashRecoveryContext *context, 169221345Sdim T *resource) 170221345Sdim : CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, 171221345Sdim T>(context, resource) {} 172221345Sdim 173221345Sdim virtual void recoverResources() { 174221345Sdim this->resource->Release(); 175221345Sdim } 176221345Sdim}; 177221345Sdim 178221345Sdimtemplate <typename T, typename Cleanup = CrashRecoveryContextDeleteCleanup<T> > 179221345Sdimclass CrashRecoveryContextCleanupRegistrar { 180221345Sdim CrashRecoveryContextCleanup *cleanup; 181221345Sdimpublic: 182221345Sdim CrashRecoveryContextCleanupRegistrar(T *x) 183221345Sdim : cleanup(Cleanup::create(x)) { 184221345Sdim if (cleanup) 185221345Sdim cleanup->getContext()->registerCleanup(cleanup); 186221345Sdim } 187221345Sdim 188221345Sdim ~CrashRecoveryContextCleanupRegistrar() { 189223017Sdim unregister(); 190223017Sdim } 191223017Sdim 192223017Sdim void unregister() { 193221345Sdim if (cleanup && !cleanup->cleanupFired) 194223017Sdim cleanup->getContext()->unregisterCleanup(cleanup); 195223017Sdim cleanup = 0; 196221345Sdim } 197221345Sdim}; 198212793Sdim} 199212793Sdim 200212793Sdim#endif 201