1 |
torben |
26 |
// |
2 |
|
|
// C++ Implementation: %{MODULE} |
3 |
|
|
// |
4 |
|
|
// Description: |
5 |
|
|
// |
6 |
|
|
// |
7 |
|
|
// Author: %{AUTHOR} <%{EMAIL}>, (C) %{YEAR} |
8 |
|
|
// |
9 |
|
|
// Copyright: See COPYING file that comes with this distribution |
10 |
|
|
// |
11 |
|
|
// |
12 |
|
|
#include "PosixSignalDispatcher.h" |
13 |
|
|
#include "PosixSignalHandler.h" |
14 |
|
|
#include <map> |
15 |
|
|
#include <errno.h> |
16 |
|
|
#include <signal.h> |
17 |
torben |
114 |
#include <stdlib.h> |
18 |
|
|
#include <string.h> |
19 |
torben |
26 |
|
20 |
|
|
namespace |
21 |
|
|
{ |
22 |
torben |
196 |
/** |
23 |
|
|
* Implementation class for the PosixSignalDispatcher. |
24 |
|
|
*/ |
25 |
|
|
class PosixSignalDispatcherImpl |
26 |
|
|
{ |
27 |
|
|
public: |
28 |
|
|
/* |
29 |
|
|
* As in the case of PosixSignalDispatcher, this is also |
30 |
|
|
* a singleton class. The only instance of this class can |
31 |
|
|
* be obtained using this method. |
32 |
|
|
*/ |
33 |
|
|
static |
34 |
|
|
PosixSignalDispatcherImpl& |
35 |
|
|
Instance() ; |
36 |
torben |
26 |
|
37 |
torben |
196 |
/* |
38 |
|
|
* Implementation of PosixSignalDispatcher::AttachHandler() |
39 |
|
|
*/ |
40 |
|
|
void |
41 |
|
|
AttachHandler( const int posixSignalNumber, |
42 |
|
|
PosixSignalHandler& signalHandler ) |
43 |
|
|
throw( PosixSignalDispatcher::CannotAttachHandler ) ; |
44 |
torben |
26 |
|
45 |
torben |
196 |
/* |
46 |
|
|
* Implementation of PosixSignalDispatcher::DetachHandler() |
47 |
|
|
*/ |
48 |
|
|
void |
49 |
|
|
DetachHandler( const int posixSignalNumber, |
50 |
|
|
const PosixSignalHandler& signalHandler ) |
51 |
|
|
throw( PosixSignalDispatcher::CannotDetachHandler, |
52 |
|
|
std::logic_error ) ; |
53 |
|
|
private: |
54 |
|
|
/* |
55 |
|
|
* List of signal handlers that are currently associated |
56 |
|
|
* with the dispatcher. |
57 |
|
|
*/ |
58 |
|
|
typedef std::multimap<int, PosixSignalHandler*> SignalHandlerList ; |
59 |
|
|
static SignalHandlerList mSignalHandlerList ; |
60 |
torben |
26 |
|
61 |
torben |
196 |
/* |
62 |
|
|
* List of signal handlers that were originally attached |
63 |
|
|
* to the corresponding signals. |
64 |
|
|
*/ |
65 |
|
|
typedef std::map<int, struct sigaction> OriginalSigactionList ; |
66 |
|
|
static OriginalSigactionList mOriginalSigactionList ; |
67 |
torben |
26 |
|
68 |
torben |
196 |
/* |
69 |
|
|
* Default constructor. |
70 |
|
|
*/ |
71 |
|
|
PosixSignalDispatcherImpl() ; |
72 |
torben |
26 |
|
73 |
torben |
196 |
/* |
74 |
|
|
* Destuctor. |
75 |
|
|
*/ |
76 |
|
|
~PosixSignalDispatcherImpl() ; |
77 |
torben |
26 |
|
78 |
torben |
196 |
/* |
79 |
|
|
* Static function that is used to attach the signal |
80 |
|
|
* dispatcher to a signal using sigaction(). |
81 |
|
|
*/ |
82 |
|
|
static |
83 |
|
|
void |
84 |
|
|
SigactionHandler( int signalNumber ) ; |
85 |
|
|
} ; |
86 |
torben |
26 |
|
87 |
torben |
196 |
// |
88 |
|
|
// Initialization of static members of class PosixSignalDispatcherImpl. |
89 |
|
|
// |
90 |
|
|
PosixSignalDispatcherImpl::SignalHandlerList |
91 |
|
|
PosixSignalDispatcherImpl::mSignalHandlerList ; |
92 |
torben |
26 |
|
93 |
torben |
196 |
PosixSignalDispatcherImpl::OriginalSigactionList |
94 |
|
|
PosixSignalDispatcherImpl::mOriginalSigactionList ; |
95 |
torben |
26 |
|
96 |
|
|
} ; |
97 |
|
|
|
98 |
|
|
PosixSignalDispatcher::PosixSignalDispatcher() |
99 |
|
|
{ |
100 |
torben |
196 |
/* empty */ |
101 |
torben |
26 |
} |
102 |
|
|
|
103 |
|
|
PosixSignalDispatcher::~PosixSignalDispatcher() |
104 |
|
|
{ |
105 |
torben |
196 |
/* empty */ |
106 |
torben |
26 |
} |
107 |
|
|
|
108 |
|
|
PosixSignalDispatcher& |
109 |
|
|
PosixSignalDispatcher::Instance() |
110 |
|
|
{ |
111 |
torben |
196 |
static PosixSignalDispatcher single_instance ; |
112 |
|
|
return single_instance ; |
113 |
torben |
26 |
} |
114 |
|
|
|
115 |
|
|
void |
116 |
|
|
PosixSignalDispatcher::AttachHandler( const int posixSignalNumber, |
117 |
|
|
PosixSignalHandler& signalHandler ) |
118 |
torben |
196 |
throw( CannotAttachHandler ) |
119 |
torben |
26 |
{ |
120 |
torben |
196 |
PosixSignalDispatcherImpl::Instance().AttachHandler( posixSignalNumber, |
121 |
|
|
signalHandler ) ; |
122 |
|
|
return ; |
123 |
torben |
26 |
} |
124 |
|
|
|
125 |
|
|
void |
126 |
|
|
PosixSignalDispatcher::DetachHandler( const int posixSignalNumber, |
127 |
|
|
const PosixSignalHandler& signalHandler ) |
128 |
torben |
196 |
throw( CannotDetachHandler, |
129 |
|
|
std::logic_error ) |
130 |
torben |
26 |
{ |
131 |
torben |
196 |
PosixSignalDispatcherImpl::Instance().DetachHandler( posixSignalNumber, |
132 |
|
|
signalHandler ) ; |
133 |
torben |
26 |
} |
134 |
|
|
|
135 |
|
|
namespace |
136 |
|
|
{ |
137 |
torben |
196 |
inline |
138 |
|
|
PosixSignalDispatcherImpl::PosixSignalDispatcherImpl() |
139 |
|
|
{ |
140 |
|
|
/* empty */ |
141 |
|
|
} |
142 |
torben |
26 |
|
143 |
torben |
196 |
inline |
144 |
|
|
PosixSignalDispatcherImpl::~PosixSignalDispatcherImpl() |
145 |
|
|
{ |
146 |
|
|
/* empty */ |
147 |
|
|
} |
148 |
torben |
26 |
|
149 |
torben |
196 |
inline |
150 |
|
|
PosixSignalDispatcherImpl& |
151 |
|
|
PosixSignalDispatcherImpl::Instance() |
152 |
|
|
{ |
153 |
|
|
static PosixSignalDispatcherImpl single_instance ; |
154 |
|
|
return single_instance ; |
155 |
|
|
} |
156 |
torben |
26 |
|
157 |
torben |
196 |
inline |
158 |
|
|
void |
159 |
|
|
PosixSignalDispatcherImpl::AttachHandler( |
160 |
|
|
const int posixSignalNumber, |
161 |
|
|
PosixSignalHandler& signalHandler ) |
162 |
|
|
throw( PosixSignalDispatcher::CannotAttachHandler ) |
163 |
|
|
{ |
164 |
|
|
/* |
165 |
|
|
* Attach this instance of PosixSignalDispatcher to the specified |
166 |
|
|
* signal. |
167 |
|
|
*/ |
168 |
|
|
struct sigaction sigaction_info ; |
169 |
|
|
sigaction_info.sa_handler = PosixSignalDispatcherImpl::SigactionHandler ; |
170 |
|
|
sigemptyset( &sigaction_info.sa_mask ) ; |
171 |
|
|
sigaction_info.sa_flags = 0 ; |
172 |
|
|
/* |
173 |
|
|
* Install the handler and get a copy of the previous handler. |
174 |
|
|
*/ |
175 |
|
|
struct sigaction old_action ; |
176 |
|
|
if ( sigaction( posixSignalNumber, |
177 |
|
|
&sigaction_info, |
178 |
|
|
&old_action ) < 0 ) |
179 |
|
|
{ |
180 |
|
|
throw PosixSignalDispatcher::CannotAttachHandler( strerror(errno) ) ; |
181 |
|
|
} |
182 |
|
|
/* |
183 |
|
|
* Save a copy of the old handler if it is not PosixSignalDispatcher::SignalHandler. |
184 |
|
|
*/ |
185 |
|
|
if ( PosixSignalDispatcherImpl::SigactionHandler != old_action.sa_handler ) |
186 |
|
|
{ |
187 |
|
|
mOriginalSigactionList.insert( |
188 |
|
|
OriginalSigactionList::value_type( posixSignalNumber, |
189 |
|
|
old_action ) ) ; |
190 |
|
|
} |
191 |
|
|
/* |
192 |
|
|
* Add the specified handler to the list of handlers associated with the signal. |
193 |
|
|
*/ |
194 |
|
|
mSignalHandlerList.insert( |
195 |
|
|
SignalHandlerList::value_type( posixSignalNumber, |
196 |
|
|
&signalHandler ) ) ; |
197 |
|
|
return ; |
198 |
|
|
} |
199 |
torben |
26 |
|
200 |
torben |
196 |
inline |
201 |
|
|
void |
202 |
|
|
PosixSignalDispatcherImpl::DetachHandler( |
203 |
|
|
const int posixSignalNumber, |
204 |
|
|
const PosixSignalHandler& signalHandler ) |
205 |
|
|
throw( PosixSignalDispatcher::CannotDetachHandler, |
206 |
|
|
std::logic_error ) |
207 |
|
|
{ |
208 |
|
|
/* |
209 |
|
|
* Get the range of values in the SignalHandlerList corresponding |
210 |
|
|
* to the specified signal number. |
211 |
|
|
*/ |
212 |
|
|
std::pair<SignalHandlerList::iterator, SignalHandlerList::iterator> |
213 |
|
|
iterator_range = mSignalHandlerList.equal_range( posixSignalNumber ) ; |
214 |
|
|
/* |
215 |
|
|
* Check if signalHandler is attached to the posixSignalNumber signal. |
216 |
|
|
*/ |
217 |
|
|
SignalHandlerList::iterator sig_handler_location = mSignalHandlerList.end() ; |
218 |
|
|
for ( SignalHandlerList::iterator i=iterator_range.first ; |
219 |
|
|
i != iterator_range.second ; |
220 |
|
|
++i ) |
221 |
|
|
{ |
222 |
|
|
if ( i->second == &signalHandler ) |
223 |
|
|
{ |
224 |
|
|
sig_handler_location = i ; |
225 |
|
|
break ; |
226 |
|
|
} |
227 |
|
|
} |
228 |
|
|
/* |
229 |
|
|
* If the signal handler is found, we need to remove it from the list. |
230 |
|
|
*/ |
231 |
|
|
if ( mSignalHandlerList.end() != sig_handler_location ) |
232 |
|
|
{ |
233 |
|
|
mSignalHandlerList.erase( sig_handler_location ) ; |
234 |
|
|
/* |
235 |
|
|
* If this was the only signal handler associated with the specified |
236 |
|
|
* signal number, then we remove the signal dispatcher from handling |
237 |
|
|
* the signal and install the original signal. |
238 |
|
|
*/ |
239 |
|
|
if ( 0 == mSignalHandlerList.count( posixSignalNumber ) ) |
240 |
|
|
{ |
241 |
|
|
/* |
242 |
|
|
* Retrieve the original sigaction corresponding to the signal. |
243 |
|
|
*/ |
244 |
|
|
OriginalSigactionList::iterator original_sigaction = |
245 |
|
|
mOriginalSigactionList.find( posixSignalNumber ) ; |
246 |
|
|
/* |
247 |
|
|
* If the signal dispatcher implementation is correct, |
248 |
|
|
* then we should always find the original sigaction. |
249 |
|
|
* If we do not find one, we throw an exception. |
250 |
|
|
*/ |
251 |
|
|
if ( mOriginalSigactionList.end() == original_sigaction ) |
252 |
|
|
{ |
253 |
|
|
throw std::logic_error( "Signal dispatcher in invalid state." ) ; |
254 |
|
|
} |
255 |
|
|
/* |
256 |
|
|
* Install the original handler. Throw an exception if we |
257 |
|
|
* encounter any error. |
258 |
|
|
*/ |
259 |
|
|
if ( sigaction( posixSignalNumber, |
260 |
|
|
&original_sigaction->second, |
261 |
|
|
NULL ) < 0 ) |
262 |
|
|
{ |
263 |
|
|
throw PosixSignalDispatcher::CannotDetachHandler( strerror(errno) ) ; |
264 |
|
|
} |
265 |
|
|
} |
266 |
|
|
} |
267 |
|
|
return ; |
268 |
|
|
} |
269 |
torben |
26 |
|
270 |
|
|
|
271 |
torben |
196 |
void |
272 |
|
|
PosixSignalDispatcherImpl::SigactionHandler( int signalNumber ) |
273 |
|
|
{ |
274 |
|
|
/* |
275 |
|
|
* Get a list of handlers associated with signalNumber. |
276 |
|
|
*/ |
277 |
|
|
std::pair<SignalHandlerList::iterator, SignalHandlerList::iterator> |
278 |
|
|
iterator_range = mSignalHandlerList.equal_range( signalNumber ) ; |
279 |
|
|
/* |
280 |
|
|
* Call each handler. |
281 |
|
|
*/ |
282 |
|
|
for ( SignalHandlerList::iterator i=iterator_range.first ; |
283 |
|
|
i != iterator_range.second ; |
284 |
|
|
++i ) |
285 |
|
|
{ |
286 |
|
|
i->second->HandlePosixSignal( signalNumber ) ; |
287 |
|
|
} |
288 |
|
|
// |
289 |
|
|
// :TODO: Why is the following code commented out using "#if 0" ? |
290 |
|
|
// Check and remove this code if it is not necessary. Otherwise, if |
291 |
|
|
// it has been commented out due to a bug then debug and correct it. |
292 |
|
|
// |
293 |
torben |
26 |
#if 0 |
294 |
torben |
196 |
/* |
295 |
|
|
* Get the original handler that was associated with the |
296 |
|
|
* signal and call it if possible. |
297 |
|
|
*/ |
298 |
|
|
OriginalSigactionList::iterator original_sigaction = |
299 |
|
|
mOriginalSigactionList.find( posixSignalNumber ) ; |
300 |
|
|
if ( ( mOriginalSigactionList.end() != original_sigaction ) && |
301 |
|
|
( SIG_DFL != original_sigaction->second.sa_handler ) && |
302 |
|
|
( SIG_IGN != original_sigaction->second.sa_handler ) && |
303 |
|
|
( 0 != original_sigaction->second.sa_handler ) ) |
304 |
|
|
{ |
305 |
|
|
original_sigaction->second.sa_handler( signalNumber ) ; |
306 |
|
|
} |
307 |
torben |
26 |
#endif |
308 |
torben |
196 |
// |
309 |
|
|
return ; |
310 |
|
|
} |
311 |
torben |
26 |
} ; |