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

Generated on Sun Aug 13 15:08:00 2006 for libassa by  doxygen 1.4.6