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
26 #include "signalfunc.hpp"
34 #include <sys/types.h>
40 #include <containerfunc.hpp>
53 * helper for using sigaddset() as unary function within (STL) algorithms.
58 SigAddSet(sigset_t *set) : m_set(set) {}
59 int operator() (int sig) { return sigaddset(m_set,sig); }
60 }; // eo struct SigAddSet
65 * blocks the given signals while existing.
67 * This class is the real (internal) implementation of the @a SignalBlocker .
69 * @internal This internal implementation is used to avoid including signal.h within the header file.
70 * This way, we can keep the header clean; and hide all the internals in the implementation.
72 class _ScopedSignalBlocker : public SystemTools::Detail::SObject
75 _ScopedSignalBlocker(const std::vector<SystemTools::Signal>& sigs);
76 ~_ScopedSignalBlocker();
78 bool successful() const {return m_set; }
82 sigset_t m_oldsigset[1];
84 }; // eo _ScopedSignalBlocker
88 * Blocks the given signals.
90 * Constructs a sigset from the passed signals; and calls sigprocmask to block them.
91 * In case of interruption with EINTR during the call, the call is repeated some times
92 * to get the desired signals blocked.
94 * @param sigs the vector with the siganls which should be blocked.
96 _ScopedSignalBlocker::_ScopedSignalBlocker(const std::vector<SystemTools::Signal>& sigs)
98 sigemptyset(m_sigset);
101 std::for_each(sigs.begin(), sigs.end(), SigAddSet(m_sigset) );
104 for(int cnt=1000; cnt-->0;)
106 res= sigprocmask(SIG_BLOCK,m_sigset, m_oldsigset);
107 if (!res || errno!=EINTR) break;
110 } // eo _ScopedSignalBlocker::_ScopedSignalBlocker()
114 * Unblocks the signals by restoring the original block mask.
116 _ScopedSignalBlocker::~_ScopedSignalBlocker()
120 for(int cnt=1000; cnt-->0;)
122 res= sigprocmask(SIG_SETMASK, m_oldsigset, NULL);
123 if (!res || errno!=EINTR) break;
125 } // eo _ScopedSignalBlocker::~_ScopedSignalBlocker()
129 } // eo namespace <anonymous>
132 /*************************************************************************\
133 \*************************************************************************/
142 const int Signal::VOID= 0;
144 // helper macro to import the signal nums:
145 #define IMPORT(sig) const int Signal::sig = SIG ## sig
182 // remove helper macro
187 int Signal::RT(int num)
189 return SIGRTMIN + num;
200 // basically: define apropriate CODE macro and copy the CODE() parts from hpp:
203 #define CODE(name) const int SignalCode::name = SI_ ## name
204 CODE(USER); CODE(QUEUE); CODE(TIMER); CODE(MESGQ);
209 #define CODE(name) const int SignalCode::ILL::name = ILL_ ## name
210 CODE(ILLOPC); CODE(ILLOPN); CODE(ILLADR); CODE(ILLTRP);
211 CODE(PRVOPC); CODE(PRVREG); CODE(COPROC); CODE(BADSTK);
213 #define CODE(name) const int SignalCode::FPE::name = FPE_ ## name
214 CODE(INTDIV); CODE(INTOVF); CODE(FLTDIV); CODE(FLTOVF);
215 CODE(FLTUND); CODE(FLTRES); CODE(FLTINV); CODE(FLTSUB);
217 #define CODE(name) const int SignalCode::SEGV::name = SEGV_ ## name
218 CODE(MAPERR); CODE(ACCERR);
220 #define CODE(name) const int SignalCode::BUS::name = BUS_ ## name
221 CODE(ADRALN); CODE(ADRERR); CODE(OBJERR);
223 #define CODE(name) const int SignalCode::TRAP::name = TRAP_ ## name
224 CODE(BRKPT); CODE(TRACE);
226 #define CODE(name) const int SignalCode::CHLD::name = CLD_ ## name
227 CODE(EXITED); CODE(KILLED); CODE(DUMPED); CODE(TRAPPED);
228 CODE(STOPPED); CODE(CONTINUED);
230 #define CODE(name) const int SignalCode::POLL::name = POLL_ ## name
231 CODE(IN); CODE(OUT); CODE(MSG); CODE(ERR); CODE(PRI); CODE(HUP);
236 * ScopedSignalBlocker
241 * Blocks the given signal.
242 * @param sig the signal which should be blocked.
244 ScopedSignalBlocker::ScopedSignalBlocker(Signal sig)
246 Implementation = new _ScopedSignalBlocker( TransientPushBackFiller< Signal, std::vector >()(sig) );
247 } // eo ScopedSignalBlocker::ScopedSignalBlocker
250 ScopedSignalBlocker::ScopedSignalBlocker(Signal sig1, Signal sig2)
252 Implementation = new _ScopedSignalBlocker( TransientPushBackFiller< Signal, std::vector >()(sig1)(sig2) );
253 } // eo ScopedSignalBlocker::ScopedSignalBlocker
256 ScopedSignalBlocker::ScopedSignalBlocker(Signal sig1, Signal sig2, Signal sig3)
258 Implementation = new _ScopedSignalBlocker( TransientPushBackFiller< Signal, std::vector >()(sig1)(sig2)(sig3) );
259 } // eo ScopedSignalBlocker::ScopedSignalBlocker
263 * Blocks the given signals.
264 * @param sigs vector with the signals which should be blocked.
266 ScopedSignalBlocker::ScopedSignalBlocker(const std::vector<Signal>& sigs)
268 Implementation = new _ScopedSignalBlocker( sigs );
269 } // eo ScopedSignalBlocker::ScopedSignalBlocker
273 * Unblocks the signals by restoring the previous blocking list.
275 ScopedSignalBlocker::~ScopedSignalBlocker()
279 delete Implementation;
280 Implementation= NULL;
282 } // eo ScopedSignalBlocker::ScopedSignalBlocker
290 typedef std::map< int, struct sigaction > SignalActionMap;
294 SignalActionMap original_signal_action;
296 } // eo namespace <anonymous>
300 * @brief installs a new signal action.
301 * @param sig the signal
302 * @param new_action the new signal action.
303 * @return @a true iff the new signal action was succesfully installed.
305 * Remembers the original value of the signal handler for later restoring.
307 bool install_signal_handler(
309 struct sigaction& new_action
312 struct sigaction old_action[1];
314 int res= ::sigaction(signum, &new_action, old_action);
317 SignalActionMap::iterator it= original_signal_action.find(signum);
318 if (it == original_signal_action.end())
320 original_signal_action[signum] = *old_action;
325 // some glibc's seem to return the errno instead of storing
326 // it in the appropriate var... *sigh*
330 } // eo install_signal_handler(int,sigaction&)
334 * @brief installs a simple signal handler.
335 * @param sig the signal.
336 * @param handler pointer to the signal handler.
337 * @return @a true iff the handler was successfully installed.
339 * Remembers the original value of the signal handler for later restoring.
341 bool install_signal_handler(
346 struct sigaction new_action;
347 new_action.sa_handler= handler;
348 sigemptyset( &new_action.sa_mask );
349 new_action.sa_flags= 0;
350 new_action.sa_restorer= NULL;
351 return install_signal_handler(sig, new_action);
352 } // eo install_signal_handler(signum,void(*)(int))
357 * @brief installs a signal action handler.
358 * @param sig the signal
359 * @param handler pointer to the signal action handler.
360 * @return @a true iff the action handler was successfully installed.
362 * Remembers the original value of the signal handler for later restoring.
364 bool install_signal_handler(
366 void(*handler)(int,struct siginfo*,void*)
369 struct sigaction new_action;
370 new_action.sa_sigaction= (void (*)(int, siginfo_t*, void*))(handler);
371 sigemptyset( &new_action.sa_mask );
372 new_action.sa_flags= SA_SIGINFO;
373 new_action.sa_restorer= NULL;
374 return install_signal_handler(sig, new_action);
375 } // eo install_signal_handler(signum,void(*)(int,siginfo_t*,void*))
379 * @brief ignores a signal.
380 * @param sig the signal
381 * @return @a true iff the ignore handler was successfully installed.
383 * Remembers the original value of the signal handler for later restoring.
385 bool ignore_signal(Signal sig)
387 return install_signal_handler(sig, SIG_IGN );
388 } // eo ignore_signal(Signal)
392 * @brief enables the default signal handler.
393 * @param sig the signal
394 * @return @a true iff the default handler was successfully installed.
396 * Remembers the original value of the signal handler for later restoring.
398 bool install_default_signal_handler(Signal sig)
400 return install_signal_handler(sig, SIG_DFL );
401 } // eo install_default_signal_handler(Signal)
405 * @brief restores a signal handle to its original value.
406 * @param sig the signal.
407 * @return @a true iff the handler was sucessfully restored.
409 bool restore_signal_handler(Signal sig)
412 SignalActionMap::iterator it= original_signal_action.find(signum);
414 if (it != original_signal_action.end())
416 res= ::sigaction(signum, &(it->second), NULL);
419 original_signal_action.erase(it);
423 } // eo restore_signal_handler
428 * @brief convenience function; send's a signal to a process.
429 * @param pid PID of the process which should recive the signal.
430 * @param signal the signal to send.
431 * @return @a true iff sending of the signal succeeded.
433 bool send_signal( pid_t pid, Signal signal)
435 return ::kill(pid, signal.Value) == 0;
436 } // eo send_signal(pid_t,Signal)
440 } // eo namespace SystemTools
441 } // eo namespace I2n