Wiselib
|
00001 // vim: set noexpandtab ts=4 sw=4: 00002 00003 #ifndef PC_TIMER_H 00004 #define PC_TIMER_H 00005 00006 #include <time.h> 00007 #include <err.h> 00008 #include <stdarg.h> 00009 #include <errno.h> 00010 #include <signal.h> 00011 #include <pthread.h> 00012 #include <sys/time.h> 00013 #include <unistd.h> 00014 00015 #include <vector> 00016 #include <iostream> 00017 00018 #include "util/delegates/delegate.hpp" 00019 #include "pc_os.h" 00020 #include "util/pstl/list_static.h" 00021 00022 namespace wiselib { 00023 00024 template<typename OsModel_P, size_t MaxTimers_P> 00025 class TimerQueue { 00026 public: 00027 typedef TimerQueue<OsModel_P, MaxTimers_P> self_t; 00028 typedef suseconds_t micros_t; 00029 typedef suseconds_t millis_t; 00030 typedef delegate1<void, void*> timer_delegate_t; 00031 typedef OsModel_P OsModel; 00032 00033 enum Restrictions { 00034 MAX_TIMERS = MaxTimers_P 00035 }; 00036 00037 00038 enum { SUCCESS = OsModel::SUCCESS, ERR_UNSPEC = OsModel::ERR_UNSPEC }; 00039 00040 TimerQueue(); 00041 00042 int insert(micros_t interval, timer_delegate_t callback, void* userdata); 00043 int lock(); 00044 int unlock(); 00045 int from_itimer(struct itimerval& timer); 00046 int to_itimer(struct itimerval& timer); 00047 bool has_event(); 00048 timer_delegate_t current_callback(); 00049 void* current_userdata(); 00050 int pop(); 00051 00052 size_t size() { return data_.size(); } 00053 void debug(); 00054 00055 private: 00056 struct Timer { 00057 timer_delegate_t callback_; 00058 micros_t offset_; 00059 void *userdata_; 00060 }; 00061 typedef list_static<OsModel, typename self_t::Timer, MAX_TIMERS> timers_list_t; 00062 00063 timers_list_t data_; 00064 bool locked_; 00065 }; 00066 00067 template<typename OsModel_P, size_t MaxTimers_P> 00068 class PCTimerModel { 00069 public: 00070 typedef OsModel_P OsModel; 00071 typedef suseconds_t millis_t; 00072 typedef suseconds_t micros_t; 00073 typedef delegate1<void, void*> timer_delegate_t; 00074 typedef PCTimerModel<OsModel_P, MaxTimers_P> self_t; 00075 typedef self_t* self_pointer_t; 00076 00077 enum Restrictions { 00078 MAX_TIMERS = MaxTimers_P 00079 }; 00080 enum { SUCCESS = OsModel::SUCCESS, ERR_UNSPEC = OsModel::ERR_UNSPEC }; 00081 00082 PCTimerModel(); 00083 PCTimerModel(PCOs& os); 00084 00085 template<typename T, void (T::*TMethod)(void*)> 00086 int set_timer(millis_t millis, T* obj, void* userdata); 00087 00088 int sleep(millis_t duration) { 00089 return ssleep( duration ); 00090 } 00091 00092 private: 00093 static int ssleep(millis_t millis) { 00094 timespec interval, remainder; 00095 00096 interval.tv_sec = millis / 1000; 00097 interval.tv_nsec = (millis % 1000) * 1000000; 00098 00099 // nanosleep does not use SIGALRM and therefore does not interfer with the timer. 00100 while((nanosleep(&interval, &remainder) == -1) && (errno == EINTR)) { 00101 interval.tv_sec = remainder.tv_sec; 00102 interval.tv_nsec = remainder.tv_nsec; 00103 } 00104 00105 return OsModel::SUCCESS; 00106 } 00107 00108 static TimerQueue<OsModel_P, MaxTimers_P> queue_; 00109 static void timer_handler_(int signum); 00110 00116 static bool itimer_active_; 00117 }; // class PCTimerModel 00118 00119 // 00120 // Implementation TimerQueue 00121 // 00122 00123 template<typename OsModel_P, size_t MaxTimers_P> 00124 TimerQueue<OsModel_P, MaxTimers_P>::TimerQueue() : locked_(false) { 00125 } 00126 00127 template<typename OsModel_P, size_t MaxTimers_P> 00128 int TimerQueue<OsModel_P, MaxTimers_P>::insert( 00129 TimerQueue<OsModel_P, MaxTimers_P>::micros_t interval, 00130 TimerQueue<OsModel_P, MaxTimers_P>::timer_delegate_t callback, 00131 void* userdata 00132 ) { 00133 if(data_.full()) { 00134 return ERR_UNSPEC; 00135 } 00136 00137 micros_t t = 0, t_prev = 0; 00138 00139 // Find place in list to insert timer (keep list sorted all times) 00140 typename timers_list_t::iterator iter = data_.begin(); 00141 for(; iter != data_.end(); ++iter) { 00142 t += iter->offset_; 00143 if(interval < t) { break; } 00144 t_prev = t; 00145 } 00146 00147 // Create list element 00148 Timer new_timer; 00149 new_timer.callback_ = callback; 00150 new_timer.offset_ = interval - t_prev; 00151 new_timer.userdata_ = userdata; 00152 00153 // Fix following offset 00154 if(iter != data_.end()) { 00155 assert(iter->offset_ >= new_timer.offset_); 00156 iter->offset_ -= new_timer.offset_; 00157 } 00158 data_.insert(iter, new_timer); 00159 00160 return SUCCESS; 00161 } 00162 00163 template<typename OsModel_P, size_t MaxTimers_P> 00164 int TimerQueue<OsModel_P, MaxTimers_P>::lock() { 00165 if(locked_) { 00166 return ERR_UNSPEC; 00167 } 00168 locked_ = true; 00169 return SUCCESS; 00170 } 00171 00172 template<typename OsModel_P, size_t MaxTimers_P> 00173 int TimerQueue<OsModel_P, MaxTimers_P>::unlock() { 00174 locked_ = false; 00175 return SUCCESS; 00176 } 00177 00178 template<typename OsModel_P, size_t MaxTimers_P> 00179 int TimerQueue<OsModel_P, MaxTimers_P>::from_itimer(struct itimerval& timer) { 00180 if(!data_.empty()) { 00181 data_.front().offset_ = timer.it_value.tv_sec * 1000000 + timer.it_value.tv_usec; 00182 } 00183 return SUCCESS; 00184 } 00185 00186 template<typename OsModel_P, size_t MaxTimers_P> 00187 int TimerQueue<OsModel_P, MaxTimers_P>::to_itimer(struct itimerval& timer) { 00188 timer.it_interval.tv_sec = 0; 00189 timer.it_interval.tv_usec = 0; 00190 timer.it_value.tv_sec = data_.front().offset_ / 1000000; 00191 timer.it_value.tv_usec = data_.front().offset_ % 1000000; 00192 return SUCCESS; 00193 } 00194 00195 template<typename OsModel_P, size_t MaxTimers_P> 00196 bool TimerQueue<OsModel_P, MaxTimers_P>::has_event() { 00197 return !data_.empty() && (data_.front().offset_ == 0); 00198 } 00199 00200 template<typename OsModel_P, size_t MaxTimers_P> 00201 typename TimerQueue<OsModel_P, MaxTimers_P>::timer_delegate_t TimerQueue<OsModel_P, MaxTimers_P>::current_callback() { 00202 return data_.front().callback_; 00203 } 00204 00205 template<typename OsModel_P, size_t MaxTimers_P> 00206 void* TimerQueue<OsModel_P, MaxTimers_P>::current_userdata() { 00207 return data_.front().userdata_; 00208 } 00209 00210 template<typename OsModel_P, size_t MaxTimers_P> 00211 int TimerQueue<OsModel_P, MaxTimers_P>::pop() { 00212 if(!data_.empty()) { 00213 data_.pop_front(); 00214 } 00215 return SUCCESS; 00216 } 00217 00218 template<typename OsModel_P, size_t MaxTimers_P> 00219 void TimerQueue<OsModel_P, MaxTimers_P>::debug() { 00220 typename timers_list_t::iterator iter(data_.begin()); 00221 for(; iter != data_.end(); iter++) { 00222 std::cout << iter->offset_ << " "; 00223 } 00224 if(has_event()) { 00225 std::cout << "[has_event] "; 00226 } 00227 if(data_.full()) { 00228 std::cout << "[FULL!] "; 00229 } 00230 std::cout << std::endl; 00231 } 00232 00233 // 00234 // Implementation PCTimerModel 00235 // 00236 00237 template<typename OsModel_P, size_t MaxTimers_P> 00238 TimerQueue<OsModel_P, MaxTimers_P> 00239 PCTimerModel<OsModel_P, MaxTimers_P>::queue_; 00240 00241 template<typename OsModel_P, size_t MaxTimers_P> 00242 bool 00243 PCTimerModel<OsModel_P, MaxTimers_P>::itimer_active_; 00244 00245 template<typename OsModel_P, size_t MaxTimers_P> 00246 PCTimerModel<OsModel_P, MaxTimers_P>::PCTimerModel() { 00247 struct sigaction alarm_action; 00248 alarm_action.sa_handler = &PCTimerModel::timer_handler_; 00249 alarm_action.sa_flags = 0; 00250 00251 if((sigemptyset(&alarm_action.sa_mask) == -1) || 00252 (sigaddset(&alarm_action.sa_mask, SIGALRM) == -1) || 00253 (sigaction(SIGALRM, &alarm_action, 0) == -1) 00254 ) { 00255 perror("Failed to install SIGALRM-handler"); 00256 } 00257 itimer_active_ = false; 00258 } 00259 00260 template<typename OsModel_P, size_t MaxTimers_P> 00261 PCTimerModel<OsModel_P, MaxTimers_P>::PCTimerModel(PCOs& os) { 00262 struct sigaction alarm_action; 00263 alarm_action.sa_handler = &PCTimerModel::timer_handler_; 00264 alarm_action.sa_flags = 0; 00265 00266 if((sigemptyset(&alarm_action.sa_mask) == -1) || 00267 (sigaddset(&alarm_action.sa_mask, SIGALRM) == -1) || 00268 (sigaction(SIGALRM, &alarm_action, 0) == -1) 00269 ) { 00270 perror("Failed to install SIGALRM-handler"); 00271 } 00272 itimer_active_ = false; 00273 } 00274 00275 template<typename OsModel_P, size_t MaxTimers_P> 00276 template<typename T, void (T::*TMethod)(void*)> 00277 int PCTimerModel<OsModel_P, MaxTimers_P>:: 00278 set_timer(millis_t millis, T* obj, void* userdata) { 00279 struct itimerval timer; 00280 00281 if(millis < 1) { 00282 return ERR_UNSPEC; 00283 } 00284 00285 queue_.lock(); 00286 00287 if(getitimer(ITIMER_REAL, &timer) == -1) { 00288 perror("Error on getitimer()"); 00289 } 00290 00291 if(itimer_active_) { 00292 queue_.from_itimer(timer); 00293 } 00294 00295 if(queue_.insert(millis * 1000, timer_delegate_t::from_method<T, TMethod>(obj), userdata) == ERR_UNSPEC) { 00296 queue_.debug(); 00297 queue_.unlock(); 00298 return ERR_UNSPEC; 00299 } 00300 00301 // handle missed events 00302 while(queue_.has_event()) { 00303 std::cout << "handling missing event" << std::endl; 00304 00305 timer_delegate_t callback = queue_.current_callback(); 00306 void *userdata = queue_.current_userdata(); 00307 queue_.pop(); 00308 00309 queue_.unlock(); 00310 callback(userdata); 00311 if(queue_.lock() == ERR_UNSPEC) { 00312 errx(1, "timer handler didn't release timer queue lock!"); 00313 } 00314 } 00315 00316 queue_.to_itimer(timer); 00317 if(setitimer(ITIMER_REAL, &timer, 0) == -1) { 00318 perror("setitimer() failed"); 00319 } 00320 itimer_active_ = true; 00321 00322 queue_.unlock(); 00323 00324 return OsModel::SUCCESS; 00325 } 00326 00327 template<typename OsModel_P, size_t MaxTimers_P> 00328 void PCTimerModel<OsModel_P, MaxTimers_P>:: 00329 timer_handler_(int signum) { 00330 int save_errno = errno; 00331 00332 // In case set_timer is currently using the queue, just do nothing, 00333 // it will handle our callbacks when it is done. 00334 if(queue_.lock() == ERR_UNSPEC) { 00335 std::cout << "missing event" << std::endl; 00336 errno = save_errno; 00337 return; 00338 } 00339 00340 struct itimerval timer; 00341 if(getitimer(ITIMER_REAL, &timer) == -1) { 00342 perror("getitimer() failed"); 00343 } 00344 itimer_active_ = false; 00345 queue_.from_itimer(timer); 00346 00347 while(queue_.has_event()) { 00348 timer_delegate_t callback = queue_.current_callback(); 00349 void *userdata = queue_.current_userdata(); 00350 queue_.pop(); 00351 00352 queue_.unlock(); 00353 callback(userdata); 00354 if(queue_.lock() == ERR_UNSPEC) { 00355 errx(1, "timer handler didn't release timer queue lock!"); 00356 } 00357 } 00358 00359 queue_.to_itimer(timer); 00360 queue_.unlock(); 00361 00362 if(setitimer(ITIMER_REAL, &timer, 0) == -1) { 00363 perror("setitimer() failed"); 00364 } 00365 itimer_active_ = true; 00366 00367 errno = save_errno; 00368 } 00369 00370 } // namespace wiselib 00371 00372 #endif // PC_TIMER_H 00373