libdap  Updated for version 3.20.6
libdap4 is an implementation of OPeNDAP's DAP protocol.
SignalHandler.cc
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 #include <cstdlib>
35 
36 #include <signal.h>
37 #include <pthread.h>
38 
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h> //for _exit
41 #endif
42 
43 #include "SignalHandler.h"
44 #include "util.h"
45 
46 namespace libdap {
47 
48 EventHandler *SignalHandler::d_signal_handlers[NSIG];
49 Sigfunc *SignalHandler::d_old_handlers[NSIG];
50 SignalHandler *SignalHandler::d_instance = 0;
51 
52 // instance_control is used to ensure that in a MT environment d_instance is
53 // correctly initialized.
54 static pthread_once_t instance_control = PTHREAD_ONCE_INIT;
55 
57 void
58 SignalHandler::initialize_instance()
59 {
60  // MT-Safe if called via pthread_once or similar
61  SignalHandler::d_instance = new SignalHandler;
62  atexit(SignalHandler::delete_instance);
63 }
64 
66 void
67 SignalHandler::delete_instance()
68 {
69  if (SignalHandler::d_instance) {
70  for (int i = 0; i < NSIG; ++i) {
71  // Fortify warns about a leak because the EventHandler objects
72  // are not deleted, but that's OK - this is a singleton and
73  // so the 'leak' is really just a constant amount of memory that
74  // gets used.
75  d_signal_handlers[i] = 0;
76  d_old_handlers[i] = 0;
77  }
78 
79  delete SignalHandler::d_instance;
80  SignalHandler::d_instance = 0;
81  }
82 }
83 
90 void
91 SignalHandler::dispatcher(int signum)
92 {
93  // Perform a sanity check...
94  if (SignalHandler::d_signal_handlers[signum] != 0)
95  // Dispatch the handler's hook method.
96  SignalHandler::d_signal_handlers[signum]->handle_signal(signum);
97 
98  Sigfunc *old_handler = SignalHandler::d_old_handlers[signum];
99  if (old_handler == SIG_IGN || old_handler == SIG_ERR)
100  return;
101  else if (old_handler == SIG_DFL) {
102  switch (signum) {
103 #if 0
104 #ifndef WIN32
105  case SIGHUP:
106  case SIGKILL:
107  case SIGUSR1:
108  case SIGUSR2:
109  case SIGPIPE:
110  case SIGALRM:
111 #endif
112  case SIGINT:
113  case SIGTERM: _exit(EXIT_FAILURE);
114 
115  // register_handler() should never allow any fiddling with
116  // signals other than those listed above.
117  default: abort();
118 #endif
119  // Calling _exit() or abort() is not a good thing for a library to be
120  // doing. This results in a warning from rpmlint
121  default:
122  throw Error(internal_error, "Signal handler operation on an unsupported signal.");
123  }
124  }
125  else
126  old_handler(signum);
127 }
128 
130 SignalHandler*
132 {
133  pthread_once(&instance_control, initialize_instance);
134 
135  return d_instance;
136 }
137 
150 EventHandler *
151 SignalHandler::register_handler(int signum, EventHandler *eh, bool override)
152 {
153  // Check first for improper use.
154  switch (signum) {
155 #ifndef WIN32
156  case SIGHUP:
157  case SIGKILL:
158  case SIGUSR1:
159  case SIGUSR2:
160  case SIGPIPE:
161  case SIGALRM:
162 #endif
163  case SIGINT:
164  case SIGTERM: break;
165 
166  default: throw InternalErr(__FILE__, __LINE__,
167  string("Call to register_handler with unsupported signal (")
168  + long_to_string(signum) + string(")."));
169  }
170 
171  // Save the old EventHandler
172  EventHandler *old_eh = SignalHandler::d_signal_handlers[signum];
173 
174  SignalHandler::d_signal_handlers[signum] = eh;
175 
176  // Register the dispatcher to handle this signal. See Stevens, Advanced
177  // Programming in the UNIX Environment, p.298.
178 #ifndef WIN32
179  struct sigaction sa;
180  sa.sa_handler = dispatcher;
181  sigemptyset(&sa.sa_mask);
182  sa.sa_flags = 0;
183 
184  // Try to suppress restarting system calls if we're handling an alarm.
185  // This lets alarms block I/O calls that would normally restart. 07/18/03
186  // jhrg
187  if (signum == SIGALRM) {
188 #ifdef SA_INTERUPT
189  sa.sa_flags |= SA_INTERUPT;
190 #endif
191  }
192  else {
193 #ifdef SA_RESTART
194  sa.sa_flags |= SA_RESTART;
195 #endif
196  }
197 
198  struct sigaction osa; // extract the old handler/action
199 
200  if (sigaction(signum, &sa, &osa) < 0)
201  throw InternalErr(__FILE__, __LINE__, "Could not register a signal handler.");
202 
203  // Take care of the case where this interface is used to register a
204  // handler more than once. We want to make sure that the dispatcher is
205  // not installed as the 'old handler' because that results in an infinite
206  // loop. 02/10/04 jhrg
207  if (override)
208  SignalHandler::d_old_handlers[signum] = SIG_IGN;
209  else if (osa.sa_handler != dispatcher)
210  SignalHandler::d_old_handlers[signum] = osa.sa_handler;
211 #endif
212 
213  return old_eh;
214 }
215 
219 EventHandler *
221 {
222  EventHandler *old_eh = SignalHandler::d_signal_handlers[signum];
223 
224  SignalHandler::d_signal_handlers[signum] = 0;
225 
226  return old_eh;
227 }
228 
229 } // namespace libdap
static SignalHandler * instance()
top level DAP object to house generic methods
Definition: AISConnect.cc:30
A class for software fault reporting.
Definition: InternalErr.h:64
EventHandler * register_handler(int signum, EventHandler *eh, bool override=false)
EventHandler * remove_handler(int signum)