libassa
3.5.0
|
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