|  | //===--- CrashRecoveryContext.h - Crash Recovery ----------------*- C++ -*-===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H | 
|  | #define LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H | 
|  |  | 
|  | #include <string> | 
|  |  | 
|  | namespace llvm { | 
|  | class StringRef; | 
|  |  | 
|  | class CrashRecoveryContextCleanup; | 
|  |  | 
|  | /// \brief Crash recovery helper object. | 
|  | /// | 
|  | /// This class implements support for running operations in a safe context so | 
|  | /// that crashes (memory errors, stack overflow, assertion violations) can be | 
|  | /// detected and control restored to the crashing thread. Crash detection is | 
|  | /// purely "best effort", the exact set of failures which can be recovered from | 
|  | /// is platform dependent. | 
|  | /// | 
|  | /// Clients make use of this code by first calling | 
|  | /// CrashRecoveryContext::Enable(), and then executing unsafe operations via a | 
|  | /// CrashRecoveryContext object. For example: | 
|  | /// | 
|  | ///    void actual_work(void *); | 
|  | /// | 
|  | ///    void foo() { | 
|  | ///      CrashRecoveryContext CRC; | 
|  | /// | 
|  | ///      if (!CRC.RunSafely(actual_work, 0)) { | 
|  | ///         ... a crash was detected, report error to user ... | 
|  | ///      } | 
|  | /// | 
|  | ///      ... no crash was detected ... | 
|  | ///    } | 
|  | /// | 
|  | /// Crash recovery contexts may not be nested. | 
|  | class CrashRecoveryContext { | 
|  | void *Impl; | 
|  | CrashRecoveryContextCleanup *head; | 
|  |  | 
|  | public: | 
|  | CrashRecoveryContext() : Impl(0), head(0) {} | 
|  | ~CrashRecoveryContext(); | 
|  |  | 
|  | void registerCleanup(CrashRecoveryContextCleanup *cleanup); | 
|  | void unregisterCleanup(CrashRecoveryContextCleanup *cleanup); | 
|  |  | 
|  | /// \brief Enable crash recovery. | 
|  | static void Enable(); | 
|  |  | 
|  | /// \brief Disable crash recovery. | 
|  | static void Disable(); | 
|  |  | 
|  | /// \brief Return the active context, if the code is currently executing in a | 
|  | /// thread which is in a protected context. | 
|  | static CrashRecoveryContext *GetCurrent(); | 
|  |  | 
|  | /// \brief Return true if the current thread is recovering from a | 
|  | /// crash. | 
|  | static bool isRecoveringFromCrash(); | 
|  |  | 
|  | /// \brief Execute the provide callback function (with the given arguments) in | 
|  | /// a protected context. | 
|  | /// | 
|  | /// \return True if the function completed successfully, and false if the | 
|  | /// function crashed (or HandleCrash was called explicitly). Clients should | 
|  | /// make as little assumptions as possible about the program state when | 
|  | /// RunSafely has returned false. Clients can use getBacktrace() to retrieve | 
|  | /// the backtrace of the crash on failures. | 
|  | bool RunSafely(void (*Fn)(void*), void *UserData); | 
|  |  | 
|  | /// \brief Execute the provide callback function (with the given arguments) in | 
|  | /// a protected context which is run in another thread (optionally with a | 
|  | /// requested stack size). | 
|  | /// | 
|  | /// See RunSafely() and llvm_execute_on_thread(). | 
|  | bool RunSafelyOnThread(void (*Fn)(void*), void *UserData, | 
|  | unsigned RequestedStackSize = 0); | 
|  |  | 
|  | /// \brief Explicitly trigger a crash recovery in the current process, and | 
|  | /// return failure from RunSafely(). This function does not return. | 
|  | void HandleCrash(); | 
|  |  | 
|  | /// \brief Return a string containing the backtrace where the crash was | 
|  | /// detected; or empty if the backtrace wasn't recovered. | 
|  | /// | 
|  | /// This function is only valid when a crash has been detected (i.e., | 
|  | /// RunSafely() has returned false. | 
|  | const std::string &getBacktrace() const; | 
|  | }; | 
|  |  | 
|  | class CrashRecoveryContextCleanup { | 
|  | protected: | 
|  | CrashRecoveryContext *context; | 
|  | CrashRecoveryContextCleanup(CrashRecoveryContext *context) | 
|  | : context(context), cleanupFired(false) {} | 
|  | public: | 
|  | bool cleanupFired; | 
|  |  | 
|  | virtual ~CrashRecoveryContextCleanup(); | 
|  | virtual void recoverResources() = 0; | 
|  |  | 
|  | CrashRecoveryContext *getContext() const { | 
|  | return context; | 
|  | } | 
|  |  | 
|  | private: | 
|  | friend class CrashRecoveryContext; | 
|  | CrashRecoveryContextCleanup *prev, *next; | 
|  | }; | 
|  |  | 
|  | template<typename DERIVED, typename T> | 
|  | class CrashRecoveryContextCleanupBase : public CrashRecoveryContextCleanup { | 
|  | protected: | 
|  | T *resource; | 
|  | CrashRecoveryContextCleanupBase(CrashRecoveryContext *context, T* resource) | 
|  | : CrashRecoveryContextCleanup(context), resource(resource) {} | 
|  | public: | 
|  | static DERIVED *create(T *x) { | 
|  | if (x) { | 
|  | if (CrashRecoveryContext *context = CrashRecoveryContext::GetCurrent()) | 
|  | return new DERIVED(context, x); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T> | 
|  | class CrashRecoveryContextDestructorCleanup : public | 
|  | CrashRecoveryContextCleanupBase<CrashRecoveryContextDestructorCleanup<T>, T> { | 
|  | public: | 
|  | CrashRecoveryContextDestructorCleanup(CrashRecoveryContext *context, | 
|  | T *resource) | 
|  | : CrashRecoveryContextCleanupBase< | 
|  | CrashRecoveryContextDestructorCleanup<T>, T>(context, resource) {} | 
|  |  | 
|  | virtual void recoverResources() { | 
|  | this->resource->~T(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T> | 
|  | class CrashRecoveryContextDeleteCleanup : public | 
|  | CrashRecoveryContextCleanupBase<CrashRecoveryContextDeleteCleanup<T>, T> { | 
|  | public: | 
|  | CrashRecoveryContextDeleteCleanup(CrashRecoveryContext *context, T *resource) | 
|  | : CrashRecoveryContextCleanupBase< | 
|  | CrashRecoveryContextDeleteCleanup<T>, T>(context, resource) {} | 
|  |  | 
|  | virtual void recoverResources() { | 
|  | delete this->resource; | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T> | 
|  | class CrashRecoveryContextReleaseRefCleanup : public | 
|  | CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, T> | 
|  | { | 
|  | public: | 
|  | CrashRecoveryContextReleaseRefCleanup(CrashRecoveryContext *context, | 
|  | T *resource) | 
|  | : CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, | 
|  | T>(context, resource) {} | 
|  |  | 
|  | virtual void recoverResources() { | 
|  | this->resource->Release(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T, typename Cleanup = CrashRecoveryContextDeleteCleanup<T> > | 
|  | class CrashRecoveryContextCleanupRegistrar { | 
|  | CrashRecoveryContextCleanup *cleanup; | 
|  | public: | 
|  | CrashRecoveryContextCleanupRegistrar(T *x) | 
|  | : cleanup(Cleanup::create(x)) { | 
|  | if (cleanup) | 
|  | cleanup->getContext()->registerCleanup(cleanup); | 
|  | } | 
|  |  | 
|  | ~CrashRecoveryContextCleanupRegistrar() { | 
|  | unregister(); | 
|  | } | 
|  |  | 
|  | void unregister() { | 
|  | if (cleanup && !cleanup->cleanupFired) | 
|  | cleanup->getContext()->unregisterCleanup(cleanup); | 
|  | cleanup = 0; | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | #endif |