Xenomai API
2.5.6.1
|
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 #define XNTIMER_NOBLCK 0x00000020 00045 00046 /* These flags are available to the real-time interfaces */ 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 /* Timer priorities */ 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 /* Insert the new timer at the proper place in the single 00091 queue managed when running in aperiodic mode. O(N) here, 00092 but users of the aperiodic mode need to pay a price for the 00093 increased flexibility... */ 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 /* q->date_shift = fls(step_tsc); */ 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 /* We could not find the next timer in the first bucket, iterate over 00179 the other buckets. */ 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 /* Do not attempt to update q->next_shot, xntimerq_head will recover. */ 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 /* CONFIG_XENO_OPT_TIMER_LIST */ 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 /* CONFIG_XENO_OPT_TIMER_LIST */ 00270 00271 struct xnsched; 00272 00273 typedef struct xntimer { 00274 00275 xntimerh_t aplink; /* Link in aperiodic timers list. */ 00276 00277 #define aplink2timer(ln) container_of(ln, xntimer_t, aplink) 00278 00279 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC 00280 xntbase_t *base; /* Time base. */ 00281 00282 xntlholder_t plink; /* Link in periodic timers wheel. */ 00283 00284 #define plink2timer(ln) container_of(ln, xntimer_t, plink) 00285 #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC */ 00286 00287 xnholder_t adjlink; 00288 00289 #define adjlink2timer(ln) container_of(ln, xntimer_t, adjlink) 00290 00291 xnflags_t status; /* !< Timer status. */ 00292 00293 xnticks_t interval; /* !< Periodic interval (in ticks, 0 == one shot). */ 00294 00295 xnticks_t pexpect; /* !< Date of next periodic release point (raw ticks). */ 00296 00297 struct xnsched *sched; /* !< Sched structure to which the timer is 00298 attached. */ 00299 00300 void (*handler)(struct xntimer *timer); /* !< Timeout handler. */ 00301 00302 #ifdef CONFIG_XENO_OPT_STATS 00303 char name[XNOBJECT_NAME_LEN]; /* !< Timer name to be displayed. */ 00304 00305 const char *handler_name; /* !< Handler name to be displayed. */ 00306 00307 xnholder_t tblink; /* !< Timer holder in timebase. */ 00308 00309 #define tblink2timer(ln) container_of(ln, xntimer_t, tblink) 00310 #endif /* CONFIG_XENO_OPT_STATS */ 00311 00312 xnstat_counter_t scheduled; /* !< Number of timer schedules. */ 00313 00314 xnstat_counter_t fired; /* !< Number of timer events. */ 00315 00316 XNARCH_DECL_DISPLAY_CONTEXT(); 00317 00318 } xntimer_t; 00319 00320 typedef struct xntimed_slave { 00321 00322 xntbase_t base; /* !< Cascaded time base. */ 00323 00324 struct percpu_cascade { 00325 xntimer_t timer; /* !< Cascading timer in master time base. */ 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 /* !CONFIG_SMP */ 00339 #define xntimer_sched(t) xnpod_current_sched() 00340 #endif /* !CONFIG_SMP */ 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 /* !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 #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 /* CONFIG_XENO_OPT_STATS */ 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 /* Careful: the do_timer_stop() helper is expected to preserve 00508 the date field of the stopped timer, so that subsequent 00509 calls to xntimer_get_timeout() would still work on such 00510 timer as expected. */ 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 /* !CONFIG_XENO_OPT_TIMING_PERIODIC */ 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 /* CONFIG_XENO_OPT_TIMING_PERIODIC */ 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 /* ! CONFIG_SMP */ 00743 #define xntimer_migrate(timer, sched) do { } while(0) 00744 #endif /* CONFIG_SMP */ 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 /* __KERNEL__ || __XENO_SIM__ */ 00755 00756 #endif /* !_XENO_NUCLEUS_TIMER_H */