libmoost
|
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 }