1 |
// |
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 |
} ; |