diff --git a/include/llvm/Support/CrashRecoveryContext.h b/include/llvm/Support/CrashRecoveryContext.h index 2e9b5d4aa54..51752706d0e 100644 --- a/include/llvm/Support/CrashRecoveryContext.h +++ b/include/llvm/Support/CrashRecoveryContext.h @@ -15,6 +15,8 @@ namespace llvm { class StringRef; +class CrashRecoveryContextCleanup; + /// \brief Crash recovery helper object. /// /// This class implements support for running operations in a safe context so @@ -42,10 +44,14 @@ class StringRef; /// Crash recovery contexts may not be nested. class CrashRecoveryContext { void *Impl; + CrashRecoveryContextCleanup *head; public: - CrashRecoveryContext() : Impl(0) {} + CrashRecoveryContext() : Impl(0), head(0) {} ~CrashRecoveryContext(); + + void registerCleanup(CrashRecoveryContextCleanup *cleanup); + void unregisterCleanup(CrashRecoveryContextCleanup *cleanup); /// \brief Enable crash recovery. static void Enable(); @@ -87,6 +93,64 @@ public: const std::string &getBacktrace() const; }; +class CrashRecoveryContextCleanup { +public: + virtual ~CrashRecoveryContextCleanup(); + virtual void recoverResources() = 0; + + template static CrashRecoveryContextCleanup *create(T *); + +private: + friend class CrashRecoveryContext; + CrashRecoveryContextCleanup *prev, *next; +}; + +template +class CrashRecoveryContextDestructorCleanup + : public CrashRecoveryContextCleanup +{ + T *resource; +public: + CrashRecoveryContextDestructorCleanup(T *resource) : resource(resource) {} + virtual void recoverResources() { + resource->~T(); + } +}; + +template +struct CrashRecoveryContextTrait { + static inline CrashRecoveryContextCleanup *createCleanup(T *resource) { + return new CrashRecoveryContextDestructorCleanup(resource); + } +}; + +template +inline CrashRecoveryContextCleanup* CrashRecoveryContextCleanup::create(T *x) { + return CrashRecoveryContext::GetCurrent() ? + CrashRecoveryContextTrait::createCleanup(x) : + 0; +} + +class CrashRecoveryContextCleanupRegistrar { + CrashRecoveryContext *context; + CrashRecoveryContextCleanup *cleanup; +public: + CrashRecoveryContextCleanupRegistrar(CrashRecoveryContextCleanup *cleanup) + : context(CrashRecoveryContext::GetCurrent()), + cleanup(cleanup) + { + if (context && cleanup) + context->registerCleanup(cleanup); + } + ~CrashRecoveryContextCleanupRegistrar() { + if (cleanup) { + if (context) + context->unregisterCleanup(cleanup); + else + delete cleanup; + } + } +}; } #endif diff --git a/lib/Support/CrashRecoveryContext.cpp b/lib/Support/CrashRecoveryContext.cpp index bf8ca3f844b..e190051e6db 100644 --- a/lib/Support/CrashRecoveryContext.cpp +++ b/lib/Support/CrashRecoveryContext.cpp @@ -57,7 +57,18 @@ public: static sys::Mutex gCrashRecoveryContexMutex; static bool gCrashRecoveryEnabled = false; +CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {} + CrashRecoveryContext::~CrashRecoveryContext() { + // Reclaim registered resources. + CrashRecoveryContextCleanup *i = head; + while (i) { + CrashRecoveryContextCleanup *tmp = i; + i = tmp->next; + tmp->recoverResources(); + delete tmp; + } + CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; delete CRCI; } @@ -70,6 +81,33 @@ CrashRecoveryContext *CrashRecoveryContext::GetCurrent() { return CRCI->CRC; } +void CrashRecoveryContext::registerCleanup(CrashRecoveryContextCleanup *cleanup) +{ + if (!cleanup) + return; + if (head) + head->prev = cleanup; + cleanup->next = head; + head = cleanup; +} + +void +CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) { + if (!cleanup) + return; + if (cleanup == head) { + head = cleanup->next; + if (head) + head->prev = 0; + } + else { + cleanup->prev->next = cleanup->next; + if (cleanup->next) + cleanup->next->prev = cleanup->prev; + } + delete cleanup; +} + #ifdef LLVM_ON_WIN32 // FIXME: No real Win32 implementation currently.