Wiselib
wiselib.testing/external_interface/pc/pc_timer.h
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines