|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// -*- mode: c++; c-basic-offset:4 -*-
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This file is part of libdap, A C++ implementation of the OPeNDAP Data
|
|
Packit |
a4aae4 |
// Access Protocol.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Copyright (c) 2002,2003 OPeNDAP, Inc.
|
|
Packit |
a4aae4 |
// Author: James Gallagher <jgallagher@opendap.org>
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// This library is free software; you can redistribute it and/or
|
|
Packit |
a4aae4 |
// modify it under the terms of the GNU Lesser General Public
|
|
Packit |
a4aae4 |
// License as published by the Free Software Foundation; either
|
|
Packit |
a4aae4 |
// version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// This library is distributed in the hope that it will be useful,
|
|
Packit |
a4aae4 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
a4aae4 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
a4aae4 |
// Lesser General Public License for more details.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// You should have received a copy of the GNU Lesser General Public
|
|
Packit |
a4aae4 |
// License along with this library; if not, write to the Free Software
|
|
Packit |
a4aae4 |
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// (c) COPYRIGHT URI/MIT 1994-2002
|
|
Packit |
a4aae4 |
// Please read the full copyright statement in the file COPYRIGHT_URI.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// Authors:
|
|
Packit |
a4aae4 |
// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "config.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <cstdlib>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <signal.h>
|
|
Packit |
a4aae4 |
#include <pthread.h>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#ifdef HAVE_UNISTD_H
|
|
Packit |
a4aae4 |
#include <unistd.h> //for _exit
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "SignalHandler.h"
|
|
Packit |
a4aae4 |
#include "util.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
namespace libdap {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
EventHandler *SignalHandler::d_signal_handlers[NSIG];
|
|
Packit |
a4aae4 |
Sigfunc *SignalHandler::d_old_handlers[NSIG];
|
|
Packit |
a4aae4 |
SignalHandler *SignalHandler::d_instance = 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// instance_control is used to ensure that in a MT environment d_instance is
|
|
Packit |
a4aae4 |
// correctly initialized.
|
|
Packit |
a4aae4 |
static pthread_once_t instance_control = PTHREAD_ONCE_INIT;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/// Private static void method.
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
SignalHandler::initialize_instance()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// MT-Safe if called via pthread_once or similar
|
|
Packit |
a4aae4 |
SignalHandler::d_instance = new SignalHandler;
|
|
Packit |
a4aae4 |
atexit(SignalHandler::delete_instance);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/// Private static void method.
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
SignalHandler::delete_instance()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (SignalHandler::d_instance) {
|
|
Packit |
a4aae4 |
for (int i = 0; i < NSIG; ++i) {
|
|
Packit |
a4aae4 |
// Fortify warns about a leak because the EventHandler objects
|
|
Packit |
a4aae4 |
// are not deleted, but that's OK - this is a singleton and
|
|
Packit |
a4aae4 |
// so the 'leak' is really just a constant amount of memory that
|
|
Packit |
a4aae4 |
// gets used.
|
|
Packit |
a4aae4 |
d_signal_handlers[i] = 0;
|
|
Packit |
a4aae4 |
d_old_handlers[i] = 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
delete SignalHandler::d_instance;
|
|
Packit |
a4aae4 |
SignalHandler::d_instance = 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** This private method is the adapter between the C-style interface of the
|
|
Packit |
a4aae4 |
signal subsystem and C++'s method interface. This uses the lookup table
|
|
Packit |
a4aae4 |
to find an instance of EventHandler and calls that instance's
|
|
Packit |
a4aae4 |
handle_signal method.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param signum The number of the signal. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
SignalHandler::dispatcher(int signum)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// Perform a sanity check...
|
|
Packit |
a4aae4 |
if (SignalHandler::d_signal_handlers[signum] != 0)
|
|
Packit |
a4aae4 |
// Dispatch the handler's hook method.
|
|
Packit |
a4aae4 |
SignalHandler::d_signal_handlers[signum]->handle_signal(signum);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Sigfunc *old_handler = SignalHandler::d_old_handlers[signum];
|
|
Packit |
a4aae4 |
if (old_handler == SIG_IGN || old_handler == SIG_ERR)
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
else if (old_handler == SIG_DFL) {
|
|
Packit |
a4aae4 |
switch (signum) {
|
|
Packit |
a4aae4 |
#if 0
|
|
Packit |
a4aae4 |
#ifndef WIN32
|
|
Packit |
a4aae4 |
case SIGHUP:
|
|
Packit |
a4aae4 |
case SIGKILL:
|
|
Packit |
a4aae4 |
case SIGUSR1:
|
|
Packit |
a4aae4 |
case SIGUSR2:
|
|
Packit |
a4aae4 |
case SIGPIPE:
|
|
Packit |
a4aae4 |
case SIGALRM:
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
case SIGINT:
|
|
Packit |
a4aae4 |
case SIGTERM: _exit(EXIT_FAILURE);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// register_handler() should never allow any fiddling with
|
|
Packit |
a4aae4 |
// signals other than those listed above.
|
|
Packit |
a4aae4 |
default: abort();
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
// Calling _exit() or abort() is not a good thing for a library to be
|
|
Packit |
a4aae4 |
// doing. This results in a warning from rpmlint
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
throw Error(internal_error, "Signal handler operation on an unsupported signal.");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
old_handler(signum);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Get a pointer to the single instance of SignalHandler. */
|
|
Packit |
a4aae4 |
SignalHandler*
|
|
Packit |
a4aae4 |
SignalHandler::instance()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
pthread_once(&instance_control, initialize_instance);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return d_instance;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Register an event handler. By default run any previously registered
|
|
Packit |
a4aae4 |
action/handler such as those installed using \c sigaction(). For signals
|
|
Packit |
a4aae4 |
such as SIGALRM (the alarm signal) this may not be what you want; see the
|
|
Packit |
a4aae4 |
\e override parameter. See also the class description.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param signum Bind the event handler to this signal number. Limited to
|
|
Packit |
a4aae4 |
those signals that, according to POSIX.1, cause process termination.
|
|
Packit |
a4aae4 |
@param eh A pointer to the EventHandler for \c signum.
|
|
Packit |
a4aae4 |
@param override If \c true, do not run the default handler/action.
|
|
Packit |
a4aae4 |
Instead run \e eh and then treat the signal as if the original action was
|
|
Packit |
a4aae4 |
SIG_IGN. Default is false.
|
|
Packit |
a4aae4 |
@return A pointer to the old EventHandler or null. */
|
|
Packit |
a4aae4 |
EventHandler *
|
|
Packit |
a4aae4 |
SignalHandler::register_handler(int signum, EventHandler *eh, bool override)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// Check first for improper use.
|
|
Packit |
a4aae4 |
switch (signum) {
|
|
Packit |
a4aae4 |
#ifndef WIN32
|
|
Packit |
a4aae4 |
case SIGHUP:
|
|
Packit |
a4aae4 |
case SIGKILL:
|
|
Packit |
a4aae4 |
case SIGUSR1:
|
|
Packit |
a4aae4 |
case SIGUSR2:
|
|
Packit |
a4aae4 |
case SIGPIPE:
|
|
Packit |
a4aae4 |
case SIGALRM:
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
case SIGINT:
|
|
Packit |
a4aae4 |
case SIGTERM: break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default: throw InternalErr(__FILE__, __LINE__,
|
|
Packit |
a4aae4 |
string("Call to register_handler with unsupported signal (")
|
|
Packit |
a4aae4 |
+ long_to_string(signum) + string(")."));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Save the old EventHandler
|
|
Packit |
a4aae4 |
EventHandler *old_eh = SignalHandler::d_signal_handlers[signum];
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
SignalHandler::d_signal_handlers[signum] = eh;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Register the dispatcher to handle this signal. See Stevens, Advanced
|
|
Packit |
a4aae4 |
// Programming in the UNIX Environment, p.298.
|
|
Packit |
a4aae4 |
#ifndef WIN32
|
|
Packit |
a4aae4 |
struct sigaction sa;
|
|
Packit |
a4aae4 |
sa.sa_handler = dispatcher;
|
|
Packit |
a4aae4 |
sigemptyset(&sa.sa_mask);
|
|
Packit |
a4aae4 |
sa.sa_flags = 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Try to suppress restarting system calls if we're handling an alarm.
|
|
Packit |
a4aae4 |
// This lets alarms block I/O calls that would normally restart. 07/18/03
|
|
Packit |
a4aae4 |
// jhrg
|
|
Packit |
a4aae4 |
if (signum == SIGALRM) {
|
|
Packit |
a4aae4 |
#ifdef SA_INTERUPT
|
|
Packit |
a4aae4 |
sa.sa_flags |= SA_INTERUPT;
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
#ifdef SA_RESTART
|
|
Packit |
a4aae4 |
sa.sa_flags |= SA_RESTART;
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
struct sigaction osa; // extract the old handler/action
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (sigaction(signum, &sa, &osa) < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not register a signal handler.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Take care of the case where this interface is used to register a
|
|
Packit |
a4aae4 |
// handler more than once. We want to make sure that the dispatcher is
|
|
Packit |
a4aae4 |
// not installed as the 'old handler' because that results in an infinite
|
|
Packit |
a4aae4 |
// loop. 02/10/04 jhrg
|
|
Packit |
a4aae4 |
if (override)
|
|
Packit |
a4aae4 |
SignalHandler::d_old_handlers[signum] = SIG_IGN;
|
|
Packit |
a4aae4 |
else if (osa.sa_handler != dispatcher)
|
|
Packit |
a4aae4 |
SignalHandler::d_old_handlers[signum] = osa.sa_handler;
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return old_eh;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Remove the event hander.
|
|
Packit |
a4aae4 |
@param signum The signal number of the handler to remove.
|
|
Packit |
a4aae4 |
@return The old event handler */
|
|
Packit |
a4aae4 |
EventHandler *
|
|
Packit |
a4aae4 |
SignalHandler::remove_handler(int signum)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
EventHandler *old_eh = SignalHandler::d_signal_handlers[signum];
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
SignalHandler::d_signal_handlers[signum] = 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return old_eh;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
} // namespace libdap
|