Xenomai API  2.6.4
timer.h
Go to the documentation of this file.
1 
23 #ifndef _XENO_NUCLEUS_TIMER_H
24 #define _XENO_NUCLEUS_TIMER_H
25 
26 #include <nucleus/timebase.h>
27 #include <nucleus/stat.h>
28 
29 #if defined(__KERNEL__) || defined(__XENO_SIM__)
30 
31 #ifndef CONFIG_XENO_OPT_DEBUG_TIMERS
32 #define CONFIG_XENO_OPT_DEBUG_TIMERS 0
33 #endif
34 
35 #define XNTIMER_WHEELSIZE 64
36 #define XNTIMER_WHEELMASK (XNTIMER_WHEELSIZE - 1)
37 
38 /* Timer status */
39 #define XNTIMER_DEQUEUED 0x00000001
40 #define XNTIMER_KILLED 0x00000002
41 #define XNTIMER_PERIODIC 0x00000004
42 #define XNTIMER_REALTIME 0x00000008
43 #define XNTIMER_FIRED 0x00000010
44 #define XNTIMER_NOBLCK 0x00000020
45 
46 /* These flags are available to the real-time interfaces */
47 #define XNTIMER_SPARE0 0x01000000
48 #define XNTIMER_SPARE1 0x02000000
49 #define XNTIMER_SPARE2 0x04000000
50 #define XNTIMER_SPARE3 0x08000000
51 #define XNTIMER_SPARE4 0x10000000
52 #define XNTIMER_SPARE5 0x20000000
53 #define XNTIMER_SPARE6 0x40000000
54 #define XNTIMER_SPARE7 0x80000000
55 
56 /* Timer priorities */
57 #define XNTIMER_LOPRIO (-999999999)
58 #define XNTIMER_STDPRIO 0
59 #define XNTIMER_HIPRIO 999999999
60 
61 #define XNTIMER_KEEPER_ID 0
62 
63 typedef struct {
64  xnholder_t link;
65  xnticks_t key;
66  int prio;
67 
68 #define link2tlholder(ln) container_of(ln, xntlholder_t, link)
69 
70 } xntlholder_t;
71 
72 #define xntlholder_date(h) ((h)->key)
73 #define xntlholder_prio(h) ((h)->prio)
74 #define xntlholder_init(h) inith(&(h)->link)
75 #define xntlist_init(q) initq(q)
76 #define xntlist_head(q) \
77  ({ xnholder_t *_h = getheadq(q); \
78  !_h ? NULL : link2tlholder(_h); \
79  })
80 
81 #define xntlist_next(q, h) \
82  ({ xnholder_t *_h = nextq(q, &(h)->link); \
83  !_h ? NULL : link2tlholder(_h); \
84  })
85 
86 static inline void xntlist_insert(xnqueue_t *q, xntlholder_t *holder)
87 {
88  xnholder_t *p;
89 
90  /* Insert the new timer at the proper place in the single
91  queue managed when running in aperiodic mode. O(N) here,
92  but users of the aperiodic mode need to pay a price for the
93  increased flexibility... */
94 
95  for (p = q->head.last; p != &q->head; p = p->last)
96  if ((xnsticks_t) (holder->key - link2tlholder(p)->key) > 0 ||
97  (holder->key == link2tlholder(p)->key &&
98  holder->prio <= link2tlholder(p)->prio))
99  break;
100 
101  insertq(q,p->next,&holder->link);
102 }
103 
104 #define xntlist_remove(q, h) removeq((q),&(h)->link)
105 
106 #if defined(CONFIG_XENO_OPT_TIMER_HEAP)
107 
108 #include <nucleus/bheap.h>
109 
110 typedef bheaph_t xntimerh_t;
111 
112 #define xntimerh_date(h) bheaph_key(h)
113 #define xntimerh_prio(h) bheaph_prio(h)
114 #define xntimerh_init(h) bheaph_init(h)
115 
116 typedef DECLARE_BHEAP_CONTAINER(xntimerq_t, CONFIG_XENO_OPT_TIMER_HEAP_CAPACITY);
117 
118 #define xntimerq_init(q) bheap_init((q), CONFIG_XENO_OPT_TIMER_HEAP_CAPACITY)
119 #define xntimerq_destroy(q) bheap_destroy(q)
120 #define xntimerq_head(q) bheap_gethead(q)
121 #define xntimerq_insert(q, h) bheap_insert((q),(h))
122 #define xntimerq_remove(q, h) bheap_delete((q),(h))
123 
124 typedef struct {} xntimerq_it_t;
125 
126 #define xntimerq_it_begin(q, i) ((void) (i), bheap_gethead(q))
127 #define xntimerq_it_next(q, i, h) ((void) (i), bheap_next((q),(h)))
128 
129 #elif defined(CONFIG_XENO_OPT_TIMER_WHEEL)
130 
131 typedef xntlholder_t xntimerh_t;
132 
133 #define xntimerh_date(h) xntlholder_date(h)
134 #define xntimerh_prio(h) xntlholder_prio(h)
135 #define xntimerh_init(h) xntlholder_init(h)
136 
137 typedef struct xntimerq {
138  unsigned date_shift;
139  unsigned long long next_shot;
140  unsigned long long shot_wrap;
141  xnqueue_t bucket[XNTIMER_WHEELSIZE];
142 } xntimerq_t;
143 
144 typedef struct xntimerq_it {
145  unsigned bucket;
146 } xntimerq_it_t;
147 
148 static inline void xntimerq_init(xntimerq_t *q)
149 {
150  unsigned long long step_tsc;
151  unsigned i;
152 
153  step_tsc = xnarch_ns_to_tsc(CONFIG_XENO_OPT_TIMER_WHEEL_STEP);
154  /* q->date_shift = fls(step_tsc); */
155  for (q->date_shift = 0; (1 << q->date_shift) < step_tsc; q->date_shift++)
156  ;
157  q->next_shot = q->shot_wrap = ((~0ULL) >> q->date_shift) + 1;
158  for (i = 0; i < sizeof(q->bucket)/sizeof(xnqueue_t); i++)
159  xntlist_init(&q->bucket[i]);
160 }
161 
162 #define xntimerq_destroy(q) do { } while (0)
163 
164 static inline xntlholder_t *xntimerq_head(xntimerq_t *q)
165 {
166  unsigned bucket = ((unsigned) q->next_shot) & XNTIMER_WHEELMASK;
167  xntlholder_t *result;
168  unsigned i;
169 
170  if (q->next_shot == q->shot_wrap)
171  return NULL;
172 
173  result = xntlist_head(&q->bucket[bucket]);
174 
175  if (result && (xntlholder_date(result) >> q->date_shift) == q->next_shot)
176  return result;
177 
178  /* We could not find the next timer in the first bucket, iterate over
179  the other buckets. */
180  for (i = (bucket + 1) & XNTIMER_WHEELMASK ;
181  i != bucket; i = (i + 1) & XNTIMER_WHEELMASK) {
182  xntlholder_t *candidate = xntlist_head(&q->bucket[i]);
183 
184  if(++q->next_shot == q->shot_wrap)
185  q->next_shot = 0;
186 
187  if (!candidate)
188  continue;
189 
190  if ((xntlholder_date(candidate) >> q->date_shift) == q->next_shot)
191  return candidate;
192 
193  if (!result || (xnsticks_t) (xntlholder_date(candidate)
194  - xntlholder_date(result)) < 0)
195  result = candidate;
196  }
197 
198  if (result)
199  q->next_shot = (xntlholder_date(result) >> q->date_shift);
200  else
201  q->next_shot = q->shot_wrap;
202  return result;
203 }
204 
205 static inline void xntimerq_insert(xntimerq_t *q, xntimerh_t *h)
206 {
207  unsigned long long shifted_date = xntlholder_date(h) >> q->date_shift;
208  unsigned bucket = ((unsigned) shifted_date) & XNTIMER_WHEELMASK;
209 
210  if ((long long) (shifted_date - q->next_shot) < 0)
211  q->next_shot = shifted_date;
212  xntlist_insert(&q->bucket[bucket], h);
213 }
214 
215 static inline void xntimerq_remove(xntimerq_t *q, xntimerh_t *h)
216 {
217  unsigned long long shifted_date = xntlholder_date(h) >> q->date_shift;
218  unsigned bucket = ((unsigned) shifted_date) & XNTIMER_WHEELMASK;
219 
220  xntlist_remove(&q->bucket[bucket], h);
221  /* Do not attempt to update q->next_shot, xntimerq_head will recover. */
222 }
223 
224 static inline xntimerh_t *xntimerq_it_begin(xntimerq_t *q, xntimerq_it_t *it)
225 {
226  xntimerh_t *holder = NULL;
227 
228  for (it->bucket = 0; it->bucket < XNTIMER_WHEELSIZE; it->bucket++)
229  if ((holder = xntlist_head(&q->bucket[it->bucket])))
230  break;
231 
232  return holder;
233 }
234 
235 static inline xntimerh_t *
236 xntimerq_it_next(xntimerq_t *q, xntimerq_it_t *it, xntimerh_t *holder)
237 {
238  xntimerh_t *next = xntlist_next(&q->bucket[it->bucket], holder);
239 
240  if (!next)
241  for(it->bucket++; it->bucket < XNTIMER_WHEELSIZE; it->bucket++)
242  if ((next = xntlist_head(&q->bucket[it->bucket])))
243  break;
244 
245  return next;
246 }
247 
248 #else /* CONFIG_XENO_OPT_TIMER_LIST */
249 
250 typedef xntlholder_t xntimerh_t;
251 
252 #define xntimerh_date(h) xntlholder_date(h)
253 #define xntimerh_prio(h) xntlholder_prio(h)
254 #define xntimerh_init(h) xntlholder_init(h)
255 
256 typedef xnqueue_t xntimerq_t;
257 
258 #define xntimerq_init(q) xntlist_init(q)
259 #define xntimerq_destroy(q) do { } while (0)
260 #define xntimerq_head(q) xntlist_head(q)
261 #define xntimerq_insert(q,h) xntlist_insert((q),(h))
262 #define xntimerq_remove(q, h) xntlist_remove((q),(h))
263 
264 typedef struct {} xntimerq_it_t;
265 
266 #define xntimerq_it_begin(q,i) ((void) (i), xntlist_head(q))
267 #define xntimerq_it_next(q,i,h) ((void) (i), xntlist_next((q),(h)))
268 
269 #endif /* CONFIG_XENO_OPT_TIMER_LIST */
270 
271 struct xnsched;
272 
273 typedef struct xntimer {
274 
275  xntimerh_t aplink; /* Link in aperiodic timers list. */
276 
277 #define aplink2timer(ln) container_of(ln, xntimer_t, aplink)
278 
279 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC
280  xntbase_t *base; /* Time base. */
281 
282  xntlholder_t plink; /* Link in periodic timers wheel. */
283 
284 #define plink2timer(ln) container_of(ln, xntimer_t, plink)
285 #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC */
286 
287  xnholder_t adjlink;
288 
289 #define adjlink2timer(ln) container_of(ln, xntimer_t, adjlink)
290 
291  xnflags_t status; /* !< Timer status. */
292 
293  xnticks_t interval; /* !< Periodic interval (in ticks, 0 == one shot). */
294 
295  xnticks_t pexpect; /* !< Date of next periodic release point (raw ticks). */
296 
297  struct xnsched *sched; /* !< Sched structure to which the timer is
298  attached. */
299 
300  void (*handler)(struct xntimer *timer); /* !< Timeout handler. */
301 
302 #ifdef CONFIG_XENO_OPT_STATS
303  char name[XNOBJECT_NAME_LEN]; /* !< Timer name to be displayed. */
304 
305  const char *handler_name; /* !< Handler name to be displayed. */
306 
307  xnholder_t tblink; /* !< Timer holder in timebase. */
308 
309 #define tblink2timer(ln) container_of(ln, xntimer_t, tblink)
310 #endif /* CONFIG_XENO_OPT_STATS */
311 
312  xnstat_counter_t scheduled; /* !< Number of timer schedules. */
313 
314  xnstat_counter_t fired; /* !< Number of timer events. */
315 
316  XNARCH_DECL_DISPLAY_CONTEXT();
317 
318 } xntimer_t;
319 
320 typedef struct xntimed_slave {
321 
322  xntbase_t base; /* !< Cascaded time base. */
323 
324  struct percpu_cascade {
325  xntimer_t timer; /* !< Cascading timer in master time base. */
326  xnqueue_t wheel[XNTIMER_WHEELSIZE];
327  } cascade[XNARCH_NR_CPUS];
328 
329 #define timer2slave(t) \
330  ((xntslave_t *)(((char *)t) - offsetof(xntslave_t, cascade[xnsched_cpu((t)->sched)].timer)))
331 #define base2slave(b) \
332  ((xntslave_t *)(((char *)b) - offsetof(xntslave_t, base)))
333 
334 } xntslave_t;
335 
336 #ifdef CONFIG_SMP
337 #define xntimer_sched(t) ((t)->sched)
338 #else /* !CONFIG_SMP */
339 #define xntimer_sched(t) xnpod_current_sched()
340 #endif /* !CONFIG_SMP */
341 #define xntimer_interval(t) ((t)->interval)
342 #define xntimer_pexpect(t) ((t)->pexpect)
343 #define xntimer_pexpect_forward(t,delta) ((t)->pexpect += delta)
344 
345 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC
346 #define xntimer_base(t) ((t)->base)
347 #define xntimer_set_priority(t,p) \
348  ({ \
349  xntimer_t *_t = (t); \
350  unsigned prio = (p); \
351  xntimerh_prio(&(_t)->aplink) = prio; \
352  xntlholder_prio(&(_t)->plink) = prio; \
353  })
354 #else /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
355 #define xntimer_base(t) (&nktbase)
356 #define xntimer_set_priority(t,p) \
357  do { xntimerh_prio(&(t)->aplink) = (p); } while(0)
358 #endif /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
359 
360 static inline int xntimer_active_p (xntimer_t *timer)
361 {
362  return timer->sched != NULL;
363 }
364 
365 static inline int xntimer_running_p(xntimer_t *timer)
366 {
367  return !testbits(timer->status,XNTIMER_DEQUEUED);
368 }
369 
370 static inline int xntimer_reload_p(xntimer_t *timer)
371 {
372  return testbits(timer->status,
373  XNTIMER_PERIODIC|XNTIMER_DEQUEUED|XNTIMER_KILLED) ==
374  (XNTIMER_PERIODIC|XNTIMER_DEQUEUED);
375 }
376 
377 #ifdef __cplusplus
378 extern "C" {
379 #endif
380 
381 extern xntbops_t nktimer_ops_aperiodic,
382  nktimer_ops_periodic;
383 
384 #ifdef CONFIG_XENO_OPT_STATS
385 #define xntimer_init(timer, base, handler) \
386  do { \
387  __xntimer_init(timer, base, handler); \
388  (timer)->handler_name = #handler; \
389  } while (0)
390 #else /* !CONFIG_XENO_OPT_STATS */
391 #define xntimer_init __xntimer_init
392 #endif /* !CONFIG_XENO_OPT_STATS */
393 
394 #define xntimer_init_noblock(timer, base, handler) \
395  do { \
396  xntimer_init(timer, base, handler); \
397  (timer)->status |= XNTIMER_NOBLCK; \
398  } while(0)
399 
400 void __xntimer_init(struct xntimer *timer,
401  struct xntbase *base,
402  void (*handler)(struct xntimer *timer));
403 
404 void xntimer_destroy(xntimer_t *timer);
405 
406 static inline void xntimer_set_name(xntimer_t *timer, const char *name)
407 {
408 #ifdef CONFIG_XENO_OPT_STATS
409  strncpy(timer->name, name, sizeof(timer->name));
410 #endif /* CONFIG_XENO_OPT_STATS */
411 }
412 
413 void xntimer_next_local_shot(struct xnsched *sched);
414 
419 #if defined(CONFIG_XENO_OPT_TIMING_PERIODIC) || defined(DOXYGEN_CPP)
420 
473 static inline int xntimer_start(xntimer_t *timer,
474  xnticks_t value, xnticks_t interval,
475  xntmode_t mode)
476 {
477  return timer->base->ops->start_timer(timer, value, interval, mode);
478 }
479 
505 static inline void xntimer_stop(xntimer_t *timer)
506 {
507  /* Careful: the do_timer_stop() helper is expected to preserve
508  the date field of the stopped timer, so that subsequent
509  calls to xntimer_get_timeout() would still work on such
510  timer as expected. */
511  if (!testbits(timer->status,XNTIMER_DEQUEUED))
512  timer->base->ops->stop_timer(timer);
513 }
514 
547 static inline xnticks_t xntimer_get_date(xntimer_t *timer)
548 {
549  if (!xntimer_running_p(timer))
550  return XN_INFINITE;
551 
552  return timer->base->ops->get_timer_date(timer);
553 }
554 
589 static inline xnticks_t xntimer_get_timeout(xntimer_t *timer)
590 {
591  if (!xntimer_running_p(timer))
592  return XN_INFINITE;
593 
594  return timer->base->ops->get_timer_timeout(timer);
595 }
596 
597 static inline xnticks_t xntimer_get_timeout_stopped(xntimer_t *timer)
598 {
599  return timer->base->ops->get_timer_timeout(timer);
600 }
601 
633 static inline xnticks_t xntimer_get_interval(xntimer_t *timer)
634 {
635  return timer->base->ops->get_timer_interval(timer);
636 }
637 
638 static inline xnticks_t xntimer_get_raw_expiry (xntimer_t *timer)
639 {
640  return timer->base->ops->get_timer_raw_expiry(timer);
641 }
642 
643 void xntslave_init(xntslave_t *slave);
644 
645 void xntslave_destroy(xntslave_t *slave);
646 
647 void xntslave_update(xntslave_t *slave,
648  xnticks_t interval);
649 
650 void xntslave_start(xntslave_t *slave,
651  xnticks_t start,
652  xnticks_t interval);
653 
654 void xntslave_stop(xntslave_t *slave);
655 
656 void xntslave_adjust(xntslave_t *slave, xnsticks_t delta);
657 
658 #else /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
659 
660 int xntimer_start_aperiodic(xntimer_t *timer,
661  xnticks_t value,
662  xnticks_t interval,
663  xntmode_t mode);
664 
665 void xntimer_stop_aperiodic(xntimer_t *timer);
666 
667 xnticks_t xntimer_get_date_aperiodic(xntimer_t *timer);
668 
669 xnticks_t xntimer_get_timeout_aperiodic(xntimer_t *timer);
670 
671 xnticks_t xntimer_get_interval_aperiodic(xntimer_t *timer);
672 
673 xnticks_t xntimer_get_raw_expiry_aperiodic(xntimer_t *timer);
674 
675 static inline int xntimer_start(xntimer_t *timer,
676  xnticks_t value, xnticks_t interval,
677  xntmode_t mode)
678 {
679  return xntimer_start_aperiodic(timer, value, interval, mode);
680 }
681 
682 static inline void xntimer_stop(xntimer_t *timer)
683 {
684  if (!testbits(timer->status,XNTIMER_DEQUEUED))
685  xntimer_stop_aperiodic(timer);
686 }
687 
688 static inline xnticks_t xntimer_get_date(xntimer_t *timer)
689 {
690  if (!xntimer_running_p(timer))
691  return XN_INFINITE;
692 
693  return xntimer_get_date_aperiodic(timer);
694 }
695 
696 static inline xnticks_t xntimer_get_timeout(xntimer_t *timer)
697 {
698  if (!xntimer_running_p(timer))
699  return XN_INFINITE;
700 
701  return xntimer_get_timeout_aperiodic(timer);
702 }
703 
704 static inline xnticks_t xntimer_get_timeout_stopped(xntimer_t *timer)
705 {
706  return xntimer_get_timeout_aperiodic(timer);
707 }
708 
709 static inline xnticks_t xntimer_get_interval(xntimer_t *timer)
710 {
711  return xntimer_get_interval_aperiodic(timer);
712 }
713 
714 static inline xnticks_t xntimer_get_raw_expiry (xntimer_t *timer)
715 {
716  return xntimerh_date(&timer->aplink);
717 }
718 
719 #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC */
720 
723 void xntimer_init_proc(void);
724 
725 void xntimer_cleanup_proc(void);
726 
727 unsigned long xntimer_get_overruns(xntimer_t *timer, xnticks_t now);
728 
729 void xntimer_freeze(void);
730 
731 void xntimer_tick_aperiodic(void);
732 
733 void xntimer_tick_periodic(xntimer_t *timer);
734 
735 void xntimer_tick_periodic_inner(xntslave_t *slave);
736 
737 void xntimer_adjust_all_aperiodic(xnsticks_t delta);
738 
739 #ifdef CONFIG_SMP
740 int xntimer_migrate(xntimer_t *timer,
741  struct xnsched *sched);
742 #else /* ! CONFIG_SMP */
743 #define xntimer_migrate(timer, sched) do { } while(0)
744 #endif /* CONFIG_SMP */
745 
746 #define xntimer_set_sched(timer, sched) xntimer_migrate(timer, sched)
747 
748 char *xntimer_format_time(xnticks_t value, int periodic,
749  char *buf, size_t bufsz);
750 #ifdef __cplusplus
751 }
752 #endif
753 
754 #endif /* __KERNEL__ || __XENO_SIM__ */
755 
756 #endif /* !_XENO_NUCLEUS_TIMER_H */