Sierra Toolkit  Version of the Day
SignalHandler.cpp
1 
10 #include <stdexcept>
11 #include <vector>
12 #include <iostream>
13 
15 
16 #include <signal.h>
17 #include <time.h>
18 
19 extern "C" {
20  static void signal_handler(int signal, siginfo_t *sip, void *ucp)
21  {
22  // This routine is called for all signals...
23  // Just a C-callable wrapper around a call to the true signal handler...
25  }
26 }
27 
28 namespace sierra {
29 
30 namespace {
31 
32 int
33 convert_name_to_signal(
34  const String & signal)
35 {
36  if (signal == "SIGABRT" || signal == "SIGKILL") {
37  return -1;
38  }
39 
40 #if defined(SIGILL)
41  if (signal == "SIGILL") return SIGILL;
42 #endif
43 #if defined(SIGSEGV)
44  if (signal == "SIGSEGV") return SIGSEGV;
45 #endif
46 #if defined(SIGALRM)
47  if (signal == "SIGALRM") return SIGALRM;
48 #endif
49 #if defined(SIGFPE)
50  if (signal == "SIGFPE") return SIGFPE;
51 #endif
52 #if defined(SIGHUP)
53  if (signal == "SIGHUP") return SIGHUP;
54 #endif
55 #if defined(SIGINT)
56  if (signal == "SIGINT") return SIGINT;
57 #endif
58 #if defined(SIGPIPE)
59  if (signal == "SIGPIPE") return SIGPIPE;
60 #endif
61 #if defined(SIGQUIT)
62  if (signal == "SIGQUIT") return SIGQUIT;
63 #endif
64 #if defined(SIGTERM)
65  if (signal == "SIGTERM") return SIGTERM;
66 #endif
67 #if defined(SIGUSR1)
68  if (signal == "SIGUSR1") return SIGUSR1;
69 #endif
70 #if defined(SIGUSR2)
71  if (signal == "SIGUSR2") return SIGUSR2;
72 #endif
73  return -2;
74 }
75 
76 } // namespace <unnamed>
77 
78 
79 SignalHandler &
81  static SignalHandler signal_handler;
82 
83  return signal_handler;
84 }
85 
86 
87 void
89  int signal)
90 {
91  typedef std::vector<const HandlerMap::value_type *> HandlerList;
92 
93  time_t now = ::time(NULL);
94 
95  std::cerr << "Sierra received signal " << signal << " at " << ::ctime(&now) << std::endl;
96 
97  HandlerList handlers;
98 
99  std::pair<HandlerMap::const_iterator, HandlerMap::const_iterator> range = m_handlerMap.equal_range(signal);
100 
101  for (HandlerMap::const_iterator pos = range.first; pos != range.second; ++pos)
102  handlers.push_back(&*pos);
103 
104  for (HandlerList::const_iterator it = handlers.begin(); it != handlers.end(); ++it) {
105  CallbackBase &obj = *(*it)->second;
106  obj();
107  }
108 }
109 
110 
111 bool
112 SignalHandler::check_signal_name(
113  const String & signal)
114 {
115  int isignal = convert_name_to_signal(signal);
116  return (isignal >= 0);
117 }
118 
119 
120 void
122  const String & signal,
123  CallbackBase & callback)
124 {
125  int isignal = convert_name_to_signal(signal);
126  if (isignal >= 0) {
127  add_handler(isignal, callback);
128  }
129  else if (isignal == -1)
130  throw std::runtime_error("signal cannot be handled");
131  else if (isignal == -2)
132  throw std::runtime_error("signal name invalid");
133  else
134  throw std::logic_error("invalid value from convert_node_to_signal()");
135 }
136 
137 
138 void
140  int signal,
141  CallbackBase & callback)
142 {
143  // See if already handling this signal...
144  if (m_handlerMap.find(signal) == m_handlerMap.end()) {
145  // Tell OS that we want to handle this signal...
146  struct sigaction action;
147  struct sigaction *old_action = new struct sigaction;
148 
149  action.sa_sigaction = signal_handler;
150  sigemptyset(&action.sa_mask);
151  action.sa_flags = SA_SIGINFO;
152  ::sigaction(signal, &action, old_action);
153  m_oldActionMap.insert(OldActionMap::value_type(signal, old_action));
154  }
155  m_handlerMap.insert(HandlerMap::value_type(signal, &callback));
156 }
157 
158 
159 void
161  int signal,
162  CallbackBase & callback)
163 {
164  typedef std::pair<HandlerMap::iterator, HandlerMap::iterator> HandlerRange;
165 
166  HandlerRange handler_range = m_handlerMap.equal_range(signal);
167  for (HandlerMap::iterator it = handler_range.first; it != handler_range.second; )
168  if ((*it).second == &callback) {
169  HandlerMap::iterator erase_it = it++;
170  m_handlerMap.erase(erase_it);
171  }
172  else
173  ++it;
174 
175  if (m_handlerMap.find(signal) == m_handlerMap.end()) {
176  OldActionMap::iterator it = m_oldActionMap.find(signal);
177  if (it != m_oldActionMap.end()) {
178  ::sigaction(signal, (*it).second, NULL);
179  delete (*it).second;
180  m_oldActionMap.erase(it);
181  }
182  }
183 }
184 
185 
186 void
188  const String & signal,
189  CallbackBase & callback)
190 {
191  int isignal = convert_name_to_signal(signal);
192  if (isignal >= 0) {
193  remove_handler(isignal, callback);
194  }
195  else if (isignal == -1)
196  throw std::runtime_error("signal cannot be handled");
197  else if (isignal == -2)
198  throw std::runtime_error("signal name invalid");
199  else
200  throw std::logic_error("invalid value from convert_node_to_signal()");
201 }
202 
203 
204 void
206 {
207  m_handlerMap.clear();
208 
209  for (OldActionMap::iterator it = m_oldActionMap.begin(); it != m_oldActionMap.end(); ++it) {
210  ::sigaction((*it).first, (*it).second, NULL);
211  delete (*it).second;
212  }
213  m_oldActionMap.clear();
214 }
215 
216 
217 } // namespace sierra
Definition: Env.cpp:53
void remove_all_handlers()
Member function remove_all_handlers ...
void remove_handler(int signal, CallbackBase &callback)
Member function remove_handler ...
Class SignalHandler ...
static SignalHandler & instance()
Member function instance ...
void add_handler(int signal, CallbackBase &callback)
Member function add_handler ...
void handle_signal(int signal)
Member function handle_signal ...
Class Callback ...
Definition: Callback.hpp:31