libdap++  Updated for version 3.8.2
SignalHandler.cc
Go to the documentation of this file.
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 static char rcsid[] not_used =
00035     { "$Id: SignalHandler.cc 25112 2011-12-29 21:44:54Z jimg $"
00036     };
00037 
00038 #include <cstdlib>
00039 
00040 #include <signal.h>
00041 #include <pthread.h>
00042 
00043 #ifdef HAVE_UNISTD_H
00044 #include <unistd.h> //for _exit
00045 #endif
00046 
00047 #include "SignalHandler.h"
00048 #include "util.h"
00049 
00050 namespace libdap {
00051 
00052 EventHandler *SignalHandler::d_signal_handlers[NSIG];
00053 Sigfunc *SignalHandler::d_old_handlers[NSIG];
00054 SignalHandler *SignalHandler::d_instance = 0;
00055 
00056 // instance_control is used to ensure that in a MT environment d_instance is
00057 // correctly initialized.
00058 static pthread_once_t instance_control = PTHREAD_ONCE_INIT;
00059 
00061 void
00062 SignalHandler::initialize_instance()
00063 {
00064     // MT-Safe if called via pthread_once or similar
00065     SignalHandler::d_instance = new SignalHandler;
00066     atexit(SignalHandler::delete_instance);
00067 }
00068 
00070 void
00071 SignalHandler::delete_instance()
00072 {
00073     if (SignalHandler::d_instance) {
00074         for (int i = 0; i < NSIG; ++i) {
00075                 // Fortify warns about a leak because the EventHandler objects
00076                 // are not deleted, but that's OK - this is a singleton and
00077                 // so the 'leak' is really just a constant amount of memory that
00078                 // gets used.
00079                 d_signal_handlers[i] = 0;
00080             d_old_handlers[i] = 0;
00081         }
00082 
00083         delete SignalHandler::d_instance;
00084         SignalHandler::d_instance = 0;
00085     }
00086 }
00087 
00094 void
00095 SignalHandler::dispatcher(int signum)
00096 {
00097     // Perform a sanity check...
00098     if (SignalHandler::d_signal_handlers[signum] != 0)
00099         // Dispatch the handler's hook method.
00100         SignalHandler::d_signal_handlers[signum]->handle_signal(signum);
00101 
00102     Sigfunc *old_handler = SignalHandler::d_old_handlers[signum];
00103     if (old_handler == SIG_IGN || old_handler == SIG_ERR)
00104         return;
00105     else if (old_handler == SIG_DFL) {
00106         switch (signum) {
00107 #if 0
00108 #ifndef WIN32
00109         case SIGHUP:
00110         case SIGKILL:
00111         case SIGUSR1:
00112         case SIGUSR2:
00113         case SIGPIPE:
00114         case SIGALRM:
00115 #endif
00116         case SIGINT:
00117         case SIGTERM: _exit(EXIT_FAILURE);
00118 
00119             // register_handler() should never allow any fiddling with
00120             // signals other than those listed above.
00121         default: abort();
00122 #endif
00123         // Calling _exit() or abort() is not a good thing for a library to be
00124         // doing. This results in a warning from rpmlint
00125         default:
00126             throw Error("Signal handler operation on an unsupported signal.");
00127         }
00128     }
00129     else
00130         old_handler(signum);
00131 }
00132 
00134 SignalHandler*
00135 SignalHandler::instance()
00136 {
00137     pthread_once(&instance_control, initialize_instance);
00138 
00139     return d_instance;
00140 }
00141 
00154 EventHandler *
00155 SignalHandler::register_handler(int signum, EventHandler *eh, bool override)
00156 {
00157     // Check first for improper use.
00158     switch (signum) {
00159 #ifndef WIN32
00160     case SIGHUP:
00161     case SIGKILL:
00162     case SIGUSR1:
00163     case SIGUSR2:
00164     case SIGPIPE:
00165     case SIGALRM:
00166 #endif
00167     case SIGINT:
00168     case SIGTERM: break;
00169 
00170     default: throw InternalErr(__FILE__, __LINE__,
00171                                    string("Call to register_handler with unsupported signal (")
00172                                    + long_to_string(signum) + string(")."));
00173     }
00174 
00175     // Save the old EventHandler
00176     EventHandler *old_eh = SignalHandler::d_signal_handlers[signum];
00177 
00178     SignalHandler::d_signal_handlers[signum] = eh;
00179 
00180     // Register the dispatcher to handle this signal. See Stevens, Advanced
00181     // Programming in the UNIX Environment, p.298.
00182 #ifndef WIN32
00183     struct sigaction sa;
00184     sa.sa_handler = dispatcher;
00185     sigemptyset(&sa.sa_mask);
00186     sa.sa_flags = 0;
00187 
00188     // Try to suppress restarting system calls if we're handling an alarm.
00189     // This lets alarms block I/O calls that would normally restart. 07/18/03
00190     // jhrg
00191     if (signum == SIGALRM) {
00192 #ifdef SA_INTERUPT
00193         sa.sa_flags |= SA_INTERUPT;
00194 #endif
00195     }
00196     else {
00197 #ifdef SA_RESTART
00198         sa.sa_flags |= SA_RESTART;
00199 #endif
00200     }
00201 
00202     struct sigaction osa; // extract the old handler/action
00203 
00204     if (sigaction(signum, &sa, &osa) < 0)
00205         throw InternalErr(__FILE__, __LINE__, "Could not register a signal handler.");
00206 
00207     // Take care of the case where this interface is used to register a
00208     // handler more than once. We want to make sure that the dispatcher is
00209     // not installed as the 'old handler' because that results in an infinite
00210     // loop. 02/10/04 jhrg
00211     if (override)
00212         SignalHandler::d_old_handlers[signum] = SIG_IGN;
00213     else if (osa.sa_handler != dispatcher)
00214         SignalHandler::d_old_handlers[signum] = osa.sa_handler;
00215 #endif
00216 
00217     return old_eh;
00218 }
00219 
00223 EventHandler *
00224 SignalHandler::remove_handler(int signum)
00225 {
00226     EventHandler *old_eh = SignalHandler::d_signal_handlers[signum];
00227 
00228     SignalHandler::d_signal_handlers[signum] = 0;
00229 
00230     return old_eh;
00231 }
00232 
00233 } // namespace libdap