libdap++  Updated for version 3.8.2
SignalHandler.cc
Go to the documentation of this file.
1 
2 // -*- mode: c++; c-basic-offset:4 -*-
3 
4 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
5 // Access Protocol.
6 
7 // Copyright (c) 2002,2003 OPeNDAP, Inc.
8 // Author: James Gallagher <jgallagher@opendap.org>
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 //
24 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25 
26 // (c) COPYRIGHT URI/MIT 1994-2002
27 // Please read the full copyright statement in the file COPYRIGHT_URI.
28 //
29 // Authors:
30 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
31 
32 #include "config.h"
33 
34 static char rcsid[] not_used =
35  { "$Id: SignalHandler.cc 22703 2010-05-11 18:10:01Z jimg $"
36  };
37 
38 #include <cstdlib>
39 
40 #include <signal.h>
41 #include <pthread.h>
42 
43 #ifdef HAVE_UNISTD_H
44 #include <unistd.h> //for _exit
45 #endif
46 
47 #include "SignalHandler.h"
48 #include "util.h"
49 
50 namespace libdap {
51 
52 EventHandler *SignalHandler::d_signal_handlers[NSIG];
53 Sigfunc *SignalHandler::d_old_handlers[NSIG];
54 SignalHandler *SignalHandler::d_instance = 0;
55 
56 // instance_control is used to ensure that in a MT environment d_instance is
57 // correctly initialized.
58 static pthread_once_t instance_control = PTHREAD_ONCE_INIT;
59 
61 void
62 SignalHandler::initialize_instance()
63 {
64  // MT-Safe if called via pthread_once or similar
65  SignalHandler::d_instance = new SignalHandler;
66  atexit(SignalHandler::delete_instance);
67 }
68 
70 void
71 SignalHandler::delete_instance()
72 {
73  if (SignalHandler::d_instance) {
74  for (int i = 0; i < NSIG; ++i) {
75  // Fortify warns about a leak because the EventHandler objects
76  // are not deleted, but that's OK - this is a singleton and
77  // so the 'leak' is really just a constant amount of memory that
78  // gets used.
79  d_signal_handlers[i] = 0;
80  d_old_handlers[i] = 0;
81  }
82 
83  delete SignalHandler::d_instance;
84  SignalHandler::d_instance = 0;
85  }
86 }
87 
94 void
95 SignalHandler::dispatcher(int signum)
96 {
97  // Perform a sanity check...
98  if (SignalHandler::d_signal_handlers[signum] != 0)
99  // Dispatch the handler's hook method.
100  SignalHandler::d_signal_handlers[signum]->handle_signal(signum);
101 
102  Sigfunc *old_handler = SignalHandler::d_old_handlers[signum];
103  if (old_handler == SIG_IGN || old_handler == SIG_ERR)
104  return;
105  else if (old_handler == SIG_DFL) {
106  switch (signum) {
107 #ifndef WIN32
108  case SIGHUP:
109  case SIGKILL:
110  case SIGUSR1:
111  case SIGUSR2:
112  case SIGPIPE:
113  case SIGALRM:
114 #endif
115  case SIGINT:
116  case SIGTERM: _exit(EXIT_FAILURE);
117 
118  // register_handler() should never allow any fiddling with
119  // signals other than those listed above.
120  default: abort();
121  }
122  }
123  else
124  old_handler(signum);
125 }
126 
128 SignalHandler*
130 {
131  pthread_once(&instance_control, initialize_instance);
132 
133  return d_instance;
134 }
135 
148 EventHandler *
149 SignalHandler::register_handler(int signum, EventHandler *eh, bool override)
150 {
151  // Check first for improper use.
152  switch (signum) {
153 #ifndef WIN32
154  case SIGHUP:
155  case SIGKILL:
156  case SIGUSR1:
157  case SIGUSR2:
158  case SIGPIPE:
159  case SIGALRM:
160 #endif
161  case SIGINT:
162  case SIGTERM: break;
163 
164  default: throw InternalErr(__FILE__, __LINE__,
165  string("Call to register_handler with unsupported signal (")
166  + long_to_string(signum) + string(")."));
167  }
168 
169  // Save the old EventHandler
170  EventHandler *old_eh = SignalHandler::d_signal_handlers[signum];
171 
172  SignalHandler::d_signal_handlers[signum] = eh;
173 
174  // Register the dispatcher to handle this signal. See Stevens, Advanced
175  // Programming in the UNIX Environment, p.298.
176 #ifndef WIN32
177  struct sigaction sa;
178  sa.sa_handler = dispatcher;
179  sigemptyset(&sa.sa_mask);
180  sa.sa_flags = 0;
181 
182  // Try to suppress restarting system calls if we're handling an alarm.
183  // This lets alarms block I/O calls that would normally restart. 07/18/03
184  // jhrg
185  if (signum == SIGALRM) {
186 #ifdef SA_INTERUPT
187  sa.sa_flags |= SA_INTERUPT;
188 #endif
189  }
190  else {
191 #ifdef SA_RESTART
192  sa.sa_flags |= SA_RESTART;
193 #endif
194  }
195 
196  struct sigaction osa; // extract the old handler/action
197 
198  if (sigaction(signum, &sa, &osa) < 0)
199  throw InternalErr(__FILE__, __LINE__, "Could not register a signal handler.");
200 
201  // Take care of the case where this interface is used to register a
202  // handler more than once. We want to make sure that the dispatcher is
203  // not installed as the 'old handler' because that results in an infinite
204  // loop. 02/10/04 jhrg
205  if (override)
206  SignalHandler::d_old_handlers[signum] = SIG_IGN;
207  else if (osa.sa_handler != dispatcher)
208  SignalHandler::d_old_handlers[signum] = osa.sa_handler;
209 #endif
210 
211  return old_eh;
212 }
213 
217 EventHandler *
219 {
220  EventHandler *old_eh = SignalHandler::d_signal_handlers[signum];
221 
222  SignalHandler::d_signal_handlers[signum] = 0;
223 
224  return old_eh;
225 }
226 
227 } // namespace libdap
#define not_used
Definition: config.h:850
static SignalHandler * instance()
A class for software fault reporting.
Definition: InternalErr.h:64
string long_to_string(long val, int base)
Definition: util.cc:440
EventHandler * register_handler(int signum, EventHandler *eh, bool override=false)
void Sigfunc(int)
Definition: SignalHandler.h:37
EventHandler * remove_handler(int signum)