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