include/nucleus/timer.h

Go to the documentation of this file.
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 /* Timer status */
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 
00045 /* These flags are available to the real-time interfaces */
00046 #define XNTIMER_SPARE0  0x01000000
00047 #define XNTIMER_SPARE1  0x02000000
00048 #define XNTIMER_SPARE2  0x04000000
00049 #define XNTIMER_SPARE3  0x08000000
00050 #define XNTIMER_SPARE4  0x10000000
00051 #define XNTIMER_SPARE5  0x20000000
00052 #define XNTIMER_SPARE6  0x40000000
00053 #define XNTIMER_SPARE7  0x80000000
00054 
00055 /* Timer priorities */
00056 #define XNTIMER_LOPRIO  (-999999999)
00057 #define XNTIMER_STDPRIO 0
00058 #define XNTIMER_HIPRIO  999999999
00059 
00060 #define XNTIMER_KEEPER_ID 0
00061 
00062 typedef struct {
00063         xnholder_t link;
00064         xnticks_t key;
00065         int prio;
00066 
00067 #define link2tlholder(ln)       container_of(ln, xntlholder_t, link)
00068 
00069 } xntlholder_t;
00070 
00071 #define xntlholder_date(h)      ((h)->key)
00072 #define xntlholder_prio(h)      ((h)->prio)
00073 #define xntlholder_init(h)      inith(&(h)->link)
00074 #define xntlist_init(q) initq(q)
00075 #define xntlist_head(q)                 \
00076         ({ xnholder_t *_h = getheadq(q);        \
00077                 !_h ? NULL : link2tlholder(_h); \
00078         })
00079 
00080 #define xntlist_next(q, h) \
00081         ({ xnholder_t *_h = nextq(q, &(h)->link);       \
00082                 !_h ? NULL : link2tlholder(_h);         \
00083         })
00084 
00085 static inline void xntlist_insert(xnqueue_t *q, xntlholder_t *holder)
00086 {
00087         xnholder_t *p;
00088 
00089         /* Insert the new timer at the proper place in the single
00090            queue managed when running in aperiodic mode. O(N) here,
00091            but users of the aperiodic mode need to pay a price for the
00092            increased flexibility... */
00093 
00094         for (p = q->head.last; p != &q->head; p = p->last)
00095                 if ((xnsticks_t) (holder->key - link2tlholder(p)->key) > 0 ||
00096                     (holder->key == link2tlholder(p)->key &&
00097                      holder->prio <= link2tlholder(p)->prio))
00098                         break;
00099 
00100         insertq(q,p->next,&holder->link);
00101 }
00102 
00103 #define xntlist_remove(q, h)  removeq((q),&(h)->link)
00104 
00105 #if defined(CONFIG_XENO_OPT_TIMER_HEAP)
00106 
00107 #include <nucleus/bheap.h>
00108 
00109 typedef bheaph_t xntimerh_t;
00110 
00111 #define xntimerh_date(h)          bheaph_key(h)
00112 #define xntimerh_prio(h)          bheaph_prio(h)
00113 #define xntimerh_init(h)          bheaph_init(h)
00114 
00115 typedef DECLARE_BHEAP_CONTAINER(xntimerq_t, CONFIG_XENO_OPT_TIMER_HEAP_CAPACITY);
00116 
00117 #define xntimerq_init(q)          bheap_init((q), CONFIG_XENO_OPT_TIMER_HEAP_CAPACITY)
00118 #define xntimerq_destroy(q)       bheap_destroy(q)
00119 #define xntimerq_head(q)          bheap_gethead(q)
00120 #define xntimerq_insert(q, h)     bheap_insert((q),(h))
00121 #define xntimerq_remove(q, h)     bheap_delete((q),(h))
00122 
00123 typedef struct {} xntimerq_it_t;
00124 
00125 #define xntimerq_it_begin(q, i)   ((void) (i), bheap_gethead(q))
00126 #define xntimerq_it_next(q, i, h) ((void) (i), bheap_next((q),(h)))
00127 
00128 #elif defined(CONFIG_XENO_OPT_TIMER_WHEEL)
00129 
00130 typedef xntlholder_t xntimerh_t;
00131 
00132 #define xntimerh_date(h)       xntlholder_date(h)
00133 #define xntimerh_prio(h)       xntlholder_prio(h)
00134 #define xntimerh_init(h)       xntlholder_init(h)
00135 
00136 typedef struct {
00137         unsigned date_shift;
00138         unsigned long long next_shot;
00139         unsigned long long shot_wrap;
00140         xnqueue_t bucket[XNTIMER_WHEELSIZE];
00141 } xntimerq_t;
00142 
00143 typedef struct {
00144         unsigned bucket;
00145 } xntimerq_it_t;
00146 
00147 static inline void xntimerq_init(xntimerq_t *q)
00148 {
00149         unsigned long long step_tsc;
00150         unsigned i;
00151 
00152         step_tsc = xnarch_ns_to_tsc(CONFIG_XENO_OPT_TIMER_WHEEL_STEP);
00153         /* q->date_shift = fls(step_tsc); */
00154         for (q->date_shift = 0; (1 << q->date_shift) < step_tsc; q->date_shift++)
00155                 ;
00156         q->next_shot = q->shot_wrap = ((~0ULL) >> q->date_shift) + 1;
00157         for (i = 0; i < sizeof(q->bucket)/sizeof(xnqueue_t); i++)
00158                 xntlist_init(&q->bucket[i]);
00159 }
00160 
00161 #define xntimerq_destroy(q)    do { } while (0)
00162 
00163 static inline xntlholder_t *xntimerq_head(xntimerq_t *q)
00164 {
00165         unsigned bucket = ((unsigned) q->next_shot) & XNTIMER_WHEELMASK;
00166         xntlholder_t *result;
00167         unsigned i;
00168 
00169         if (q->next_shot == q->shot_wrap)
00170                 return NULL;
00171 
00172         result = xntlist_head(&q->bucket[bucket]);
00173 
00174         if (result && (xntlholder_date(result) >> q->date_shift) == q->next_shot)
00175                 return result;
00176 
00177         /* We could not find the next timer in the first bucket, iterate over
00178            the other buckets. */
00179         for (i = (bucket + 1) & XNTIMER_WHEELMASK ;
00180              i != bucket; i = (i + 1) & XNTIMER_WHEELMASK) {
00181                 xntlholder_t *candidate = xntlist_head(&q->bucket[i]);
00182 
00183                 if(++q->next_shot == q->shot_wrap)
00184                         q->next_shot = 0;
00185 
00186                 if (!candidate)
00187                         continue;
00188 
00189                 if ((xntlholder_date(candidate) >> q->date_shift) == q->next_shot)
00190                         return candidate;
00191 
00192                 if (!result || (xnsticks_t) (xntlholder_date(candidate)
00193                                              - xntlholder_date(result)) < 0)
00194                         result = candidate;
00195         }
00196 
00197         if (result)
00198                 q->next_shot = (xntlholder_date(result) >> q->date_shift);
00199         else
00200                 q->next_shot = q->shot_wrap;
00201         return result;
00202 }
00203 
00204 static inline void xntimerq_insert(xntimerq_t *q, xntimerh_t *h)
00205 {
00206         unsigned long long shifted_date = xntlholder_date(h) >> q->date_shift;
00207         unsigned bucket = ((unsigned) shifted_date) & XNTIMER_WHEELMASK;
00208 
00209         if ((long long) (shifted_date - q->next_shot) < 0)
00210                 q->next_shot = shifted_date;
00211         xntlist_insert(&q->bucket[bucket], h);
00212 }
00213 
00214 static inline void xntimerq_remove(xntimerq_t *q, xntimerh_t *h)
00215 {
00216         unsigned long long shifted_date = xntlholder_date(h) >> q->date_shift;
00217         unsigned bucket = ((unsigned) shifted_date) & XNTIMER_WHEELMASK;
00218 
00219         xntlist_remove(&q->bucket[bucket], h);
00220         /* Do not attempt to update q->next_shot, xntimerq_head will recover. */
00221 }
00222 
00223 static inline xntimerh_t *xntimerq_it_begin(xntimerq_t *q, xntimerq_it_t *it)
00224 {
00225         xntimerh_t *holder = NULL;
00226 
00227         for (it->bucket = 0; it->bucket < XNTIMER_WHEELSIZE; it->bucket++)
00228                 if ((holder = xntlist_head(&q->bucket[it->bucket])))
00229                         break;
00230 
00231         return holder;
00232 }
00233 
00234 static inline xntimerh_t *
00235 xntimerq_it_next(xntimerq_t *q, xntimerq_it_t *it, xntimerh_t *holder)
00236 {
00237         xntimerh_t *next = xntlist_next(&q->bucket[it->bucket], holder);
00238 
00239         if (!next)
00240                 for(it->bucket++; it->bucket < XNTIMER_WHEELSIZE; it->bucket++)
00241                         if ((next = xntlist_head(&q->bucket[it->bucket])))
00242                                 break;
00243 
00244         return next;
00245 }
00246 
00247 #else /* CONFIG_XENO_OPT_TIMER_LIST */
00248 
00249 typedef xntlholder_t xntimerh_t;
00250 
00251 #define xntimerh_date(h)        xntlholder_date(h)
00252 #define xntimerh_prio(h)        xntlholder_prio(h)
00253 #define xntimerh_init(h)        xntlholder_init(h)
00254 
00255 typedef xnqueue_t xntimerq_t;
00256 
00257 #define xntimerq_init(q)        xntlist_init(q)
00258 #define xntimerq_destroy(q)     do { } while (0)
00259 #define xntimerq_head(q)        xntlist_head(q)
00260 #define xntimerq_insert(q,h)    xntlist_insert((q),(h))
00261 #define xntimerq_remove(q, h)   xntlist_remove((q),(h))
00262 
00263 typedef struct {} xntimerq_it_t;
00264 
00265 #define xntimerq_it_begin(q,i)  ((void) (i), xntlist_head(q))
00266 #define xntimerq_it_next(q,i,h) ((void) (i), xntlist_next((q),(h)))
00267 
00268 #endif /* CONFIG_XENO_OPT_TIMER_LIST */
00269 
00270 struct xnsched;
00271 
00272 typedef struct xntimer {
00273 
00274         xntimerh_t aplink;      /* Link in aperiodic timers list. */
00275 
00276 #define aplink2timer(ln) container_of(ln, xntimer_t, aplink)
00277 
00278 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC
00279         xntbase_t *base;        /* Time base. */
00280 
00281         xntlholder_t plink;     /* Link in periodic timers wheel. */
00282 
00283 #define plink2timer(ln) container_of(ln, xntimer_t, plink)
00284 #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC */
00285 
00286         xnholder_t adjlink;
00287 
00288 #define adjlink2timer(ln) container_of(ln, xntimer_t, adjlink)
00289 
00290         xnflags_t status;       /* !< Timer status. */
00291 
00292         xnticks_t interval;     /* !< Periodic interval (in ticks, 0 == one shot). */
00293 
00294         xnticks_t pexpect;      /* !< Date of next periodic release point (raw ticks). */
00295 
00296         struct xnsched *sched;  /* !< Sched structure to which the timer is
00297                                    attached. */
00298 
00299         void (*handler)(struct xntimer *timer); /* !< Timeout handler. */
00300 
00301 #ifdef CONFIG_XENO_OPT_STATS
00302         char name[XNOBJECT_NAME_LEN]; /* !< Timer name to be displayed. */
00303 
00304         const char *handler_name; /* !< Handler name to be displayed. */
00305 
00306         xnholder_t tblink;      /* !< Timer holder in timebase. */
00307 
00308 #define tblink2timer(ln)        container_of(ln, xntimer_t, tblink)
00309 #endif /* CONFIG_XENO_OPT_STATS */
00310 
00311         xnstat_counter_t scheduled; /* !< Number of timer schedules. */
00312 
00313         xnstat_counter_t fired; /* !< Number of timer events. */
00314 
00315         XNARCH_DECL_DISPLAY_CONTEXT();
00316 
00317 } xntimer_t;
00318 
00319 typedef struct xntimed_slave {
00320 
00321         xntbase_t base;         /* !< Cascaded time base. */
00322 
00323         struct percpu_cascade {
00324                 xntimer_t timer; /* !< Cascading timer in master time base. */
00325                 xnqueue_t wheel[XNTIMER_WHEELSIZE]; 
00326         } cascade[XNARCH_NR_CPUS];
00327 
00328 #define timer2slave(t) \
00329     ((xntslave_t *)(((char *)t) - offsetof(xntslave_t, cascade[xnsched_cpu((t)->sched)].timer)))
00330 #define base2slave(b) \
00331     ((xntslave_t *)(((char *)b) - offsetof(xntslave_t, base)))
00332 
00333 } xntslave_t;
00334 
00335 #ifdef CONFIG_SMP
00336 #define xntimer_sched(t)        ((t)->sched)
00337 #else /* !CONFIG_SMP */
00338 #define xntimer_sched(t)        xnpod_current_sched()
00339 #endif /* !CONFIG_SMP */
00340 #define xntimer_interval(t)     ((t)->interval)
00341 #define xntimer_set_cookie(t,c) ((t)->cookie = (c))
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 /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
00355 #define xntimer_base(t)         (&nktbase)
00356 #define xntimer_set_priority(t,p)                               \
00357         do { xntimerh_prio(&(t)->aplink) = (p); } while(0)
00358 #endif /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
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 /* !CONFIG_XENO_OPT_STATS */
00391 #define xntimer_init    __xntimer_init
00392 #endif /* !CONFIG_XENO_OPT_STATS */
00393 
00394 void __xntimer_init(xntimer_t *timer,
00395                   xntbase_t *base,
00396                   void (*handler)(xntimer_t *timer));
00397 
00398 void xntimer_destroy(xntimer_t *timer);
00399 
00400 static inline void xntimer_set_name(xntimer_t *timer, const char *name)
00401 {
00402 #ifdef CONFIG_XENO_OPT_STATS
00403         strncpy(timer->name, name, sizeof(timer->name));
00404 #endif /* CONFIG_XENO_OPT_STATS */
00405 }
00406 
00411 #if defined(CONFIG_XENO_OPT_TIMING_PERIODIC) || defined(DOXYGEN_CPP)
00412 
00465 static inline int xntimer_start(xntimer_t *timer,
00466                                 xnticks_t value, xnticks_t interval,
00467                                 xntmode_t mode)
00468 {
00469         return timer->base->ops->start_timer(timer, value, interval, mode);
00470 }
00471 
00497 static inline void xntimer_stop(xntimer_t *timer)
00498 {
00499         /* Careful: the do_timer_stop() helper is expected to preserve
00500            the date field of the stopped timer, so that subsequent
00501            calls to xntimer_get_timeout() would still work on such
00502            timer as expected. */
00503         if (!testbits(timer->status,XNTIMER_DEQUEUED))
00504                 timer->base->ops->stop_timer(timer);
00505 }
00506 
00539 static inline xnticks_t xntimer_get_date(xntimer_t *timer)
00540 {
00541         if (!xntimer_running_p(timer))
00542                 return XN_INFINITE;
00543 
00544         return timer->base->ops->get_timer_date(timer);
00545 }
00546 
00581 static inline xnticks_t xntimer_get_timeout(xntimer_t *timer)
00582 {
00583         if (!xntimer_running_p(timer))
00584                 return XN_INFINITE;
00585 
00586         return timer->base->ops->get_timer_timeout(timer);
00587 }
00588 
00620 static inline xnticks_t xntimer_get_interval(xntimer_t *timer)
00621 {
00622         return timer->base->ops->get_timer_interval(timer);
00623 }
00624 
00625 static inline xnticks_t xntimer_get_raw_expiry (xntimer_t *timer)
00626 {
00627         return timer->base->ops->get_timer_raw_expiry(timer);
00628 }
00629 
00630 void xntslave_init(xntslave_t *slave);
00631 
00632 void xntslave_destroy(xntslave_t *slave);
00633 
00634 void xntslave_update(xntslave_t *slave,
00635                      xnticks_t interval);
00636 
00637 void xntslave_start(xntslave_t *slave,
00638                     xnticks_t start,
00639                     xnticks_t interval);
00640 
00641 void xntslave_stop(xntslave_t *slave);
00642 
00643 void xntslave_adjust(xntslave_t *slave, xnsticks_t delta);
00644 
00645 #else /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
00646 
00647 int xntimer_start_aperiodic(xntimer_t *timer,
00648                             xnticks_t value,
00649                             xnticks_t interval,
00650                             xntmode_t mode);
00651 
00652 void xntimer_stop_aperiodic(xntimer_t *timer);
00653 
00654 xnticks_t xntimer_get_date_aperiodic(xntimer_t *timer);
00655 
00656 xnticks_t xntimer_get_timeout_aperiodic(xntimer_t *timer);
00657 
00658 xnticks_t xntimer_get_interval_aperiodic(xntimer_t *timer);
00659 
00660 xnticks_t xntimer_get_raw_expiry_aperiodic(xntimer_t *timer);
00661 
00662 static inline int xntimer_start(xntimer_t *timer,
00663                                 xnticks_t value, xnticks_t interval,
00664                                 xntmode_t mode)
00665 {
00666         return xntimer_start_aperiodic(timer, value, interval, mode);
00667 }
00668 
00669 static inline void xntimer_stop(xntimer_t *timer)
00670 {
00671         if (!testbits(timer->status,XNTIMER_DEQUEUED))
00672                 xntimer_stop_aperiodic(timer);
00673 }
00674 
00675 static inline xnticks_t xntimer_get_date(xntimer_t *timer)
00676 {
00677         if (!xntimer_running_p(timer))
00678                 return XN_INFINITE;
00679 
00680         return xntimer_get_date_aperiodic(timer);
00681 }
00682 
00683 static inline xnticks_t xntimer_get_timeout(xntimer_t *timer)
00684 {
00685         if (!xntimer_running_p(timer))
00686                 return XN_INFINITE;
00687 
00688         return xntimer_get_timeout_aperiodic(timer);
00689 }
00690 
00691 static inline xnticks_t xntimer_get_interval(xntimer_t *timer)
00692 {
00693         return xntimer_get_interval_aperiodic(timer);
00694 }
00695 
00696 static inline xnticks_t xntimer_get_raw_expiry (xntimer_t *timer)
00697 {
00698         return xntimerh_date(&timer->aplink);
00699 }
00700 
00701 #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC */
00702 
00705 unsigned long xntimer_get_overruns(xntimer_t *timer, xnticks_t now);
00706 
00707 void xntimer_freeze(void);
00708 
00709 void xntimer_tick_aperiodic(void);
00710 
00711 void xntimer_tick_periodic(xntimer_t *timer);
00712 
00713 void xntimer_tick_periodic_inner(xntslave_t *slave);
00714 
00715 void xntimer_adjust_all_aperiodic(xnsticks_t delta);
00716 
00717 #ifdef CONFIG_SMP
00718 int xntimer_migrate(xntimer_t *timer,
00719                     struct xnsched *sched);
00720 #else /* ! CONFIG_SMP */
00721 #define xntimer_migrate(timer, sched)           do { } while(0)
00722 #endif /* CONFIG_SMP */
00723 
00724 #define xntimer_set_sched(timer, sched) xntimer_migrate(timer, sched)
00725 
00726 #ifdef __cplusplus
00727 }
00728 #endif
00729 
00730 #endif /* __KERNEL__ || __XENO_SIM__ */
00731 
00732 #endif /* !_XENO_NUCLEUS_TIMER_H */

Generated on Mon Mar 24 18:02:40 2008 for Xenomai API by  doxygen 1.5.3