libmoost
/home/mhx/git/github/libmoost/src/signal/signal_handler.cpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 #include <stdexcept>
00029 #include <pthread.h>
00030 #include "../../include/moost/signal/signal_handler.h"
00031 
00032 using namespace moost::signal;
00033 
00034 class signal_handler::impl
00035 {
00036 private:
00037 
00038   sigset_t       m_signal_mask;     // signals to block
00039   pthread_t      m_thread;          // our pthread
00040   pthread_attr_t m_thread_attr;     // thread attributes
00041 
00042   boost::function<void(int)> m_callback;  // our callback
00043 
00044   void wait_loop();
00045 
00046   static void * t_entry(void * p)
00047   {
00048     signal_handler::impl * psig_handler = static_cast<signal_handler::impl *>(p);
00049     psig_handler->wait_loop();
00050     return NULL;
00051   }
00052 
00053 public:
00054 
00055   impl(const boost::function<void(int)> & callback);
00056 
00057   ~impl();
00058 };
00059 
00060 signal_handler::signal_handler(const boost::function<void(int)> & callback)
00061 : m_pimpl(new impl(callback))
00062 {
00063 }
00064 
00065 signal_handler::impl::impl(const boost::function<void(int)> & callback)
00066 : m_callback(callback)
00067 {
00068   sigemptyset(&m_signal_mask);
00069   sigaddset(&m_signal_mask, SIGINT);
00070   sigaddset(&m_signal_mask, SIGHUP);
00071   sigaddset(&m_signal_mask, SIGTERM);
00072   // we use SIGUSR1 for our own devices:
00073   // sighandler thread wakes up when receiving it and knows to exit
00074   sigaddset(&m_signal_mask, SIGUSR1);
00075 
00076   // inform pthreads that this thread (and any thread spawning from it)
00077   // should intercept the signals masked into m_signal_mask
00078   if (pthread_sigmask(SIG_BLOCK, &m_signal_mask, NULL) != 0)
00079     throw std::runtime_error("failed to set sigmask");
00080 
00081   if (pthread_attr_init(&m_thread_attr) != 0)
00082     throw std::runtime_error("failed to set thread attr");
00083 
00084   if (pthread_create(&m_thread, &m_thread_attr, t_entry, this) != 0)
00085     throw std::runtime_error("failed to create thread");
00086 }
00087 
00088 signal_handler::impl::~impl()
00089 {
00090   // wake thread up
00091   pthread_kill(m_thread, SIGUSR1);
00092   pthread_join(m_thread, NULL);
00093   // revert to not handling the aforementioned signals
00094   pthread_sigmask(SIG_UNBLOCK, &m_signal_mask, NULL);
00095 }
00096 
00097 void signal_handler::impl::wait_loop()
00098 {
00099   int      sig_caught;   // caught signal
00100 
00101   for (;;)
00102   {
00103     if (sigwait(&m_signal_mask, &sig_caught) != 0)
00104       m_callback(-1); // error catching signal
00105     else if (sig_caught == SIGUSR1)
00106     {
00107       return;
00108     }
00109     else
00110       m_callback(sig_caught);
00111   }
00112 }