LLVM API Documentation

Signals.inc

Go to the documentation of this file.
00001 //===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===//
00002 // 
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file was developed by the LLVM research group and is distributed under
00006 // the University of Illinois Open Source License. See LICENSE.TXT for details.
00007 // 
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file defines some helpful functions for dealing with the possibility of
00011 // Unix signals occuring while your program is running.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "Unix.h"
00016 #include <vector>
00017 #include <algorithm>
00018 #if HAVE_EXECINFO_H
00019 # include <execinfo.h>         // For backtrace().
00020 #endif
00021 #if HAVE_SIGNAL_H
00022 #include <signal.h>
00023 #endif
00024 
00025 namespace {
00026 
00027 /// InterruptFunction - The function to call if ctrl-c is pressed.
00028 void (*InterruptFunction)() = 0;
00029 
00030 std::vector<std::string> *FilesToRemove = 0 ;
00031 std::vector<llvm::sys::Path> *DirectoriesToRemove = 0;
00032 
00033 // IntSigs - Signals that may interrupt the program at any time.
00034 const int IntSigs[] = {
00035   SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2
00036 };
00037 const int *IntSigsEnd = IntSigs + sizeof(IntSigs)/sizeof(IntSigs[0]);
00038 
00039 // KillSigs - Signals that are synchronous with the program that will cause it
00040 // to die.
00041 const int KillSigs[] = {
00042   SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGSYS, SIGXCPU, SIGXFSZ
00043 #ifdef SIGEMT
00044   , SIGEMT
00045 #endif
00046 };
00047 const int *KillSigsEnd = KillSigs + sizeof(KillSigs)/sizeof(KillSigs[0]);
00048 
00049 #ifdef HAVE_BACKTRACE
00050 void* StackTrace[256];
00051 #endif
00052 
00053 // PrintStackTrace - In the case of a program crash or fault, print out a stack
00054 // trace so that the user has an indication of why and where we died.
00055 //
00056 // On glibc systems we have the 'backtrace' function, which works nicely, but
00057 // doesn't demangle symbols.  In order to backtrace symbols, we fork and exec a
00058 // 'c++filt' process to do the demangling.  This seems like the simplest and
00059 // most robust solution when we can't allocate memory (such as in a signal
00060 // handler).  If we can't find 'c++filt', we fallback to printing mangled names.
00061 //
00062 void PrintStackTrace() {
00063 #ifdef HAVE_BACKTRACE
00064   // Use backtrace() to output a backtrace on Linux systems with glibc.
00065   int depth = backtrace(StackTrace, sizeof(StackTrace)/sizeof(StackTrace[0]));
00066   
00067   // Create a one-way unix pipe.  The backtracing process writes to PipeFDs[1],
00068   // the c++filt process reads from PipeFDs[0].
00069   int PipeFDs[2];
00070   if (pipe(PipeFDs)) {
00071     backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO);
00072     return;
00073   }
00074 
00075   switch (pid_t ChildPID = fork()) {
00076   case -1:        // Error forking, print mangled stack trace
00077     close(PipeFDs[0]);
00078     close(PipeFDs[1]);
00079     backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO);
00080     return;
00081   default:        // backtracing process
00082     close(PipeFDs[0]);  // Close the reader side.
00083 
00084     // Print the mangled backtrace into the pipe.
00085     backtrace_symbols_fd(StackTrace, depth, PipeFDs[1]);
00086     close(PipeFDs[1]);   // We are done writing.
00087     while (waitpid(ChildPID, 0, 0) == -1)
00088       if (errno != EINTR) break;
00089     return;
00090 
00091   case 0:         // c++filt process
00092     close(PipeFDs[1]);    // Close the writer side.
00093     dup2(PipeFDs[0], 0);  // Read from standard input
00094     close(PipeFDs[0]);    // Close the old descriptor
00095     dup2(2, 1);           // Revector stdout -> stderr
00096 
00097     // Try to run c++filt or gc++filt.  If neither is found, call back on 'cat'
00098     // to print the mangled stack trace.  If we can't find cat, just exit.
00099     execlp("c++filt", "c++filt", (char*)NULL);
00100     execlp("gc++filt", "gc++filt", (char*)NULL);
00101     execlp("cat", "cat", (char*)NULL);
00102     execlp("/bin/cat", "cat", (char*)NULL);
00103     exit(0);
00104   }
00105 #endif
00106 }
00107 
00108 // SignalHandler - The signal handler that runs...
00109 RETSIGTYPE SignalHandler(int Sig) {
00110   if (FilesToRemove != 0)
00111     while (!FilesToRemove->empty()) {
00112       std::remove(FilesToRemove->back().c_str());
00113       FilesToRemove->pop_back();
00114     }
00115 
00116   if (DirectoriesToRemove != 0)
00117     while (!DirectoriesToRemove->empty()) {
00118       DirectoriesToRemove->back().eraseFromDisk(true);
00119       DirectoriesToRemove->pop_back();
00120     }
00121 
00122   if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) {
00123     if (InterruptFunction) {
00124       void (*IF)() = InterruptFunction;
00125       InterruptFunction = 0;
00126       IF();        // run the interrupt function.
00127       return;
00128     } else {
00129       exit(1);   // If this is an interrupt signal, exit the program
00130     }
00131   }
00132 
00133   // Otherwise if it is a fault (like SEGV) output the stacktrace to
00134   // STDERR (if we can) and reissue the signal to die...
00135   PrintStackTrace();
00136   signal(Sig, SIG_DFL);
00137 }
00138 
00139 // Just call signal
00140 void RegisterHandler(int Signal) { 
00141   signal(Signal, SignalHandler); 
00142 }
00143 
00144 }
00145 
00146 namespace llvm {
00147 
00148 void sys::SetInterruptFunction(void (*IF)()) {
00149   InterruptFunction = IF;
00150   RegisterHandler(SIGINT);
00151 }
00152 
00153 // RemoveFileOnSignal - The public API
00154 void sys::RemoveFileOnSignal(const sys::Path &Filename) {
00155   if (FilesToRemove == 0)
00156     FilesToRemove = new std::vector<std::string>;
00157 
00158   FilesToRemove->push_back(Filename.toString());
00159 
00160   std::for_each(IntSigs, IntSigsEnd, RegisterHandler);
00161   std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
00162 }
00163 
00164 // RemoveDirectoryOnSignal - The public API
00165 void sys::RemoveDirectoryOnSignal(const llvm::sys::Path& path) {
00166   if (!path.isDirectory())
00167     return;
00168 
00169   if (DirectoriesToRemove == 0)
00170     DirectoriesToRemove = new std::vector<sys::Path>;
00171 
00172   DirectoriesToRemove->push_back(path);
00173 
00174   std::for_each(IntSigs, IntSigsEnd, RegisterHandler);
00175   std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
00176 }
00177 
00178 /// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
00179 /// SIGSEGV) is delivered to the process, print a stack trace and then exit.
00180 void sys::PrintStackTraceOnErrorSignal() {
00181   std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
00182 }
00183 
00184 }
00185