Fix nested CrashRecoveryContexts with LLVM_ENABLE_THREADS=OFF, allow them.
libclang uses a CrashRecoveryContext, and building a module does too. If a module gets built through libclang, nested CrashRecoveryContexts are used. They work fine with threads as things are stored in ThreadLocal variables, but in LLVM_ENABLE_THREADS=OFF builds the two recovery contexts would write to the same globals. To fix, keep active CrashRecoveryContextImpls in a list and have the global point to the innermost one, and do something similar for tlIsRecoveringFromCrash. Necessary (but not sufficient) for PR11974 and PR20325 http://reviews.llvm.org/D11770 llvm-svn: 244251
This commit is contained in:
parent
242ca930e8
commit
28dc4171e9
|
@ -39,8 +39,6 @@ class CrashRecoveryContextCleanup;
|
||||||
///
|
///
|
||||||
/// ... no crash was detected ...
|
/// ... no crash was detected ...
|
||||||
/// }
|
/// }
|
||||||
///
|
|
||||||
/// Crash recovery contexts may not be nested.
|
|
||||||
class CrashRecoveryContext {
|
class CrashRecoveryContext {
|
||||||
void *Impl;
|
void *Impl;
|
||||||
CrashRecoveryContextCleanup *head;
|
CrashRecoveryContextCleanup *head;
|
||||||
|
|
|
@ -24,6 +24,8 @@ static ManagedStatic<
|
||||||
sys::ThreadLocal<const CrashRecoveryContextImpl> > CurrentContext;
|
sys::ThreadLocal<const CrashRecoveryContextImpl> > CurrentContext;
|
||||||
|
|
||||||
struct CrashRecoveryContextImpl {
|
struct CrashRecoveryContextImpl {
|
||||||
|
const CrashRecoveryContextImpl *Next;
|
||||||
|
|
||||||
CrashRecoveryContext *CRC;
|
CrashRecoveryContext *CRC;
|
||||||
std::string Backtrace;
|
std::string Backtrace;
|
||||||
::jmp_buf JumpBuffer;
|
::jmp_buf JumpBuffer;
|
||||||
|
@ -34,21 +36,26 @@ public:
|
||||||
CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC),
|
CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC),
|
||||||
Failed(false),
|
Failed(false),
|
||||||
SwitchedThread(false) {
|
SwitchedThread(false) {
|
||||||
|
Next = CurrentContext->get();
|
||||||
CurrentContext->set(this);
|
CurrentContext->set(this);
|
||||||
}
|
}
|
||||||
~CrashRecoveryContextImpl() {
|
~CrashRecoveryContextImpl() {
|
||||||
if (!SwitchedThread)
|
if (!SwitchedThread)
|
||||||
CurrentContext->erase();
|
CurrentContext->set(Next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Called when the separate crash-recovery thread was finished, to
|
/// \brief Called when the separate crash-recovery thread was finished, to
|
||||||
/// indicate that we don't need to clear the thread-local CurrentContext.
|
/// indicate that we don't need to clear the thread-local CurrentContext.
|
||||||
void setSwitchedThread() { SwitchedThread = true; }
|
void setSwitchedThread() {
|
||||||
|
#if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
|
||||||
|
SwitchedThread = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void HandleCrash() {
|
void HandleCrash() {
|
||||||
// Eliminate the current context entry, to avoid re-entering in case the
|
// Eliminate the current context entry, to avoid re-entering in case the
|
||||||
// cleanup code crashes.
|
// cleanup code crashes.
|
||||||
CurrentContext->erase();
|
CurrentContext->set(Next);
|
||||||
|
|
||||||
assert(!Failed && "Crash recovery context already failed!");
|
assert(!Failed && "Crash recovery context already failed!");
|
||||||
Failed = true;
|
Failed = true;
|
||||||
|
@ -65,7 +72,7 @@ public:
|
||||||
static ManagedStatic<sys::Mutex> gCrashRecoveryContextMutex;
|
static ManagedStatic<sys::Mutex> gCrashRecoveryContextMutex;
|
||||||
static bool gCrashRecoveryEnabled = false;
|
static bool gCrashRecoveryEnabled = false;
|
||||||
|
|
||||||
static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContextCleanup> >
|
static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContext>>
|
||||||
tlIsRecoveringFromCrash;
|
tlIsRecoveringFromCrash;
|
||||||
|
|
||||||
CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {}
|
CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {}
|
||||||
|
@ -73,7 +80,8 @@ CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {}
|
||||||
CrashRecoveryContext::~CrashRecoveryContext() {
|
CrashRecoveryContext::~CrashRecoveryContext() {
|
||||||
// Reclaim registered resources.
|
// Reclaim registered resources.
|
||||||
CrashRecoveryContextCleanup *i = head;
|
CrashRecoveryContextCleanup *i = head;
|
||||||
tlIsRecoveringFromCrash->set(head);
|
const CrashRecoveryContext *PC = tlIsRecoveringFromCrash->get();
|
||||||
|
tlIsRecoveringFromCrash->set(this);
|
||||||
while (i) {
|
while (i) {
|
||||||
CrashRecoveryContextCleanup *tmp = i;
|
CrashRecoveryContextCleanup *tmp = i;
|
||||||
i = tmp->next;
|
i = tmp->next;
|
||||||
|
@ -81,7 +89,7 @@ CrashRecoveryContext::~CrashRecoveryContext() {
|
||||||
tmp->recoverResources();
|
tmp->recoverResources();
|
||||||
delete tmp;
|
delete tmp;
|
||||||
}
|
}
|
||||||
tlIsRecoveringFromCrash->erase();
|
tlIsRecoveringFromCrash->set(PC);
|
||||||
|
|
||||||
CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
|
CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
|
||||||
delete CRCI;
|
delete CRCI;
|
||||||
|
|
Loading…
Reference in New Issue