libdap  Updated for version 3.17.0
SignalHandler.cc
00001 
00002 // -*- mode: c++; c-basic-offset:4 -*-
00003 
00004 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
00005 // Access Protocol.
00006 
00007 // Copyright (c) 2002,2003 OPeNDAP, Inc.
00008 // Author: James Gallagher <jgallagher@opendap.org>
00009 //
00010 // This library is free software; you can redistribute it and/or
00011 // modify it under the terms of the GNU Lesser General Public
00012 // License as published by the Free Software Foundation; either
00013 // version 2.1 of the License, or (at your option) any later version.
00014 //
00015 // This library is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00023 //
00024 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00025 
00026 // (c) COPYRIGHT URI/MIT 1994-2002
00027 // Please read the full copyright statement in the file COPYRIGHT_URI.
00028 //
00029 // Authors:
00030 //      jhrg,jimg       James Gallagher <jgallagher@gso.uri.edu>
00031 
00032 #include "config.h"
00033 
00034 #include <cstdlib>
00035 
00036 #include <signal.h>
00037 #include <pthread.h>
00038 
00039 #ifdef HAVE_UNISTD_H
00040 #include <unistd.h> //for _exit
00041 #endif
00042 
00043 #include "SignalHandler.h"
00044 #include "util.h"
00045 
00046 namespace libdap {
00047 
00048 EventHandler *SignalHandler::d_signal_handlers[NSIG];
00049 Sigfunc *SignalHandler::d_old_handlers[NSIG];
00050 SignalHandler *SignalHandler::d_instance = 0;
00051 
00052 // instance_control is used to ensure that in a MT environment d_instance is
00053 // correctly initialized.
00054 static pthread_once_t instance_control = PTHREAD_ONCE_INIT;
00055 
00057 void
00058 SignalHandler::initialize_instance()
00059 {
00060     // MT-Safe if called via pthread_once or similar
00061     SignalHandler::d_instance = new SignalHandler;
00062     atexit(SignalHandler::delete_instance);
00063 }
00064 
00066 void
00067 SignalHandler::delete_instance()
00068 {
00069     if (SignalHandler::d_instance) {
00070         for (int i = 0; i < NSIG; ++i) {
00071                 // Fortify warns about a leak because the EventHandler objects
00072                 // are not deleted, but that's OK - this is a singleton and
00073                 // so the 'leak' is really just a constant amount of memory that
00074                 // gets used.
00075                 d_signal_handlers[i] = 0;
00076             d_old_handlers[i] = 0;
00077         }
00078 
00079         delete SignalHandler::d_instance;
00080         SignalHandler::d_instance = 0;
00081     }
00082 }
00083 
00090 void
00091 SignalHandler::dispatcher(int signum)
00092 {
00093     // Perform a sanity check...
00094     if (SignalHandler::d_signal_handlers[signum] != 0)
00095         // Dispatch the handler's hook method.
00096         SignalHandler::d_signal_handlers[signum]->handle_signal(signum);
00097 
00098     Sigfunc *old_handler = SignalHandler::d_old_handlers[signum];
00099     if (old_handler == SIG_IGN || old_handler == SIG_ERR)
00100         return;
00101     else if (old_handler == SIG_DFL) {
00102         switch (signum) {
00103 #if 0
00104 #ifndef WIN32
00105         case SIGHUP:
00106         case SIGKILL:
00107         case SIGUSR1:
00108         case SIGUSR2:
00109         case SIGPIPE:
00110         case SIGALRM:
00111 #endif
00112         case SIGINT:
00113         case SIGTERM: _exit(EXIT_FAILURE);
00114 
00115             // register_handler() should never allow any fiddling with
00116             // signals other than those listed above.
00117         default: abort();
00118 #endif
00119         // Calling _exit() or abort() is not a good thing for a library to be
00120         // doing. This results in a warning from rpmlint
00121         default:
00122             throw Error(internal_error, "Signal handler operation on an unsupported signal.");
00123         }
00124     }
00125     else
00126         old_handler(signum);
00127 }
00128 
00130 SignalHandler*
00131 SignalHandler::instance()
00132 {
00133     pthread_once(&instance_control, initialize_instance);
00134 
00135     return d_instance;
00136 }
00137 
00150 EventHandler *
00151 SignalHandler::register_handler(int signum, EventHandler *eh, bool override)
00152 {
00153     // Check first for improper use.
00154     switch (signum) {
00155 #ifndef WIN32
00156         case SIGHUP:
00157         case SIGKILL:
00158         case SIGUSR1:
00159         case SIGUSR2:
00160         case SIGPIPE:
00161         case SIGALRM:
00162 #endif
00163         case SIGINT:
00164         case SIGTERM: break;
00165 
00166         default: throw InternalErr(__FILE__, __LINE__,
00167                 string("Call to register_handler with unsupported signal (")
00168                 + long_to_string(signum) + string(")."));
00169     }
00170 
00171     // Save the old EventHandler
00172     EventHandler *old_eh = SignalHandler::d_signal_handlers[signum];
00173 
00174     SignalHandler::d_signal_handlers[signum] = eh;
00175 
00176     // Register the dispatcher to handle this signal. See Stevens, Advanced
00177     // Programming in the UNIX Environment, p.298.
00178 #ifndef WIN32
00179     struct sigaction sa;
00180     sa.sa_handler = dispatcher;
00181     sigemptyset(&sa.sa_mask);
00182     sa.sa_flags = 0;
00183 
00184     // Try to suppress restarting system calls if we're handling an alarm.
00185     // This lets alarms block I/O calls that would normally restart. 07/18/03
00186     // jhrg
00187     if (signum == SIGALRM) {
00188 #ifdef SA_INTERUPT
00189         sa.sa_flags |= SA_INTERUPT;
00190 #endif
00191     }
00192     else {
00193 #ifdef SA_RESTART
00194         sa.sa_flags |= SA_RESTART;
00195 #endif
00196     }
00197 
00198     struct sigaction osa; // extract the old handler/action
00199 
00200     if (sigaction(signum, &sa, &osa) < 0)
00201         throw InternalErr(__FILE__, __LINE__, "Could not register a signal handler.");
00202 
00203     // Take care of the case where this interface is used to register a
00204     // handler more than once. We want to make sure that the dispatcher is
00205     // not installed as the 'old handler' because that results in an infinite
00206     // loop. 02/10/04 jhrg
00207     if (override)
00208         SignalHandler::d_old_handlers[signum] = SIG_IGN;
00209     else if (osa.sa_handler != dispatcher)
00210         SignalHandler::d_old_handlers[signum] = osa.sa_handler;
00211 #endif
00212 
00213     return old_eh;
00214 }
00215 
00219 EventHandler *
00220 SignalHandler::remove_handler(int signum)
00221 {
00222     EventHandler *old_eh = SignalHandler::d_signal_handlers[signum];
00223 
00224     SignalHandler::d_signal_handlers[signum] = 0;
00225 
00226     return old_eh;
00227 }
00228 
00229 } // namespace libdap