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