Fix nested CrashRecoveryContexts with LLVM_ENABLE_THREADS=OFF, allow them.
[oota-llvm.git] / lib / Support / CrashRecoveryContext.cpp
1 //===--- CrashRecoveryContext.cpp - Crash Recovery ------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "llvm/Support/CrashRecoveryContext.h"
11 #include "llvm/Config/config.h"
12 #include "llvm/Support/ErrorHandling.h"
13 #include "llvm/Support/ManagedStatic.h"
14 #include "llvm/Support/Mutex.h"
15 #include "llvm/Support/ThreadLocal.h"
16 #include <setjmp.h>
17 using namespace llvm;
18
19 namespace {
20
21 struct CrashRecoveryContextImpl;
22
23 static ManagedStatic<
24     sys::ThreadLocal<const CrashRecoveryContextImpl> > CurrentContext;
25
26 struct CrashRecoveryContextImpl {
27   const CrashRecoveryContextImpl *Next;
28
29   CrashRecoveryContext *CRC;
30   std::string Backtrace;
31   ::jmp_buf JumpBuffer;
32   volatile unsigned Failed : 1;
33   unsigned SwitchedThread : 1;
34
35 public:
36   CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC),
37                                                         Failed(false),
38                                                         SwitchedThread(false) {
39     Next = CurrentContext->get();
40     CurrentContext->set(this);
41   }
42   ~CrashRecoveryContextImpl() {
43     if (!SwitchedThread)
44       CurrentContext->set(Next);
45   }
46
47   /// \brief Called when the separate crash-recovery thread was finished, to
48   /// indicate that we don't need to clear the thread-local CurrentContext.
49   void setSwitchedThread() { 
50 #if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
51     SwitchedThread = true;
52 #endif
53   }
54
55   void HandleCrash() {
56     // Eliminate the current context entry, to avoid re-entering in case the
57     // cleanup code crashes.
58     CurrentContext->set(Next);
59
60     assert(!Failed && "Crash recovery context already failed!");
61     Failed = true;
62
63     // FIXME: Stash the backtrace.
64
65     // Jump back to the RunSafely we were called under.
66     longjmp(JumpBuffer, 1);
67   }
68 };
69
70 }
71
72 static ManagedStatic<sys::Mutex> gCrashRecoveryContextMutex;
73 static bool gCrashRecoveryEnabled = false;
74
75 static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContext>>
76        tlIsRecoveringFromCrash;
77
78 CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {}
79
80 CrashRecoveryContext::~CrashRecoveryContext() {
81   // Reclaim registered resources.
82   CrashRecoveryContextCleanup *i = head;
83   const CrashRecoveryContext *PC = tlIsRecoveringFromCrash->get();
84   tlIsRecoveringFromCrash->set(this);
85   while (i) {
86     CrashRecoveryContextCleanup *tmp = i;
87     i = tmp->next;
88     tmp->cleanupFired = true;
89     tmp->recoverResources();
90     delete tmp;
91   }
92   tlIsRecoveringFromCrash->set(PC);
93   
94   CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
95   delete CRCI;
96 }
97
98 bool CrashRecoveryContext::isRecoveringFromCrash() {
99   return tlIsRecoveringFromCrash->get() != nullptr;
100 }
101
102 CrashRecoveryContext *CrashRecoveryContext::GetCurrent() {
103   if (!gCrashRecoveryEnabled)
104     return nullptr;
105
106   const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
107   if (!CRCI)
108     return nullptr;
109
110   return CRCI->CRC;
111 }
112
113 void CrashRecoveryContext::registerCleanup(CrashRecoveryContextCleanup *cleanup)
114 {
115   if (!cleanup)
116     return;
117   if (head)
118     head->prev = cleanup;
119   cleanup->next = head;
120   head = cleanup;
121 }
122
123 void
124 CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) {
125   if (!cleanup)
126     return;
127   if (cleanup == head) {
128     head = cleanup->next;
129     if (head)
130       head->prev = nullptr;
131   }
132   else {
133     cleanup->prev->next = cleanup->next;
134     if (cleanup->next)
135       cleanup->next->prev = cleanup->prev;
136   }
137   delete cleanup;
138 }
139
140 #ifdef LLVM_ON_WIN32
141
142 #include "Windows/WindowsSupport.h"
143
144 // On Windows, we can make use of vectored exception handling to
145 // catch most crashing situations.  Note that this does mean
146 // we will be alerted of exceptions *before* structured exception
147 // handling has the opportunity to catch it.  But that isn't likely
148 // to cause problems because nowhere in the project is SEH being
149 // used.
150 //
151 // Vectored exception handling is built on top of SEH, and so it
152 // works on a per-thread basis.
153 //
154 // The vectored exception handler functionality was added in Windows
155 // XP, so if support for older versions of Windows is required,
156 // it will have to be added.
157 //
158 // If we want to support as far back as Win2k, we could use the
159 // SetUnhandledExceptionFilter API, but there's a risk of that
160 // being entirely overwritten (it's not a chain).
161
162 static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
163 {
164   // Lookup the current thread local recovery object.
165   const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
166
167   if (!CRCI) {
168     // Something has gone horribly wrong, so let's just tell everyone
169     // to keep searching
170     CrashRecoveryContext::Disable();
171     return EXCEPTION_CONTINUE_SEARCH;
172   }
173
174   // TODO: We can capture the stack backtrace here and store it on the
175   // implementation if we so choose.
176
177   // Handle the crash
178   const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash();
179
180   // Note that we don't actually get here because HandleCrash calls
181   // longjmp, which means the HandleCrash function never returns.
182   llvm_unreachable("Handled the crash, should have longjmp'ed out of here");
183 }
184
185 // Because the Enable and Disable calls are static, it means that
186 // there may not actually be an Impl available, or even a current
187 // CrashRecoveryContext at all.  So we make use of a thread-local
188 // exception table.  The handles contained in here will either be
189 // non-NULL, valid VEH handles, or NULL.
190 static sys::ThreadLocal<const void> sCurrentExceptionHandle;
191
192 void CrashRecoveryContext::Enable() {
193   sys::ScopedLock L(*gCrashRecoveryContextMutex);
194
195   if (gCrashRecoveryEnabled)
196     return;
197
198   gCrashRecoveryEnabled = true;
199
200   // We can set up vectored exception handling now.  We will install our
201   // handler as the front of the list, though there's no assurances that
202   // it will remain at the front (another call could install itself before
203   // our handler).  This 1) isn't likely, and 2) shouldn't cause problems.
204   PVOID handle = ::AddVectoredExceptionHandler(1, ExceptionHandler);
205   sCurrentExceptionHandle.set(handle);
206 }
207
208 void CrashRecoveryContext::Disable() {
209   sys::ScopedLock L(*gCrashRecoveryContextMutex);
210
211   if (!gCrashRecoveryEnabled)
212     return;
213
214   gCrashRecoveryEnabled = false;
215
216   PVOID currentHandle = const_cast<PVOID>(sCurrentExceptionHandle.get());
217   if (currentHandle) {
218     // Now we can remove the vectored exception handler from the chain
219     ::RemoveVectoredExceptionHandler(currentHandle);
220
221     // Reset the handle in our thread-local set.
222     sCurrentExceptionHandle.set(NULL);
223   }
224 }
225
226 #else
227
228 // Generic POSIX implementation.
229 //
230 // This implementation relies on synchronous signals being delivered to the
231 // current thread. We use a thread local object to keep track of the active
232 // crash recovery context, and install signal handlers to invoke HandleCrash on
233 // the active object.
234 //
235 // This implementation does not to attempt to chain signal handlers in any
236 // reliable fashion -- if we get a signal outside of a crash recovery context we
237 // simply disable crash recovery and raise the signal again.
238
239 #include <signal.h>
240
241 static const int Signals[] =
242     { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP };
243 static const unsigned NumSignals = sizeof(Signals) / sizeof(Signals[0]);
244 static struct sigaction PrevActions[NumSignals];
245
246 static void CrashRecoverySignalHandler(int Signal) {
247   // Lookup the current thread local recovery object.
248   const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
249
250   if (!CRCI) {
251     // We didn't find a crash recovery context -- this means either we got a
252     // signal on a thread we didn't expect it on, the application got a signal
253     // outside of a crash recovery context, or something else went horribly
254     // wrong.
255     //
256     // Disable crash recovery and raise the signal again. The assumption here is
257     // that the enclosing application will terminate soon, and we won't want to
258     // attempt crash recovery again.
259     //
260     // This call of Disable isn't thread safe, but it doesn't actually matter.
261     CrashRecoveryContext::Disable();
262     raise(Signal);
263
264     // The signal will be thrown once the signal mask is restored.
265     return;
266   }
267
268   // Unblock the signal we received.
269   sigset_t SigMask;
270   sigemptyset(&SigMask);
271   sigaddset(&SigMask, Signal);
272   sigprocmask(SIG_UNBLOCK, &SigMask, nullptr);
273
274   if (CRCI)
275     const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash();
276 }
277
278 void CrashRecoveryContext::Enable() {
279   sys::ScopedLock L(*gCrashRecoveryContextMutex);
280
281   if (gCrashRecoveryEnabled)
282     return;
283
284   gCrashRecoveryEnabled = true;
285
286   // Setup the signal handler.
287   struct sigaction Handler;
288   Handler.sa_handler = CrashRecoverySignalHandler;
289   Handler.sa_flags = 0;
290   sigemptyset(&Handler.sa_mask);
291
292   for (unsigned i = 0; i != NumSignals; ++i) {
293     sigaction(Signals[i], &Handler, &PrevActions[i]);
294   }
295 }
296
297 void CrashRecoveryContext::Disable() {
298   sys::ScopedLock L(*gCrashRecoveryContextMutex);
299
300   if (!gCrashRecoveryEnabled)
301     return;
302
303   gCrashRecoveryEnabled = false;
304
305   // Restore the previous signal handlers.
306   for (unsigned i = 0; i != NumSignals; ++i)
307     sigaction(Signals[i], &PrevActions[i], nullptr);
308 }
309
310 #endif
311
312 bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
313   // If crash recovery is disabled, do nothing.
314   if (gCrashRecoveryEnabled) {
315     assert(!Impl && "Crash recovery context already initialized!");
316     CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this);
317     Impl = CRCI;
318
319     if (setjmp(CRCI->JumpBuffer) != 0) {
320       return false;
321     }
322   }
323
324   Fn();
325   return true;
326 }
327
328 void CrashRecoveryContext::HandleCrash() {
329   CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
330   assert(CRCI && "Crash recovery context never initialized!");
331   CRCI->HandleCrash();
332 }
333
334 const std::string &CrashRecoveryContext::getBacktrace() const {
335   CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *) Impl;
336   assert(CRC && "Crash recovery context never initialized!");
337   assert(CRC->Failed && "No crash was detected!");
338   return CRC->Backtrace;
339 }
340
341 // FIXME: Portability.
342 static void setThreadBackgroundPriority() {
343 #ifdef __APPLE__
344   setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG);
345 #endif
346 }
347
348 static bool hasThreadBackgroundPriority() {
349 #ifdef __APPLE__
350   return getpriority(PRIO_DARWIN_THREAD, 0) == 1;
351 #else
352   return false;
353 #endif
354 }
355
356 namespace {
357 struct RunSafelyOnThreadInfo {
358   function_ref<void()> Fn;
359   CrashRecoveryContext *CRC;
360   bool UseBackgroundPriority;
361   bool Result;
362 };
363 }
364
365 static void RunSafelyOnThread_Dispatch(void *UserData) {
366   RunSafelyOnThreadInfo *Info =
367     reinterpret_cast<RunSafelyOnThreadInfo*>(UserData);
368
369   if (Info->UseBackgroundPriority)
370     setThreadBackgroundPriority();
371
372   Info->Result = Info->CRC->RunSafely(Info->Fn);
373 }
374 bool CrashRecoveryContext::RunSafelyOnThread(function_ref<void()> Fn,
375                                              unsigned RequestedStackSize) {
376   bool UseBackgroundPriority = hasThreadBackgroundPriority();
377   RunSafelyOnThreadInfo Info = { Fn, this, UseBackgroundPriority, false };
378   llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize);
379   if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
380     CRC->setSwitchedThread();
381   return Info.Result;
382 }