SigHandlers.cpp

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 //------------------------------------------------------------------------------
00003 //                            SigHandlers.cpp
00004 //------------------------------------------------------------------------------
00005 //  Copyright (C) 1997-2002  Vladislav Grinchenko 
00006 //
00007 //  This library is free software; you can redistribute it and/or
00008 //  modify it under the terms of the GNU Library General Public
00009 //  License as published by the Free Software Foundation; either
00010 //  version 2 of the License, or (at your option) any later version.
00011 //------------------------------------------------------------------------------
00012 #include "assa/SigHandlers.h"
00013 
00014 using namespace ASSA;
00015 
00016 //---------------------------------------------------------------------------
00017 // static declarations
00018 //---------------------------------------------------------------------------
00019 
00020 SigHandlersList* SigHandlersList::m_instance[NSIG];
00021 
00022 void
00023 SigHandlers::
00024 sighandlers_dispatcher (int signum_)
00025 {
00026     trace_with_mask("SigHandlers::sighandlers_dispatch", SIGHAND);
00027 
00028     DL((SIGHAND,"==> Recevied signal # %d\n", signum_));
00029     dispatch (signum_);
00030 }
00031 
00032 int 
00033 SigHandlers::
00034 install (int            signum_,
00035          EventHandler*  new_hand_,
00036          SigAction*     new_disp_, 
00037          EventHandler** old_hand_,  
00038          SigAction*     old_disp_)  
00039 {
00040     /*
00041       Retrieve current signal disposition. If 3rd party handler has 
00042       already been istalled, make CFUNC_Handler out of it, and put it in 
00043       the list with id=0. 
00044       
00045       Add new_hand_ to the list. Has global sighandlers_dispatcher not 
00046       been installed yet, install it too.
00047     */
00048 
00049     trace_with_mask("SigHandlers::install()", SIGHAND);
00050 
00051     if (!in_range(signum_) == -1) {
00052         EL((ERROR,"in_range (%s) failed\n",signum_));
00053         return -1;
00054     }
00055 
00056     CFUNC_Handler* cfhp = NULL;
00057     SigHandlersList* handlist = NULL;
00058 
00059     handlist = SigHandlersList::instance(signum_);
00060 
00061     /*--- Retrieve current signal disposition ---*/
00062 
00063     SigAction cd;
00064     cd.retrieve_action(signum_);
00065 
00066     /*
00067       Check whether 3rd party software has already installed 
00068       signal handler. 
00069     */
00070     if ( cd.handler() != (C_SIG_HANDLER) sighandlers_dispatcher &&
00071          cd.handler() != SIG_IGN && 
00072          cd.handler() != SIG_DFL ) 
00073     {
00074     /*
00075       Looks like some other code got ahead of me and installed C-function 
00076       signal handler. Make a note of it.  
00077       
00078       Create EventHandler to hold 3rd party handler. This handler will be 
00079       deleted only by SigHandlers::remove (NULL), when application demanded 
00080       to remove all of the handlers.
00081     */
00082         DL((SIGHAND,"Detected 3rd party \"C\" handler!\n"));
00083         
00084         cfhp = new CFUNC_Handler (cd.handler ());
00085         handlist->cfunc_handler (cfhp);
00086         
00087         /*
00088           Insert 3rd party handler in list of handlers 
00089           for this signal.
00090         */
00091         DL((SIGHAND,"Adding 3rd party \"C\" handler\n"));
00092         
00093         if ( handlist->insert (cfhp) == false ) {
00094             EL((ERROR, "Failed to insert "\
00095                 "c_func_handler for signum %d\n", signum_));
00096             delete (cfhp);
00097             handlist->cfunc_handler (0);
00098             return -1;
00099         }
00100         DL((SIGHAND,"Set size: %d\n", handlist->size () ));
00101     }
00102     /*--- Add new_hand_ to the list of handlers for signum_. ---*/
00103     
00104     DL((SIGHAND,"Adding EventHandler to the list\n"));
00105 
00106     if (handlist->insert (new_hand_) == false) {
00107         /*---
00108           I failed to install new handler and might have already
00109           added 3rd party CFUNC_Handler to the list without altering
00110           disposition - if that's true, clean up the list.
00111           ---*/
00112         EL((ERROR,"failed to add new_hand_ to handlers list\n"));
00113 
00114         if (handlist->seen_cfunc_handler () &&
00115             handlist->size() == 1) 
00116         {
00117             handlist->erase ();
00118             handlist->cfunc_handler (0);
00119         }
00120         return -1;
00121     }
00122     DL((SIGHAND,"Set size: %d\n", handlist->size () ));
00123 
00124     /*--- Has sighandlers_dispatcher been already installed? ---*/
00125 
00126     if (cd.handler() == (C_SIG_HANDLER) sighandlers_dispatcher) {
00127         return 0;
00128     }
00129     DL((SIGHAND,"Installing 'sighandlers_dispatcher'\n"));
00130 
00131     /*
00132       Installing new disposition; if user forgot to give me one
00133       then default will be used. 
00134     */
00135     SigAction sa ((C_SIG_HANDLER) SIG_DFL);
00136 
00137     if (new_disp_ == 0) {
00138         new_disp_ = &sa;
00139     }
00140     
00141     new_disp_->handler ((C_SIG_HANDLER) sighandlers_dispatcher);
00142         
00143     if (new_disp_->register_action (signum_, old_disp_) == -1) {
00144         /*---
00145           I failed to install sighandlers_dispatcher. Up to this
00146           point, if application had conventional C handler installed,
00147           it still remains active. Handlers list built so far is
00148           meaningless - get rid of it. ---*/
00149         
00150         EL((ERROR,"register_action() error\n"));
00151         
00152         if (handlist->seen_cfunc_handler ()) {
00153             handlist->erase ();
00154             handlist->cfunc_handler (0);
00155             delete cfhp;
00156         }
00157         handlist->erase (new_hand_);
00158         return -1;
00159     }
00160     return 0;
00161 }
00162 
00163 int
00164 SigHandlers::
00165 remove (int signum_, EventHandler* eh_,
00166         SigAction* new_disp_, SigAction* old_disp_)
00167 
00168 {
00169     trace_with_mask("SigHandlers::remove()", SIGHAND);
00170 
00171     if (in_range (signum_)) {
00172         EL((ERROR, "singum_ %d is out of range\n", signum_));
00173         return -1;
00174     }
00175 
00176     CFUNC_Handler* Cfhp = NULL; // pointer to C-function event handler
00177     EventHandler* ehp = NULL;   // pointer to current event handler
00178 
00179     SigHandlersList& handlist = *(SigHandlersList::instance(signum_));
00180     
00181     if (eh_ == NULL) {
00182         DL((SIGHAND,"Erasing the entire set\n"));
00183         /*--- Erase an entire list. ---*/
00184         handlist.erase ();
00185         DL((SIGHAND,"Set size: %d\n", handlist.size ()));
00186     }
00187     else {
00188         /*
00189           Note: I cannot do erasure in the same loop for following  reason:
00190           
00191           According to Stroustrup (Section 17.4.1.7):
00192           "After erase(), the iterator cannot be used again because
00193           the element to which it pointed is no longer there."
00194           
00195           According to STL Tutorial and Ref. Guide:
00196           "The erase function invalidates all iterators to all
00197           positions past the point of erasure."
00198           
00199           That's why here we first take care of id recycling and heap memory 
00200           deallocation, and only then clean() the map all at once.
00201         */
00202         SigHandlersList::iterator it;
00203         
00204         if ((it = handlist.find (eh_)) != handlist.end ()) {
00205             DL((SIGHAND,"Removing EventHandler\n"));
00206             ehp = (*it);
00207             handlist.erase (it);
00208         }
00209         DL((SIGHAND,"Set size: %d\n", handlist.size () ));
00210     }
00211     /*--- If set is not empty, we're done ---*/
00212     if (handlist.size ()) return 0;
00213 
00214     /* If map was emptied out, install new disposition
00215        with the 3rd party "C" function handler, if we had it.
00216     */
00217     SigAction null_sa;
00218     if (new_disp_ == 0) new_disp_ = &null_sa;
00219 
00220     DL((SIGHAND,"Handlers List is empty\n"));
00221     
00222     if (handlist.seen_cfunc_handler ()) {
00223         /*--- Put 3rd party handler into disposition  ---*/
00224         DL((SIGHAND,"Reinstalling \"C\" handler\n"));
00225         Cfhp = handlist.cfunc_handler (0);
00226         new_disp_->handler (Cfhp->handler ());
00227         delete Cfhp;
00228     }
00229     /*--- Install new disposition ---*/
00230     return new_disp_->register_action (signum_, old_disp_);
00231 }
00232 
00233 void
00234 SigHandlers::
00235 dispatch (int signum_)
00236 {
00237     trace_with_mask("SigHandlers::dispatch", SIGHAND);
00238 
00239     /*---
00240       For every element in the set that holds all EventHandlers for
00241       given signum, call its respective handle_signal() member function.
00242       ---*/
00243 
00244     /*--- save errno ---*/
00245     int errno_saved = errno;
00246 
00247     SigHandlersList& handlist = *(SigHandlersList::instance(signum_));
00248     SigHandlersList::iterator it;
00249     EventHandler* ehp;
00250     
00251     for (it=handlist.begin(); it != handlist.end(); it++) {
00252         ehp = *it;
00253         if (ehp->handle_signal (signum_) == -1) {
00254             /*---
00255               this event handler reported error when handling
00256               signum - remove it from the set
00257               ---*/
00258             handlist.erase (it);
00259         }
00260     }
00261     /*--- restore errno ---*/
00262     errno = errno_saved;
00263 }

Generated on Mon Dec 19 16:37:15 2005 for libassa by  doxygen 1.4.5