File: SigHandlers.cpp

package info (click to toggle)
libassa 3.5.1-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 3,268 kB
  • sloc: cpp: 15,703; sh: 12,083; makefile: 379; perl: 51
file content (268 lines) | stat: -rw-r--r-- 7,670 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
// -*- c++ -*-
//------------------------------------------------------------------------------
//                            SigHandlers.cpp
//------------------------------------------------------------------------------
//  Copyright (C) 1997-2002  Vladislav Grinchenko 
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//------------------------------------------------------------------------------
#include "assa/SigHandlers.h"

using namespace ASSA;

#if !defined(WIN32)

//---------------------------------------------------------------------------
// static declarations
//---------------------------------------------------------------------------

SigHandlersList* SigHandlersList::m_instance[NSIG];

void
SigHandlers::
sighandlers_dispatcher (int signum_)
{
    trace_with_mask("SigHandlers::sighandlers_dispatch", SIGHAND);

    DL((SIGHAND,"==> Recevied signal # %d\n", signum_));
    dispatch (signum_);
}

int 
SigHandlers::
install (int            signum_,
		 EventHandler*  new_hand_,
		 SigAction*     new_disp_, 
		 EventHandler** old_hand_,	
		 SigAction*     old_disp_)  
{
    /*
      Retrieve current signal disposition. If 3rd party handler has 
      already been istalled, make CFUNC_Handler out of it, and put it in 
      the list with id=0. 
	  
      Add new_hand_ to the list. Has global sighandlers_dispatcher not 
      been installed yet, install it too.
    */

    trace_with_mask("SigHandlers::install()", SIGHAND);

    if (!in_range(signum_) == -1) {
		EL((ASSAERR,"in_range (%s) failed\n",signum_));
		return -1;
    }

    CFUNC_Handler* cfhp = NULL;
    SigHandlersList* handlist = NULL;

    handlist = SigHandlersList::instance(signum_);

    /*--- Retrieve current signal disposition ---*/

    SigAction cd;
    cd.retrieve_action(signum_);

    /*
      Check whether 3rd party software has already installed 
      signal handler. 
    */
    if ( cd.handler() != (C_SIG_HANDLER) sighandlers_dispatcher &&
		 cd.handler() != SIG_IGN && 
		 cd.handler() != SIG_DFL ) 
    {
    /*
	  Looks like some other code got ahead of me and installed C-function 
	  signal handler. Make a note of it.  
	  
	  Create EventHandler to hold 3rd party handler. This handler will be 
	  deleted only by SigHandlers::remove (NULL), when application demanded 
	  to remove all of the handlers.
	*/
		DL((SIGHAND,"Detected 3rd party \"C\" handler!\n"));
		
		cfhp = new CFUNC_Handler (cd.handler ());
		handlist->cfunc_handler (cfhp);
		
		/*
		  Insert 3rd party handler in list of handlers 
		  for this signal.
		*/
		DL((SIGHAND,"Adding 3rd party \"C\" handler\n"));
		
		if ( handlist->insert (cfhp) == false ) {
			EL((ASSAERR, "Failed to insert "\
				"c_func_handler for signum %d\n", signum_));
			delete (cfhp);
			handlist->cfunc_handler (0);
			return -1;
		}
		DL((SIGHAND,"Set size: %d\n", handlist->size () ));
    }
    /*--- Add new_hand_ to the list of handlers for signum_. ---*/
	
    DL((SIGHAND,"Adding EventHandler to the list\n"));

    if (handlist->insert (new_hand_) == false) {
		/*---
		  I failed to install new handler and might have already
		  added 3rd party CFUNC_Handler to the list without altering
		  disposition - if that's true, clean up the list.
		  ---*/
		EL((ASSAERR,"failed to add new_hand_ to handlers list\n"));

		if (handlist->seen_cfunc_handler () &&
			handlist->size() == 1) 
		{
			handlist->erase ();
			handlist->cfunc_handler (0);
		}
		return -1;
    }
    DL((SIGHAND,"Set size: %d\n", handlist->size () ));

    /*--- Has sighandlers_dispatcher been already installed? ---*/

    if (cd.handler() == (C_SIG_HANDLER) sighandlers_dispatcher) {
		return 0;
    }
    DL((SIGHAND,"Installing 'sighandlers_dispatcher'\n"));

    /*
      Installing new disposition; if user forgot to give me one
      then default will be used. 
    */
    SigAction sa ((C_SIG_HANDLER) SIG_DFL);

    if (new_disp_ == 0) {
		new_disp_ = &sa;
    }
	
    new_disp_->handler ((C_SIG_HANDLER) sighandlers_dispatcher);
	    
    if (new_disp_->register_action (signum_, old_disp_) == -1) {
		/*---
		  I failed to install sighandlers_dispatcher. Up to this
		  point, if application had conventional C handler installed,
		  it still remains active. Handlers list built so far is
		  meaningless - get rid of it. ---*/
		
		EL((ASSAERR,"register_action() error\n"));
		
		if (handlist->seen_cfunc_handler ()) {
			handlist->erase ();
			handlist->cfunc_handler (0);
			delete cfhp;
		}
		handlist->erase (new_hand_);
		return -1;
    }
    return 0;
}

int
SigHandlers::
remove (int signum_, EventHandler* eh_,
		SigAction* new_disp_, SigAction* old_disp_)

{
    trace_with_mask("SigHandlers::remove()", SIGHAND);

    if (in_range (signum_)) {
		EL((ASSAERR, "singum_ %d is out of range\n", signum_));
		return -1;
    }

    CFUNC_Handler* Cfhp = NULL;	// pointer to C-function event handler
    EventHandler* ehp = NULL;	// pointer to current event handler

    SigHandlersList& handlist = *(SigHandlersList::instance(signum_));
	
    if (eh_ == NULL) {
		DL((SIGHAND,"Erasing the entire set\n"));
		/*--- Erase an entire list. ---*/
		handlist.erase ();
		DL((SIGHAND,"Set size: %d\n", handlist.size ()));
    }
    else {
        /*
		  Note: I cannot do erasure in the same loop for following  reason:
		  
		  According to Stroustrup (Section 17.4.1.7):
		  "After erase(), the iterator cannot be used again because
		  the element to which it pointed is no longer there."
		  
		  According to STL Tutorial and Ref. Guide:
		  "The erase function invalidates all iterators to all
		  positions past the point of erasure."
		  
		  That's why here we first take care of id recycling and heap memory 
		  deallocation, and only then clean() the map all at once.
		*/
		SigHandlersList::iterator it;
		
		if ((it = handlist.find (eh_)) != handlist.end ()) {
			DL((SIGHAND,"Removing EventHandler\n"));
			ehp = (*it);
			handlist.erase (it);
		}
		DL((SIGHAND,"Set size: %d\n", handlist.size () ));
    }
    /*--- If set is not empty, we're done ---*/
    if (handlist.size ()) return 0;

    /* If map was emptied out, install new disposition
       with the 3rd party "C" function handler, if we had it.
    */
    SigAction null_sa;
    if (new_disp_ == 0) new_disp_ = &null_sa;

    DL((SIGHAND,"Handlers List is empty\n"));
	
    if (handlist.seen_cfunc_handler ()) {
		/*--- Put 3rd party handler into disposition  ---*/
		DL((SIGHAND,"Reinstalling \"C\" handler\n"));
		Cfhp = handlist.cfunc_handler (0);
		new_disp_->handler (Cfhp->handler ());
		delete Cfhp;
    }
    /*--- Install new disposition ---*/
    return new_disp_->register_action (signum_, old_disp_);
}

void
SigHandlers::
dispatch (int signum_)
{
    trace_with_mask("SigHandlers::dispatch", SIGHAND);

    /*---
      For every element in the set that holds all EventHandlers for
      given signum, call its respective handle_signal() member function.
      ---*/

    /*--- save errno ---*/
    int errno_saved = errno;

    SigHandlersList& handlist = *(SigHandlersList::instance(signum_));
    SigHandlersList::iterator it;
    EventHandler* ehp;
    
    for (it=handlist.begin(); it != handlist.end(); it++) {
		ehp = *it;
		if (ehp->handle_signal (signum_) == -1) {
			/*---
			  this event handler reported error when handling
			  signum - remove it from the set
			  ---*/
			handlist.erase (it);
		}
    }
    /*--- restore errno ---*/
    errno = errno_saved;
}

#endif // !defined(WIN32)