libdap Updated for version 3.20.11
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
46namespace libdap {
47
48EventHandler *SignalHandler::d_signal_handlers[NSIG];
49Sigfunc *SignalHandler::d_old_handlers[NSIG];
50SignalHandler *SignalHandler::d_instance = 0;
51
52// instance_control is used to ensure that in a MT environment d_instance is
53// correctly initialized.
54static pthread_once_t instance_control = PTHREAD_ONCE_INIT;
55
57void
58SignalHandler::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
66void
67SignalHandler::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
90void
91SignalHandler::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
130SignalHandler*
132{
133 pthread_once(&instance_control, initialize_instance);
134
135 return d_instance;
136}
137
151SignalHandler::register_handler(int signum, EventHandler *eh, bool ignore_by_default)
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 (ignore_by_default)
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
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
A class for software fault reporting.
Definition: InternalErr.h:65
EventHandler * register_handler(int signum, EventHandler *eh, bool ignore_by_default=false)
static SignalHandler * instance()
EventHandler * remove_handler(int signum)
top level DAP object to house generic methods
Definition: AlarmHandler.h:36