libmoost
|
00001 /* vim:set ts=3 sw=3 sts=3 et: */ 00035 #ifndef MOOST_FIXED_INTERVAL_TIMER_TIMER_HPP__ 00036 #define MOOST_FIXED_INTERVAL_TIMER_TIMER_HPP__ 00037 00038 #include <csignal> 00039 #include <utility> 00040 #include <boost/function.hpp> 00041 #include <boost/thread.hpp> 00042 #include <boost/bind.hpp> 00043 #include <boost/shared_ptr.hpp> 00044 #include <boost/date_time/posix_time/posix_time.hpp> 00045 #include <boost/asio.hpp> 00046 #include <boost/ref.hpp> 00047 00048 namespace moost { namespace utils { 00049 00082 class fixed_interval_timer 00083 { 00084 private: 00085 typedef boost::promise<int> promise_t; 00086 typedef boost::shared_ptr<promise_t> promise_ptr; 00087 typedef std::sig_atomic_t volatile sig_atomic_t; 00088 typedef boost::shared_ptr<sig_atomic_t> signal_ptr; 00089 00090 public: 00091 typedef boost::function0<void> callback_t; 00092 typedef std::pair<boost::posix_time::ptime, callback_t> process_arg; 00093 00100 fixed_interval_timer(boost::posix_time::time_duration const & interval) 00101 : interval_(interval) 00102 , thread_(boost::bind(&boost::asio::io_service::run, &io_service_)) 00103 , pwork_(new boost::asio::io_service::work(io_service_)) 00104 { 00105 } 00106 00110 ~fixed_interval_timer() 00111 { 00112 try 00113 { 00114 // right, down tools chaps 00115 pwork_.reset(); 00116 thread_.join(); 00117 } 00118 catch(...) 00119 { 00120 // oh, crap :( 00121 } 00122 } 00123 00129 void notify(callback_t const & cb) 00130 { 00131 // notify me when this time has passed 00132 boost::posix_time::ptime pt = 00133 boost::posix_time::microsec_clock::universal_time() + interval_; 00134 00135 // queue the notification request 00136 io_service_.post(boost::bind( 00137 &fixed_interval_timer::process, this, 00138 std::make_pair(pt, cb))); 00139 } 00140 00144 typedef boost::unique_future<int> future_t; 00145 00151 void notify(future_t & f_sig) 00152 { 00153 // signal me when this time has passed 00154 boost::posix_time::ptime pt = 00155 boost::posix_time::microsec_clock::universal_time() + interval_; 00156 00157 // I promise to notify you in the future 00158 promise_ptr p_sig(new promise_t); 00159 f_sig = p_sig->get_future(); 00160 00161 // queue the notification request 00162 io_service_.post(boost::bind( 00163 &fixed_interval_timer::process, this, 00164 std::make_pair(pt, boost::bind( 00165 &fixed_interval_timer::fulfil_promise, this, p_sig)) 00166 )); 00167 } 00168 00169 00173 class signal_t 00174 { 00175 friend class fixed_interval_timer; 00176 00177 public: 00178 signal_t() 00179 : psig_(new sig_atomic_t(0)) {} 00180 00181 bool is_ready() const 00182 { 00183 return *psig_ == 1; 00184 } 00185 00186 private: 00187 signal_ptr psig_; 00188 }; 00189 00195 void notify(signal_t & sig) 00196 { 00197 // signal me when this time has passed 00198 boost::posix_time::ptime pt = 00199 boost::posix_time::microsec_clock::universal_time() + interval_; 00200 00201 // queue the signal request 00202 io_service_.post(boost::bind( 00203 &fixed_interval_timer::process, this, 00204 std::make_pair(pt, boost::bind( 00205 &fixed_interval_timer::set_signal, this, sig.psig_)) 00206 )); 00207 } 00208 00209 00210 private: 00211 // process the current queue item 00212 void process(process_arg const & arg) const 00213 { 00214 // sleep until it's time to call the callback 00215 boost::thread::sleep(arg.first); 00216 00217 // call the callback 00218 arg.second(); 00219 } 00220 00221 // make good on our promise 00222 void fulfil_promise(promise_ptr p_sig) const 00223 { 00224 // a promise should never be broken! 00225 p_sig->set_value(1); 00226 } 00227 00228 // signal that sucker 00229 void set_signal(signal_ptr psig) const 00230 { 00231 *psig = 1; 00232 } 00233 00234 private: 00235 boost::posix_time::time_duration interval_; 00236 boost::asio::io_service io_service_; 00237 boost::thread thread_; 00238 boost::shared_ptr<boost::asio::io_service::work> pwork_; 00239 }; 00240 00241 }} 00242 00243 #endif