Augment CrashRecoveryContext to have registered "cleanup" objects that can be used...
authorTed Kremenek <kremenek@apple.com>
Fri, 18 Mar 2011 02:05:11 +0000 (02:05 +0000)
committerTed Kremenek <kremenek@apple.com>
Fri, 18 Mar 2011 02:05:11 +0000 (02:05 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@127849 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Support/CrashRecoveryContext.h
lib/Support/CrashRecoveryContext.cpp

index 2e9b5d4aa541eaed4d86ca5dd556fc873c5ad478..51752706d0e15f339c8de9729718f4218b5d4227 100644 (file)
@@ -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 <typename T> static CrashRecoveryContextCleanup *create(T *);
+  
+private:
+  friend class CrashRecoveryContext;
+  CrashRecoveryContextCleanup *prev, *next;
+};
+
+template <typename T>
+class CrashRecoveryContextDestructorCleanup 
+  : public CrashRecoveryContextCleanup
+{
+  T *resource;
+public:
+  CrashRecoveryContextDestructorCleanup(T *resource) : resource(resource) {}
+  virtual void recoverResources() {
+    resource->~T();
+  }
+};
+  
+template <typename T>
+struct CrashRecoveryContextTrait {
+  static inline CrashRecoveryContextCleanup *createCleanup(T *resource) {
+    return new CrashRecoveryContextDestructorCleanup<T>(resource);
+  }
+};
+
+template<typename T>
+inline CrashRecoveryContextCleanup* CrashRecoveryContextCleanup::create(T *x) {
+  return CrashRecoveryContext::GetCurrent() ?
+          CrashRecoveryContextTrait<T>::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
index bf8ca3f844b46320a084c1a6de07b3a3771ceb75..e190051e6dbe1b6793da0de79c07c1d00920e773 100644 (file)
@@ -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.