From 35033a5876aa27ea5729bc29b41bb4460a303cad Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Wed, 4 Mar 2009 21:21:36 +0000 Subject: [PATCH] Add a new 'AddSignalHandler' function to Signals.h that allows arbitrary functions to be run when a crash happens. Delete RemoveDirectoryOnSignal as it is dead and has never had clients. Change PrintStackTraceOnErrorSignal to be implemented in terms of AddSignalHandler. I updated the Win32 versions of these APIs, but can't test them. If there are any problems, I'd be happy to fix them as well. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@66072 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/System/Signals.h | 11 ++- lib/System/Unix/Signals.inc | 162 ++++++++++++++-------------------- lib/System/Win32/Signals.inc | 56 ++++-------- 3 files changed, 88 insertions(+), 141 deletions(-) diff --git a/include/llvm/System/Signals.h b/include/llvm/System/Signals.h index 197e4e1d2d6..2b9d8ca6bf9 100644 --- a/include/llvm/System/Signals.h +++ b/include/llvm/System/Signals.h @@ -25,17 +25,16 @@ namespace sys { /// @brief Remove a file if a fatal signal occurs. bool RemoveFileOnSignal(const Path &Filename, std::string* ErrMsg = 0); - /// This function registers a signal handler to ensure that if a fatal signal - /// gets delivered to the process that the named directory and all its - /// contents are removed. - /// @brief Remove a directory if a fatal signal occurs. - bool RemoveDirectoryOnSignal(const Path& path, std::string* ErrMsg = 0); - /// When an error signal (such as SIBABRT or SIGSEGV) is delivered to the /// process, print a stack trace and then exit. /// @brief Print a stack trace if a fatal signal occurs. void PrintStackTraceOnErrorSignal(); + /// AddSignalHandler - Add a function to be called when an abort/kill signal + /// is delivered to the process. The handler can have a cookie passed to it + /// to identify what instance of the handler it is. + void AddSignalHandler(void (*FnPtr)(void *), void *Cookie); + /// This function registers a function to be called when the user "interrupts" /// the program (typically by pressing ctrl-c). When the user interrupts the /// program, the specified interrupt function is called instead of the program diff --git a/lib/System/Unix/Signals.inc b/lib/System/Unix/Signals.inc index e42841263ea..ac0d982f4e5 100644 --- a/lib/System/Unix/Signals.inc +++ b/lib/System/Unix/Signals.inc @@ -31,15 +31,11 @@ #endif using namespace llvm; -namespace { - -static bool StackTraceRequested = false; - /// InterruptFunction - The function to call if ctrl-c is pressed. static void (*InterruptFunction)() = 0; -static std::vector *FilesToRemove = 0 ; -static std::vector *DirectoriesToRemove = 0; +static std::vector *FilesToRemove = 0; +static std::vector > *CallBacksToRun = 0; // IntSigs - Signals that may interrupt the program at any time. static const int IntSigs[] = { @@ -59,17 +55,77 @@ static const int KillSigs[] = { static const int *const KillSigsEnd = KillSigs + sizeof(KillSigs) / sizeof(KillSigs[0]); -#ifdef HAVE_BACKTRACE -static void* StackTrace[256]; -#endif +// SignalHandler - The signal handler that runs... +static RETSIGTYPE SignalHandler(int Sig) { + if (FilesToRemove != 0) + while (!FilesToRemove->empty()) { + FilesToRemove->back().eraseFromDisk(true); + FilesToRemove->pop_back(); + } + + if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) { + if (InterruptFunction) { + void (*IF)() = InterruptFunction; + InterruptFunction = 0; + IF(); // run the interrupt function. + return; + } + exit(1); // If this is an interrupt signal, exit the program + } + + // Otherwise if it is a fault (like SEGV) run any handler. + if (CallBacksToRun) + for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i) + (*CallBacksToRun)[i].first((*CallBacksToRun)[i].second); + + // Restore the signal behavior to default, so that the program actually + // crashes when we return and the signal reissues. + signal(Sig, SIG_DFL); +} + +// Just call signal +static void RegisterHandler(int Signal) { + signal(Signal, SignalHandler); +} + + + +void sys::SetInterruptFunction(void (*IF)()) { + InterruptFunction = IF; + RegisterHandler(SIGINT); +} + +// RemoveFileOnSignal - The public API +bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) { + if (FilesToRemove == 0) + FilesToRemove = new std::vector(); + + FilesToRemove->push_back(Filename); + + std::for_each(IntSigs, IntSigsEnd, RegisterHandler); + std::for_each(KillSigs, KillSigsEnd, RegisterHandler); + return false; +} + +/// AddSignalHandler - Add a function to be called when a signal is delivered +/// to the process. The handler can have a cookie passed to it to identify +/// what instance of the handler it is. +void sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { + if (CallBacksToRun == 0) + CallBacksToRun = new std::vector >(); + CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); + std::for_each(KillSigs, KillSigsEnd, RegisterHandler); +} + // PrintStackTrace - In the case of a program crash or fault, print out a stack // trace so that the user has an indication of why and where we died. // // On glibc systems we have the 'backtrace' function, which works nicely, but // doesn't demangle symbols. -static void PrintStackTrace() { +static void PrintStackTrace(void *) { #ifdef HAVE_BACKTRACE + static void* StackTrace[256]; // Use backtrace() to output a backtrace on Linux systems with glibc. int depth = backtrace(StackTrace, static_cast(array_lengthof(StackTrace))); @@ -118,91 +174,9 @@ static void PrintStackTrace() { #endif } -// SignalHandler - The signal handler that runs... -static RETSIGTYPE SignalHandler(int Sig) { - if (FilesToRemove != 0) - while (!FilesToRemove->empty()) { - FilesToRemove->back().eraseFromDisk(true); - FilesToRemove->pop_back(); - } - - if (DirectoriesToRemove != 0) - while (!DirectoriesToRemove->empty()) { - DirectoriesToRemove->back().eraseFromDisk(true); - DirectoriesToRemove->pop_back(); - } - - if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) { - if (InterruptFunction) { - void (*IF)() = InterruptFunction; - InterruptFunction = 0; - IF(); // run the interrupt function. - return; - } else { - exit(1); // If this is an interrupt signal, exit the program - } - } - - // Otherwise if it is a fault (like SEGV) output the stacktrace to - // STDERR (if we can) and reissue the signal to die... - if (StackTraceRequested) - PrintStackTrace(); - signal(Sig, SIG_DFL); -} - -// Just call signal -static void RegisterHandler(int Signal) { - signal(Signal, SignalHandler); -} - -} - - -void sys::SetInterruptFunction(void (*IF)()) { - InterruptFunction = IF; - RegisterHandler(SIGINT); -} - -// RemoveFileOnSignal - The public API -bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) { - if (FilesToRemove == 0) - FilesToRemove = new std::vector; - - FilesToRemove->push_back(Filename); - - std::for_each(IntSigs, IntSigsEnd, RegisterHandler); - std::for_each(KillSigs, KillSigsEnd, RegisterHandler); - return false; -} - -// RemoveDirectoryOnSignal - The public API -bool sys::RemoveDirectoryOnSignal(const sys::Path& path, std::string* ErrMsg) { - // Not a directory? - struct stat buf; - if (0 != stat(path.c_str(), &buf)) { - MakeErrMsg(ErrMsg, path.toString() + ": can't get status of file"); - return true; - } - - if (!S_ISDIR(buf.st_mode)) { - if (ErrMsg) - *ErrMsg = path.toString() + " is not a directory"; - return true; - } - - if (DirectoriesToRemove == 0) - DirectoriesToRemove = new std::vector; - - DirectoriesToRemove->push_back(path); - - std::for_each(IntSigs, IntSigsEnd, RegisterHandler); - std::for_each(KillSigs, KillSigsEnd, RegisterHandler); - return false; -} - /// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or /// SIGSEGV) is delivered to the process, print a stack trace and then exit. void sys::PrintStackTraceOnErrorSignal() { - StackTraceRequested = true; - std::for_each(KillSigs, KillSigsEnd, RegisterHandler); + AddSignalHandler(PrintStackTrace, 0); } + diff --git a/lib/System/Win32/Signals.inc b/lib/System/Win32/Signals.inc index 02dab86f22d..da9fd502a7e 100644 --- a/lib/System/Win32/Signals.inc +++ b/lib/System/Win32/Signals.inc @@ -39,7 +39,7 @@ static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); static void (*InterruptFunction)() = 0; static std::vector *FilesToRemove = NULL; -static std::vector *DirectoriesToRemove = NULL; +static std::vector > *CallBacksToRun = 0; static bool RegisteredUnhandledExceptionFilter = false; static bool CleanupExecuted = false; static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; @@ -98,37 +98,6 @@ bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) { return false; } -// RemoveDirectoryOnSignal - The public API -bool sys::RemoveDirectoryOnSignal(const sys::Path& path, std::string* ErrMsg) { - // Not a directory? - WIN32_FILE_ATTRIBUTE_DATA fi; - if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) { - MakeErrMsg(ErrMsg, path.toString() + ": can't get status of file"); - return true; - } - - if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - if (ErrMsg) - *ErrMsg = path.toString() + ": not a directory"; - return true; - } - - RegisterHandler(); - - if (CleanupExecuted) { - if (ErrMsg) - *ErrMsg = "Process terminating -- cannot register for removal"; - return true; - } - - if (DirectoriesToRemove == NULL) - DirectoriesToRemove = new std::vector; - DirectoriesToRemove->push_back(path); - - LeaveCriticalSection(&CriticalSection); - return false; -} - /// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or /// SIGSEGV) is delivered to the process, print a stack trace and then exit. void sys::PrintStackTraceOnErrorSignal() { @@ -162,14 +131,9 @@ static void Cleanup() { FilesToRemove->pop_back(); } - if (DirectoriesToRemove != NULL) - while (!DirectoriesToRemove->empty()) { - try { - DirectoriesToRemove->back().eraseFromDisk(true); - } catch (...) { - } - DirectoriesToRemove->pop_back(); - } + if (CallBacksToRun) + for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i) + (*CallBacksToRun)[i].first((*CallBacksToRun)[i].second); LeaveCriticalSection(&CriticalSection); } @@ -259,7 +223,7 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { #endif } catch (...) { - assert(!"Crashed in LLVMUnhandledExceptionFilter"); + assert(0 && "Crashed in LLVMUnhandledExceptionFilter"); } // Allow dialog box to pop up allowing choice to start debugger. @@ -292,3 +256,13 @@ static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { return FALSE; } +/// AddSignalHandler - Add a function to be called when a signal is delivered +/// to the process. The handler can have a cookie passed to it to identify +/// what instance of the handler it is. +void sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { + if (CallBacksToRun == 0) + CallBacksToRun = new std::vector >(); + CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); + std::for_each(KillSigs, KillSigsEnd, RegisterHandler); +} +