00001 
00023 #ifndef _XENO_NUCLEUS_TIMER_H
00024 #define _XENO_NUCLEUS_TIMER_H
00025 
00026 #include <nucleus/timebase.h>
00027 #include <nucleus/stat.h>
00028 
00029 #if defined(__KERNEL__) || defined(__XENO_SIM__)
00030 
00031 #ifndef CONFIG_XENO_OPT_DEBUG_TIMERS
00032 #define CONFIG_XENO_OPT_DEBUG_TIMERS  0
00033 #endif
00034 
00035 #define XNTIMER_WHEELSIZE 64
00036 #define XNTIMER_WHEELMASK (XNTIMER_WHEELSIZE - 1)
00037 
00038 
00039 #define XNTIMER_DEQUEUED  0x00000001
00040 #define XNTIMER_KILLED    0x00000002
00041 #define XNTIMER_PERIODIC  0x00000004
00042 #define XNTIMER_REALTIME  0x00000008
00043 #define XNTIMER_FIRED     0x00000010
00044 #define XNTIMER_NOBLCK    0x00000020
00045 
00046 
00047 #define XNTIMER_SPARE0  0x01000000
00048 #define XNTIMER_SPARE1  0x02000000
00049 #define XNTIMER_SPARE2  0x04000000
00050 #define XNTIMER_SPARE3  0x08000000
00051 #define XNTIMER_SPARE4  0x10000000
00052 #define XNTIMER_SPARE5  0x20000000
00053 #define XNTIMER_SPARE6  0x40000000
00054 #define XNTIMER_SPARE7  0x80000000
00055 
00056 
00057 #define XNTIMER_LOPRIO  (-999999999)
00058 #define XNTIMER_STDPRIO 0
00059 #define XNTIMER_HIPRIO  999999999
00060 
00061 #define XNTIMER_KEEPER_ID 0
00062 
00063 typedef struct {
00064         xnholder_t link;
00065         xnticks_t key;
00066         int prio;
00067 
00068 #define link2tlholder(ln)       container_of(ln, xntlholder_t, link)
00069 
00070 } xntlholder_t;
00071 
00072 #define xntlholder_date(h)      ((h)->key)
00073 #define xntlholder_prio(h)      ((h)->prio)
00074 #define xntlholder_init(h)      inith(&(h)->link)
00075 #define xntlist_init(q) initq(q)
00076 #define xntlist_head(q)                 \
00077         ({ xnholder_t *_h = getheadq(q);        \
00078                 !_h ? NULL : link2tlholder(_h); \
00079         })
00080 
00081 #define xntlist_next(q, h) \
00082         ({ xnholder_t *_h = nextq(q, &(h)->link);       \
00083                 !_h ? NULL : link2tlholder(_h);         \
00084         })
00085 
00086 static inline void xntlist_insert(xnqueue_t *q, xntlholder_t *holder)
00087 {
00088         xnholder_t *p;
00089 
00090         
00091 
00092 
00093 
00094 
00095         for (p = q->head.last; p != &q->head; p = p->last)
00096                 if ((xnsticks_t) (holder->key - link2tlholder(p)->key) > 0 ||
00097                     (holder->key == link2tlholder(p)->key &&
00098                      holder->prio <= link2tlholder(p)->prio))
00099                         break;
00100 
00101         insertq(q,p->next,&holder->link);
00102 }
00103 
00104 #define xntlist_remove(q, h)  removeq((q),&(h)->link)
00105 
00106 #if defined(CONFIG_XENO_OPT_TIMER_HEAP)
00107 
00108 #include <nucleus/bheap.h>
00109 
00110 typedef bheaph_t xntimerh_t;
00111 
00112 #define xntimerh_date(h)          bheaph_key(h)
00113 #define xntimerh_prio(h)          bheaph_prio(h)
00114 #define xntimerh_init(h)          bheaph_init(h)
00115 
00116 typedef DECLARE_BHEAP_CONTAINER(xntimerq_t, CONFIG_XENO_OPT_TIMER_HEAP_CAPACITY);
00117 
00118 #define xntimerq_init(q)          bheap_init((q), CONFIG_XENO_OPT_TIMER_HEAP_CAPACITY)
00119 #define xntimerq_destroy(q)       bheap_destroy(q)
00120 #define xntimerq_head(q)          bheap_gethead(q)
00121 #define xntimerq_insert(q, h)     bheap_insert((q),(h))
00122 #define xntimerq_remove(q, h)     bheap_delete((q),(h))
00123 
00124 typedef struct {} xntimerq_it_t;
00125 
00126 #define xntimerq_it_begin(q, i)   ((void) (i), bheap_gethead(q))
00127 #define xntimerq_it_next(q, i, h) ((void) (i), bheap_next((q),(h)))
00128 
00129 #elif defined(CONFIG_XENO_OPT_TIMER_WHEEL)
00130 
00131 typedef xntlholder_t xntimerh_t;
00132 
00133 #define xntimerh_date(h)       xntlholder_date(h)
00134 #define xntimerh_prio(h)       xntlholder_prio(h)
00135 #define xntimerh_init(h)       xntlholder_init(h)
00136 
00137 typedef struct xntimerq {
00138         unsigned date_shift;
00139         unsigned long long next_shot;
00140         unsigned long long shot_wrap;
00141         xnqueue_t bucket[XNTIMER_WHEELSIZE];
00142 } xntimerq_t;
00143 
00144 typedef struct xntimerq_it {
00145         unsigned bucket;
00146 } xntimerq_it_t;
00147 
00148 static inline void xntimerq_init(xntimerq_t *q)
00149 {
00150         unsigned long long step_tsc;
00151         unsigned i;
00152 
00153         step_tsc = xnarch_ns_to_tsc(CONFIG_XENO_OPT_TIMER_WHEEL_STEP);
00154         
00155         for (q->date_shift = 0; (1 << q->date_shift) < step_tsc; q->date_shift++)
00156                 ;
00157         q->next_shot = q->shot_wrap = ((~0ULL) >> q->date_shift) + 1;
00158         for (i = 0; i < sizeof(q->bucket)/sizeof(xnqueue_t); i++)
00159                 xntlist_init(&q->bucket[i]);
00160 }
00161 
00162 #define xntimerq_destroy(q)    do { } while (0)
00163 
00164 static inline xntlholder_t *xntimerq_head(xntimerq_t *q)
00165 {
00166         unsigned bucket = ((unsigned) q->next_shot) & XNTIMER_WHEELMASK;
00167         xntlholder_t *result;
00168         unsigned i;
00169 
00170         if (q->next_shot == q->shot_wrap)
00171                 return NULL;
00172 
00173         result = xntlist_head(&q->bucket[bucket]);
00174 
00175         if (result && (xntlholder_date(result) >> q->date_shift) == q->next_shot)
00176                 return result;
00177 
00178         
00179 
00180         for (i = (bucket + 1) & XNTIMER_WHEELMASK ;
00181              i != bucket; i = (i + 1) & XNTIMER_WHEELMASK) {
00182                 xntlholder_t *candidate = xntlist_head(&q->bucket[i]);
00183 
00184                 if(++q->next_shot == q->shot_wrap)
00185                         q->next_shot = 0;
00186 
00187                 if (!candidate)
00188                         continue;
00189 
00190                 if ((xntlholder_date(candidate) >> q->date_shift) == q->next_shot)
00191                         return candidate;
00192 
00193                 if (!result || (xnsticks_t) (xntlholder_date(candidate)
00194                                              - xntlholder_date(result)) < 0)
00195                         result = candidate;
00196         }
00197 
00198         if (result)
00199                 q->next_shot = (xntlholder_date(result) >> q->date_shift);
00200         else
00201                 q->next_shot = q->shot_wrap;
00202         return result;
00203 }
00204 
00205 static inline void xntimerq_insert(xntimerq_t *q, xntimerh_t *h)
00206 {
00207         unsigned long long shifted_date = xntlholder_date(h) >> q->date_shift;
00208         unsigned bucket = ((unsigned) shifted_date) & XNTIMER_WHEELMASK;
00209 
00210         if ((long long) (shifted_date - q->next_shot) < 0)
00211                 q->next_shot = shifted_date;
00212         xntlist_insert(&q->bucket[bucket], h);
00213 }
00214 
00215 static inline void xntimerq_remove(xntimerq_t *q, xntimerh_t *h)
00216 {
00217         unsigned long long shifted_date = xntlholder_date(h) >> q->date_shift;
00218         unsigned bucket = ((unsigned) shifted_date) & XNTIMER_WHEELMASK;
00219 
00220         xntlist_remove(&q->bucket[bucket], h);
00221         
00222 }
00223 
00224 static inline xntimerh_t *xntimerq_it_begin(xntimerq_t *q, xntimerq_it_t *it)
00225 {
00226         xntimerh_t *holder = NULL;
00227 
00228         for (it->bucket = 0; it->bucket < XNTIMER_WHEELSIZE; it->bucket++)
00229                 if ((holder = xntlist_head(&q->bucket[it->bucket])))
00230                         break;
00231 
00232         return holder;
00233 }
00234 
00235 static inline xntimerh_t *
00236 xntimerq_it_next(xntimerq_t *q, xntimerq_it_t *it, xntimerh_t *holder)
00237 {
00238         xntimerh_t *next = xntlist_next(&q->bucket[it->bucket], holder);
00239 
00240         if (!next)
00241                 for(it->bucket++; it->bucket < XNTIMER_WHEELSIZE; it->bucket++)
00242                         if ((next = xntlist_head(&q->bucket[it->bucket])))
00243                                 break;
00244 
00245         return next;
00246 }
00247 
00248 #else 
00249 
00250 typedef xntlholder_t xntimerh_t;
00251 
00252 #define xntimerh_date(h)        xntlholder_date(h)
00253 #define xntimerh_prio(h)        xntlholder_prio(h)
00254 #define xntimerh_init(h)        xntlholder_init(h)
00255 
00256 typedef xnqueue_t xntimerq_t;
00257 
00258 #define xntimerq_init(q)        xntlist_init(q)
00259 #define xntimerq_destroy(q)     do { } while (0)
00260 #define xntimerq_head(q)        xntlist_head(q)
00261 #define xntimerq_insert(q,h)    xntlist_insert((q),(h))
00262 #define xntimerq_remove(q, h)   xntlist_remove((q),(h))
00263 
00264 typedef struct {} xntimerq_it_t;
00265 
00266 #define xntimerq_it_begin(q,i)  ((void) (i), xntlist_head(q))
00267 #define xntimerq_it_next(q,i,h) ((void) (i), xntlist_next((q),(h)))
00268 
00269 #endif 
00270 
00271 struct xnsched;
00272 
00273 typedef struct xntimer {
00274 
00275         xntimerh_t aplink;      
00276 
00277 #define aplink2timer(ln) container_of(ln, xntimer_t, aplink)
00278 
00279 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC
00280         xntbase_t *base;        
00281 
00282         xntlholder_t plink;     
00283 
00284 #define plink2timer(ln) container_of(ln, xntimer_t, plink)
00285 #endif 
00286 
00287         xnholder_t adjlink;
00288 
00289 #define adjlink2timer(ln) container_of(ln, xntimer_t, adjlink)
00290 
00291         xnflags_t status;       
00292 
00293         xnticks_t interval;     
00294 
00295         xnticks_t pexpect;      
00296 
00297         struct xnsched *sched;  
00298 
00299 
00300         void (*handler)(struct xntimer *timer); 
00301 
00302 #ifdef CONFIG_XENO_OPT_STATS
00303         char name[XNOBJECT_NAME_LEN]; 
00304 
00305         const char *handler_name; 
00306 
00307         xnholder_t tblink;      
00308 
00309 #define tblink2timer(ln)        container_of(ln, xntimer_t, tblink)
00310 #endif 
00311 
00312         xnstat_counter_t scheduled; 
00313 
00314         xnstat_counter_t fired; 
00315 
00316         XNARCH_DECL_DISPLAY_CONTEXT();
00317 
00318 } xntimer_t;
00319 
00320 typedef struct xntimed_slave {
00321 
00322         xntbase_t base;         
00323 
00324         struct percpu_cascade {
00325                 xntimer_t timer; 
00326                 xnqueue_t wheel[XNTIMER_WHEELSIZE]; 
00327         } cascade[XNARCH_NR_CPUS];
00328 
00329 #define timer2slave(t) \
00330     ((xntslave_t *)(((char *)t) - offsetof(xntslave_t, cascade[xnsched_cpu((t)->sched)].timer)))
00331 #define base2slave(b) \
00332     ((xntslave_t *)(((char *)b) - offsetof(xntslave_t, base)))
00333 
00334 } xntslave_t;
00335 
00336 #ifdef CONFIG_SMP
00337 #define xntimer_sched(t)        ((t)->sched)
00338 #else 
00339 #define xntimer_sched(t)        xnpod_current_sched()
00340 #endif 
00341 #define xntimer_interval(t)     ((t)->interval)
00342 #define xntimer_pexpect(t)      ((t)->pexpect)
00343 #define xntimer_pexpect_forward(t,delta) ((t)->pexpect += delta)
00344 
00345 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC
00346 #define xntimer_base(t)         ((t)->base)
00347 #define xntimer_set_priority(t,p)                               \
00348         ({                                                      \
00349                 xntimer_t *_t = (t);                            \
00350                 unsigned prio = (p);                            \
00351                 xntimerh_prio(&(_t)->aplink) = prio;            \
00352                 xntlholder_prio(&(_t)->plink) = prio;           \
00353         })
00354 #else 
00355 #define xntimer_base(t)         (&nktbase)
00356 #define xntimer_set_priority(t,p)                               \
00357         do { xntimerh_prio(&(t)->aplink) = (p); } while(0)
00358 #endif 
00359 
00360 static inline int xntimer_active_p (xntimer_t *timer)
00361 {
00362         return timer->sched != NULL;
00363 }
00364 
00365 static inline int xntimer_running_p(xntimer_t *timer)
00366 {
00367         return !testbits(timer->status,XNTIMER_DEQUEUED);
00368 }
00369 
00370 static inline int xntimer_reload_p(xntimer_t *timer)
00371 {
00372         return testbits(timer->status,
00373                         XNTIMER_PERIODIC|XNTIMER_DEQUEUED|XNTIMER_KILLED) ==
00374                 (XNTIMER_PERIODIC|XNTIMER_DEQUEUED);
00375 }
00376 
00377 #ifdef __cplusplus
00378 extern "C" {
00379 #endif
00380 
00381 extern xntbops_t nktimer_ops_aperiodic,
00382                  nktimer_ops_periodic;
00383 
00384 #ifdef CONFIG_XENO_OPT_STATS
00385 #define xntimer_init(timer, base, handler)              \
00386         do {                                            \
00387                 __xntimer_init(timer, base, handler);   \
00388                 (timer)->handler_name = #handler;       \
00389         } while (0)
00390 #else 
00391 #define xntimer_init    __xntimer_init
00392 #endif 
00393 
00394 #define xntimer_init_noblock(timer, base, handler)      \
00395         do {                                            \
00396                 xntimer_init(timer, base, handler);     \
00397                 (timer)->status |= XNTIMER_NOBLCK;      \
00398         } while(0)
00399 
00400 void __xntimer_init(struct xntimer *timer,
00401                     struct xntbase *base,
00402                     void (*handler)(struct xntimer *timer));
00403 
00404 void xntimer_destroy(xntimer_t *timer);
00405 
00406 static inline void xntimer_set_name(xntimer_t *timer, const char *name)
00407 {
00408 #ifdef CONFIG_XENO_OPT_STATS
00409         strncpy(timer->name, name, sizeof(timer->name));
00410 #endif 
00411 }
00412 
00413 void xntimer_next_local_shot(struct xnsched *sched);
00414 
00419 #if defined(CONFIG_XENO_OPT_TIMING_PERIODIC) || defined(DOXYGEN_CPP)
00420 
00473 static inline int xntimer_start(xntimer_t *timer,
00474                                 xnticks_t value, xnticks_t interval,
00475                                 xntmode_t mode)
00476 {
00477         return timer->base->ops->start_timer(timer, value, interval, mode);
00478 }
00479 
00505 static inline void xntimer_stop(xntimer_t *timer)
00506 {
00507         
00508 
00509 
00510 
00511         if (!testbits(timer->status,XNTIMER_DEQUEUED))
00512                 timer->base->ops->stop_timer(timer);
00513 }
00514 
00547 static inline xnticks_t xntimer_get_date(xntimer_t *timer)
00548 {
00549         if (!xntimer_running_p(timer))
00550                 return XN_INFINITE;
00551 
00552         return timer->base->ops->get_timer_date(timer);
00553 }
00554 
00589 static inline xnticks_t xntimer_get_timeout(xntimer_t *timer)
00590 {
00591         if (!xntimer_running_p(timer))
00592                 return XN_INFINITE;
00593 
00594         return timer->base->ops->get_timer_timeout(timer);
00595 }
00596 
00597 static inline xnticks_t xntimer_get_timeout_stopped(xntimer_t *timer)
00598 {
00599         return timer->base->ops->get_timer_timeout(timer);
00600 }
00601 
00633 static inline xnticks_t xntimer_get_interval(xntimer_t *timer)
00634 {
00635         return timer->base->ops->get_timer_interval(timer);
00636 }
00637 
00638 static inline xnticks_t xntimer_get_raw_expiry (xntimer_t *timer)
00639 {
00640         return timer->base->ops->get_timer_raw_expiry(timer);
00641 }
00642 
00643 void xntslave_init(xntslave_t *slave);
00644 
00645 void xntslave_destroy(xntslave_t *slave);
00646 
00647 void xntslave_update(xntslave_t *slave,
00648                      xnticks_t interval);
00649 
00650 void xntslave_start(xntslave_t *slave,
00651                     xnticks_t start,
00652                     xnticks_t interval);
00653 
00654 void xntslave_stop(xntslave_t *slave);
00655 
00656 void xntslave_adjust(xntslave_t *slave, xnsticks_t delta);
00657 
00658 #else 
00659 
00660 int xntimer_start_aperiodic(xntimer_t *timer,
00661                             xnticks_t value,
00662                             xnticks_t interval,
00663                             xntmode_t mode);
00664 
00665 void xntimer_stop_aperiodic(xntimer_t *timer);
00666 
00667 xnticks_t xntimer_get_date_aperiodic(xntimer_t *timer);
00668 
00669 xnticks_t xntimer_get_timeout_aperiodic(xntimer_t *timer);
00670 
00671 xnticks_t xntimer_get_interval_aperiodic(xntimer_t *timer);
00672 
00673 xnticks_t xntimer_get_raw_expiry_aperiodic(xntimer_t *timer);
00674 
00675 static inline int xntimer_start(xntimer_t *timer,
00676                                 xnticks_t value, xnticks_t interval,
00677                                 xntmode_t mode)
00678 {
00679         return xntimer_start_aperiodic(timer, value, interval, mode);
00680 }
00681 
00682 static inline void xntimer_stop(xntimer_t *timer)
00683 {
00684         if (!testbits(timer->status,XNTIMER_DEQUEUED))
00685                 xntimer_stop_aperiodic(timer);
00686 }
00687 
00688 static inline xnticks_t xntimer_get_date(xntimer_t *timer)
00689 {
00690         if (!xntimer_running_p(timer))
00691                 return XN_INFINITE;
00692 
00693         return xntimer_get_date_aperiodic(timer);
00694 }
00695 
00696 static inline xnticks_t xntimer_get_timeout(xntimer_t *timer)
00697 {
00698         if (!xntimer_running_p(timer))
00699                 return XN_INFINITE;
00700 
00701         return xntimer_get_timeout_aperiodic(timer);
00702 }
00703 
00704 static inline xnticks_t xntimer_get_timeout_stopped(xntimer_t *timer)
00705 {
00706         return xntimer_get_timeout_aperiodic(timer);
00707 }
00708 
00709 static inline xnticks_t xntimer_get_interval(xntimer_t *timer)
00710 {
00711         return xntimer_get_interval_aperiodic(timer);
00712 }
00713 
00714 static inline xnticks_t xntimer_get_raw_expiry (xntimer_t *timer)
00715 {
00716         return xntimerh_date(&timer->aplink);
00717 }
00718 
00719 #endif 
00720 
00723 void xntimer_init_proc(void);
00724 
00725 void xntimer_cleanup_proc(void);
00726 
00727 unsigned long xntimer_get_overruns(xntimer_t *timer, xnticks_t now);
00728 
00729 void xntimer_freeze(void);
00730 
00731 void xntimer_tick_aperiodic(void);
00732 
00733 void xntimer_tick_periodic(xntimer_t *timer);
00734 
00735 void xntimer_tick_periodic_inner(xntslave_t *slave);
00736 
00737 void xntimer_adjust_all_aperiodic(xnsticks_t delta);
00738 
00739 #ifdef CONFIG_SMP
00740 int xntimer_migrate(xntimer_t *timer,
00741                     struct xnsched *sched);
00742 #else 
00743 #define xntimer_migrate(timer, sched)           do { } while(0)
00744 #endif 
00745 
00746 #define xntimer_set_sched(timer, sched) xntimer_migrate(timer, sched)
00747 
00748 char *xntimer_format_time(xnticks_t value, int periodic,
00749                           char *buf, size_t bufsz);
00750 #ifdef __cplusplus
00751 }
00752 #endif
00753 
00754 #endif 
00755 
00756 #endif