Augment CrashRecoveryContext to have registered "cleanup" objects that can be used to release resources during a crash.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@127849 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ted Kremenek 2011-03-18 02:05:11 +00:00
parent efdc115c82
commit a4f9839701
2 changed files with 103 additions and 1 deletions

View 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

View 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.