Fix spelling and grammar in a comment.
[oota-llvm.git] / lib / System / Unix / Signals.inc
1 //===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===//
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 // This file defines some helpful functions for dealing with the possibility of
11 // Unix signals occuring while your program is running.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "Unix.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include <vector>
18 #include <algorithm>
19 #if HAVE_EXECINFO_H
20 # include <execinfo.h>         // For backtrace().
21 #endif
22 #if HAVE_SIGNAL_H
23 #include <signal.h>
24 #endif
25 #if HAVE_SYS_STAT_H
26 #include <sys/stat.h>
27 #endif
28 using namespace llvm;
29
30 namespace {
31
32 static bool StackTraceRequested = false; 
33
34 /// InterruptFunction - The function to call if ctrl-c is pressed.
35 static void (*InterruptFunction)() = 0;
36
37 static std::vector<sys::Path> *FilesToRemove = 0 ;
38 static std::vector<sys::Path> *DirectoriesToRemove = 0;
39
40 // IntSigs - Signals that may interrupt the program at any time.
41 static const int IntSigs[] = {
42   SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2
43 };
44 static const int *const IntSigsEnd =
45   IntSigs + sizeof(IntSigs) / sizeof(IntSigs[0]);
46
47 // KillSigs - Signals that are synchronous with the program that will cause it
48 // to die.
49 static const int KillSigs[] = {
50   SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGSYS, SIGXCPU, SIGXFSZ
51 #ifdef SIGEMT
52   , SIGEMT
53 #endif
54 };
55 static const int *const KillSigsEnd =
56   KillSigs + sizeof(KillSigs) / sizeof(KillSigs[0]);
57
58 #ifdef HAVE_BACKTRACE
59 static void* StackTrace[256];
60 #endif
61
62 // PrintStackTrace - In the case of a program crash or fault, print out a stack
63 // trace so that the user has an indication of why and where we died.
64 //
65 // On glibc systems we have the 'backtrace' function, which works nicely, but
66 // doesn't demangle symbols.  
67 static void PrintStackTrace() {
68 #ifdef HAVE_BACKTRACE
69   // Use backtrace() to output a backtrace on Linux systems with glibc.
70   int depth = backtrace(StackTrace,
71                         static_cast<int>(array_lengthof(StackTrace)));
72   backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO);
73 #endif
74 }
75
76 // SignalHandler - The signal handler that runs...
77 static RETSIGTYPE SignalHandler(int Sig) {
78   if (FilesToRemove != 0)
79     while (!FilesToRemove->empty()) {
80       FilesToRemove->back().eraseFromDisk(true);
81       FilesToRemove->pop_back();
82     }
83
84   if (DirectoriesToRemove != 0)
85     while (!DirectoriesToRemove->empty()) {
86       DirectoriesToRemove->back().eraseFromDisk(true);
87       DirectoriesToRemove->pop_back();
88     }
89
90   if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) {
91     if (InterruptFunction) {
92       void (*IF)() = InterruptFunction;
93       InterruptFunction = 0;
94       IF();        // run the interrupt function.
95       return;
96     } else {
97       exit(1);   // If this is an interrupt signal, exit the program
98     }
99   }
100
101   // Otherwise if it is a fault (like SEGV) output the stacktrace to
102   // STDERR (if we can) and reissue the signal to die...
103   if (StackTraceRequested)
104     PrintStackTrace();
105   signal(Sig, SIG_DFL);
106 }
107
108 // Just call signal
109 static void RegisterHandler(int Signal) { 
110   signal(Signal, SignalHandler); 
111 }
112
113 }
114
115
116 void sys::SetInterruptFunction(void (*IF)()) {
117   InterruptFunction = IF;
118   RegisterHandler(SIGINT);
119 }
120
121 // RemoveFileOnSignal - The public API
122 bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) {
123   if (FilesToRemove == 0)
124     FilesToRemove = new std::vector<sys::Path>;
125
126   FilesToRemove->push_back(Filename);
127
128   std::for_each(IntSigs, IntSigsEnd, RegisterHandler);
129   std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
130   return false;
131 }
132
133 // RemoveDirectoryOnSignal - The public API
134 bool sys::RemoveDirectoryOnSignal(const sys::Path& path, std::string* ErrMsg) {
135   // Not a directory?
136   struct stat buf;
137   if (0 != stat(path.c_str(), &buf)) {
138     MakeErrMsg(ErrMsg, path.toString() + ": can't get status of file");
139     return true;
140   }
141
142   if (!S_ISDIR(buf.st_mode)) {
143     if (ErrMsg)
144       *ErrMsg = path.toString() + " is not a directory";
145     return true;
146   }
147
148   if (DirectoriesToRemove == 0)
149     DirectoriesToRemove = new std::vector<sys::Path>;
150
151   DirectoriesToRemove->push_back(path);
152
153   std::for_each(IntSigs, IntSigsEnd, RegisterHandler);
154   std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
155   return false;
156 }
157
158 /// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
159 /// SIGSEGV) is delivered to the process, print a stack trace and then exit.
160 void sys::PrintStackTraceOnErrorSignal() {
161   StackTraceRequested = true;
162   std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
163 }