2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
21 * @brief implementation of wrapper and tools for signal related stuff.
23 * @copyright © Copyright 2007-2008 by Intra2net AG
25 * opensource@intra2net.com
28 #include "signalfunc.hpp"
36 #include <sys/types.h>
42 #include <containerfunc.hpp>
55 * helper for using sigaddset() as unary function within (STL) algorithms.
60 SigAddSet(sigset_t *set) : m_set(set) {}
61 int operator() (int sig) { return sigaddset(m_set,sig); }
62 }; // eo struct SigAddSet
67 * blocks the given signals while existing.
69 * This class is the real (internal) implementation of the @a SignalBlocker .
71 * @internal This internal implementation is used to avoid including signal.h within the header file.
72 * This way, we can keep the header clean; and hide all the internals in the implementation.
74 class _ScopedSignalBlocker : public SystemTools::Detail::SObject
77 _ScopedSignalBlocker(const std::vector<SystemTools::Signal>& sigs);
78 ~_ScopedSignalBlocker();
80 bool successful() const {return m_set; }
84 sigset_t m_oldsigset[1];
86 }; // eo _ScopedSignalBlocker
90 * Blocks the given signals.
92 * Constructs a sigset from the passed signals; and calls sigprocmask to block them.
93 * In case of interruption with EINTR during the call, the call is repeated some times
94 * to get the desired signals blocked.
96 * @param sigs the vector with the siganls which should be blocked.
98 _ScopedSignalBlocker::_ScopedSignalBlocker(const std::vector<SystemTools::Signal>& sigs)
100 sigemptyset(m_sigset);
103 std::for_each(sigs.begin(), sigs.end(), SigAddSet(m_sigset) );
106 for(int cnt=1000; cnt-->0;)
108 res= sigprocmask(SIG_BLOCK,m_sigset, m_oldsigset);
109 if (!res || errno!=EINTR) break;
112 } // eo _ScopedSignalBlocker::_ScopedSignalBlocker()
116 * Unblocks the signals by restoring the original block mask.
118 _ScopedSignalBlocker::~_ScopedSignalBlocker()
122 for(int cnt=1000; cnt-->0;)
124 res= sigprocmask(SIG_SETMASK, m_oldsigset, NULL);
125 if (!res || errno!=EINTR) break;
127 } // eo _ScopedSignalBlocker::~_ScopedSignalBlocker()
131 } // eo namespace <anonymous>
134 /*************************************************************************\
135 \*************************************************************************/
144 const int Signal::VOID= 0;
146 // helper macro to import the signal nums:
147 #define IMPORT(sig) const int Signal::sig = SIG ## sig
184 // remove helper macro
189 int Signal::RT(int num)
191 return SIGRTMIN + num;
202 // basically: define apropriate CODE macro and copy the CODE() parts from hpp:
205 #define CODE(name) const int SignalCode::name = SI_ ## name
206 CODE(USER); CODE(QUEUE); CODE(TIMER); CODE(MESGQ);
211 #define CODE(name) const int SignalCode::ILL::name = ILL_ ## name
212 CODE(ILLOPC); CODE(ILLOPN); CODE(ILLADR); CODE(ILLTRP);
213 CODE(PRVOPC); CODE(PRVREG); CODE(COPROC); CODE(BADSTK);
215 #define CODE(name) const int SignalCode::FPE::name = FPE_ ## name
216 CODE(INTDIV); CODE(INTOVF); CODE(FLTDIV); CODE(FLTOVF);
217 CODE(FLTUND); CODE(FLTRES); CODE(FLTINV); CODE(FLTSUB);
219 #define CODE(name) const int SignalCode::SEGV::name = SEGV_ ## name
220 CODE(MAPERR); CODE(ACCERR);
222 #define CODE(name) const int SignalCode::BUS::name = BUS_ ## name
223 CODE(ADRALN); CODE(ADRERR); CODE(OBJERR);
225 #define CODE(name) const int SignalCode::TRAP::name = TRAP_ ## name
226 CODE(BRKPT); CODE(TRACE);
228 #define CODE(name) const int SignalCode::CHLD::name = CLD_ ## name
229 CODE(EXITED); CODE(KILLED); CODE(DUMPED); CODE(TRAPPED);
230 CODE(STOPPED); CODE(CONTINUED);
232 #define CODE(name) const int SignalCode::POLL::name = POLL_ ## name
233 CODE(IN); CODE(OUT); CODE(MSG); CODE(ERR); CODE(PRI); CODE(HUP);
238 * ScopedSignalBlocker
243 * Blocks the given signal.
244 * @param sig the signal which should be blocked.
246 ScopedSignalBlocker::ScopedSignalBlocker(Signal sig)
248 Implementation = new _ScopedSignalBlocker( TransientPushBackFiller< Signal, std::vector >()(sig) );
249 } // eo ScopedSignalBlocker::ScopedSignalBlocker
252 ScopedSignalBlocker::ScopedSignalBlocker(Signal sig1, Signal sig2)
254 Implementation = new _ScopedSignalBlocker( TransientPushBackFiller< Signal, std::vector >()(sig1)(sig2) );
255 } // eo ScopedSignalBlocker::ScopedSignalBlocker
258 ScopedSignalBlocker::ScopedSignalBlocker(Signal sig1, Signal sig2, Signal sig3)
260 Implementation = new _ScopedSignalBlocker( TransientPushBackFiller< Signal, std::vector >()(sig1)(sig2)(sig3) );
261 } // eo ScopedSignalBlocker::ScopedSignalBlocker
265 * Blocks the given signals.
266 * @param sigs vector with the signals which should be blocked.
268 ScopedSignalBlocker::ScopedSignalBlocker(const std::vector<Signal>& sigs)
270 Implementation = new _ScopedSignalBlocker( sigs );
271 } // eo ScopedSignalBlocker::ScopedSignalBlocker
275 * Unblocks the signals by restoring the previous blocking list.
277 ScopedSignalBlocker::~ScopedSignalBlocker()
281 delete Implementation;
282 Implementation= NULL;
284 } // eo ScopedSignalBlocker::ScopedSignalBlocker
292 typedef std::map< int, struct sigaction > SignalActionMap;
296 SignalActionMap original_signal_action;
298 } // eo namespace <anonymous>
302 * @brief installs a new signal action.
303 * @param sig the signal
304 * @param new_action the new signal action.
305 * @return @a true iff the new signal action was succesfully installed.
307 * Remembers the original value of the signal handler for later restoring.
309 bool install_signal_handler(
311 struct sigaction& new_action
314 struct sigaction old_action[1];
316 int res= ::sigaction(signum, &new_action, old_action);
319 SignalActionMap::iterator it= original_signal_action.find(signum);
320 if (it == original_signal_action.end())
322 original_signal_action[signum] = *old_action;
327 // some glibc's seem to return the errno instead of storing
328 // it in the appropriate var... *sigh*
332 } // eo install_signal_handler(int,sigaction&)
336 * @brief installs a simple signal handler.
337 * @param sig the signal.
338 * @param handler pointer to the signal handler.
339 * @return @a true iff the handler was successfully installed.
341 * Remembers the original value of the signal handler for later restoring.
343 bool install_signal_handler(
348 struct sigaction new_action;
349 new_action.sa_handler= handler;
350 sigemptyset( &new_action.sa_mask );
351 new_action.sa_flags= 0;
352 new_action.sa_restorer= NULL;
353 return install_signal_handler(sig, new_action);
354 } // eo install_signal_handler(signum,void(*)(int))
359 * @brief installs a signal action handler.
360 * @param sig the signal
361 * @param handler pointer to the signal action handler.
362 * @return @a true iff the action handler was successfully installed.
364 * Remembers the original value of the signal handler for later restoring.
366 bool install_signal_handler(
368 void(*handler)(int,struct siginfo*,void*)
371 struct sigaction new_action;
372 new_action.sa_sigaction= handler;
373 sigemptyset( &new_action.sa_mask );
374 new_action.sa_flags= SA_SIGINFO;
375 new_action.sa_restorer= NULL;
376 return install_signal_handler(sig, new_action);
377 } // eo install_signal_handler(signum,void(*)(int,siginfo_t*,void*))
381 * @brief ignores a signal.
382 * @param sig the signal
383 * @return @a true iff the ignore handler was successfully installed.
385 * Remembers the original value of the signal handler for later restoring.
387 bool ignore_signal(Signal sig)
389 return install_signal_handler(sig, SIG_IGN );
390 } // eo ignore_signal(Signal)
394 * @brief enables the default signal handler.
395 * @param sig the signal
396 * @return @a true iff the default handler was successfully installed.
398 * Remembers the original value of the signal handler for later restoring.
400 bool install_default_signal_handler(Signal sig)
402 return install_signal_handler(sig, SIG_DFL );
403 } // eo install_default_signal_handler(Signal)
407 * @brief restores a signal handle to its original value.
408 * @param sig the signal.
409 * @return @a true iff the handler was sucessfully restored.
411 bool restore_signal_handler(Signal sig)
414 SignalActionMap::iterator it= original_signal_action.find(signum);
416 if (it != original_signal_action.end())
418 res= ::sigaction(signum, &(it->second), NULL);
421 original_signal_action.erase(it);
425 } // eo restore_signal_handler
430 * @brief convenience function; send's a signal to a process.
431 * @param pid PID of the process which should recive the signal.
432 * @param signal the signal to send.
433 * @return @a true iff sending of the signal succeeded.
435 bool send_signal( pid_t pid, Signal signal)
437 return ::kill(pid, signal.Value) == 0;
438 } // eo send_signal(pid_t,Signal)
442 } // eo namespace SystemTools
443 } // eo namespace I2n