Xenomai  3.0.3
timer.h
1 /*
2  * Copyright (C) 2001,2002,2003 Philippe Gerum <rpm@xenomai.org>.
3  *
4  * Xenomai is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published
6  * by the Free Software Foundation; either version 2 of the License,
7  * or (at your option) any later version.
8  *
9  * Xenomai is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with Xenomai; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17  * 02111-1307, USA.
18  */
19 
20 #ifndef _COBALT_KERNEL_TIMER_H
21 #define _COBALT_KERNEL_TIMER_H
22 
23 #include <cobalt/kernel/clock.h>
24 #include <cobalt/kernel/stat.h>
25 #include <cobalt/kernel/list.h>
26 #include <cobalt/kernel/assert.h>
27 #include <cobalt/kernel/ancillaries.h>
28 #include <asm/xenomai/wrappers.h>
29 
34 #define XN_INFINITE ((xnticks_t)0)
35 #define XN_NONBLOCK ((xnticks_t)-1)
36 
37 /* Timer modes */
38 typedef enum xntmode {
39  XN_RELATIVE,
40  XN_ABSOLUTE,
41  XN_REALTIME
42 } xntmode_t;
43 
44 /* Timer status */
45 #define XNTIMER_DEQUEUED 0x00000001
46 #define XNTIMER_KILLED 0x00000002
47 #define XNTIMER_PERIODIC 0x00000004
48 #define XNTIMER_REALTIME 0x00000008
49 #define XNTIMER_FIRED 0x00000010
50 #define XNTIMER_NOBLCK 0x00000020
51 #define XNTIMER_RUNNING 0x00000040
52 #define XNTIMER_KGRAVITY 0x00000080
53 #define XNTIMER_UGRAVITY 0x00000100
54 #define XNTIMER_IGRAVITY 0 /* most conservative */
55 
56 #define XNTIMER_GRAVITY_MASK (XNTIMER_KGRAVITY|XNTIMER_UGRAVITY)
57 #define XNTIMER_INIT_MASK (XNTIMER_GRAVITY_MASK|XNTIMER_NOBLCK)
58 
59 #define __XNTIMER_CORE 0x10000000
60 
61 /* These flags are available to the real-time interfaces */
62 #define XNTIMER_SPARE0 0x01000000
63 #define XNTIMER_SPARE1 0x02000000
64 #define XNTIMER_SPARE2 0x04000000
65 #define XNTIMER_SPARE3 0x08000000
66 #define XNTIMER_SPARE4 0x10000000
67 #define XNTIMER_SPARE5 0x20000000
68 #define XNTIMER_SPARE6 0x40000000
69 #define XNTIMER_SPARE7 0x80000000
70 
71 /* Timer priorities */
72 #define XNTIMER_LOPRIO (-999999999)
73 #define XNTIMER_STDPRIO 0
74 #define XNTIMER_HIPRIO 999999999
75 
76 struct xntlholder {
77  struct list_head link;
78  xnticks_t key;
79  int prio;
80 };
81 
82 #define xntlholder_date(h) ((h)->key)
83 #define xntlholder_prio(h) ((h)->prio)
84 #define xntlist_init(q) INIT_LIST_HEAD(q)
85 #define xntlist_empty(q) list_empty(q)
86 
87 static inline struct xntlholder *xntlist_head(struct list_head *q)
88 {
89  if (list_empty(q))
90  return NULL;
91 
92  return list_first_entry(q, struct xntlholder, link);
93 }
94 
95 static inline struct xntlholder *xntlist_next(struct list_head *q,
96  struct xntlholder *h)
97 {
98  if (list_is_last(&h->link, q))
99  return NULL;
100 
101  return list_entry(h->link.next, struct xntlholder, link);
102 }
103 
104 static inline struct xntlholder *xntlist_second(struct list_head *q,
105  struct xntlholder *h)
106 {
107  return xntlist_next(q, h);
108 }
109 
110 static inline void xntlist_insert(struct list_head *q, struct xntlholder *holder)
111 {
112  struct xntlholder *p;
113 
114  if (list_empty(q)) {
115  list_add(&holder->link, q);
116  return;
117  }
118 
119  /*
120  * Insert the new timer at the proper place in the single
121  * queue. O(N) here, but this is the price for the increased
122  * flexibility...
123  */
124  list_for_each_entry_reverse(p, q, link) {
125  if ((xnsticks_t) (holder->key - p->key) > 0 ||
126  (holder->key == p->key && holder->prio <= p->prio))
127  break;
128  }
129 
130  list_add(&holder->link, &p->link);
131 }
132 
133 #define xntlist_remove(q, h) \
134  do { \
135  (void)(q); \
136  list_del(&(h)->link); \
137  } while (0)
138 
139 #if defined(CONFIG_XENO_OPT_TIMER_RBTREE)
140 
141 #include <linux/rbtree.h>
142 
143 typedef struct {
144  unsigned long long date;
145  unsigned prio;
146  struct rb_node link;
147 } xntimerh_t;
148 
149 #define xntimerh_date(h) ((h)->date)
150 #define xntimerh_prio(h) ((h)->prio)
151 #define xntimerh_init(h) do { } while (0)
152 
153 typedef struct {
154  struct rb_root root;
155  xntimerh_t *head;
156 } xntimerq_t;
157 
158 #define xntimerq_init(q) \
159  ({ \
160  xntimerq_t *_q = (q); \
161  _q->root = RB_ROOT; \
162  _q->head = NULL; \
163  })
164 
165 #define xntimerq_destroy(q) do { } while (0)
166 #define xntimerq_empty(q) ((q)->head != NULL)
167 
168 #define xntimerq_head(q) ((q)->head)
169 
170 #define xntimerq_next(q, h) \
171  ({ \
172  struct rb_node *_node = rb_next(&(h)->link); \
173  _node ? (container_of(_node, xntimerh_t, link)) : NULL; \
174  })
175 
176 #define xntimerq_second(q, h) xntimerq_next(q, h)
177 
178 void xntimerq_insert(xntimerq_t *q, xntimerh_t *holder);
179 
180 static inline void xntimerq_remove(xntimerq_t *q, xntimerh_t *holder)
181 {
182  if (holder == q->head)
183  q->head = xntimerq_second(q, holder);
184 
185  rb_erase(&holder->link, &q->root);
186 }
187 
188 typedef struct { } xntimerq_it_t;
189 
190 #define xntimerq_it_begin(q,i) ((void) (i), xntimerq_head(q))
191 #define xntimerq_it_next(q,i,h) ((void) (i), xntimerq_next((q),(h)))
192 
193 #else /* CONFIG_XENO_OPT_TIMER_LIST */
194 
195 typedef struct xntlholder xntimerh_t;
196 
197 #define xntimerh_date(h) xntlholder_date(h)
198 #define xntimerh_prio(h) xntlholder_prio(h)
199 #define xntimerh_init(h) do { } while (0)
200 
201 typedef struct list_head xntimerq_t;
202 
203 #define xntimerq_init(q) xntlist_init(q)
204 #define xntimerq_destroy(q) do { } while (0)
205 #define xntimerq_empty(q) xntlist_empty(q)
206 #define xntimerq_head(q) xntlist_head(q)
207 #define xntimerq_second(q, h) xntlist_second((q),(h))
208 #define xntimerq_insert(q, h) xntlist_insert((q),(h))
209 #define xntimerq_remove(q, h) xntlist_remove((q),(h))
210 
211 typedef struct { } xntimerq_it_t;
212 
213 #define xntimerq_it_begin(q,i) ((void) (i), xntlist_head(q))
214 #define xntimerq_it_next(q,i,h) ((void) (i), xntlist_next((q),(h)))
215 
216 #endif /* CONFIG_XENO_OPT_TIMER_LIST */
217 
218 struct xnsched;
219 
220 struct xntimerdata {
221  xntimerq_t q;
222 };
223 
224 static inline struct xntimerdata *
225 xnclock_percpu_timerdata(struct xnclock *clock, int cpu)
226 {
227  return per_cpu_ptr(clock->timerdata, cpu);
228 }
229 
230 static inline struct xntimerdata *
231 xnclock_this_timerdata(struct xnclock *clock)
232 {
233  return raw_cpu_ptr(clock->timerdata);
234 }
235 
236 struct xntimer {
237 #ifdef CONFIG_XENO_OPT_EXTCLOCK
238  struct xnclock *clock;
239 #endif
240 
241  xntimerh_t aplink;
242  struct list_head adjlink;
244  unsigned long status;
246  xnticks_t interval;
248  xnticks_t interval_ns;
250  xnticks_t periodic_ticks;
252  xnticks_t start_date;
254  xnticks_t pexpect_ticks;
256  struct xnsched *sched;
258  void (*handler)(struct xntimer *timer);
259 #ifdef CONFIG_XENO_OPT_STATS
260 #ifdef CONFIG_XENO_OPT_EXTCLOCK
261  struct xnclock *tracker;
262 #endif
263 
264  char name[XNOBJECT_NAME_LEN];
266  struct list_head next_stat;
268  xnstat_counter_t scheduled;
270  xnstat_counter_t fired;
271 #endif /* CONFIG_XENO_OPT_STATS */
272 };
273 
274 #ifdef CONFIG_XENO_OPT_EXTCLOCK
275 
276 static inline struct xnclock *xntimer_clock(struct xntimer *timer)
277 {
278  return timer->clock;
279 }
280 
281 void xntimer_set_clock(struct xntimer *timer,
282  struct xnclock *newclock);
283 
284 #else /* !CONFIG_XENO_OPT_EXTCLOCK */
285 
286 static inline struct xnclock *xntimer_clock(struct xntimer *timer)
287 {
288  return &nkclock;
289 }
290 
291 static inline void xntimer_set_clock(struct xntimer *timer,
292  struct xnclock *newclock)
293 {
294  XENO_BUG_ON(COBALT, newclock != &nkclock);
295 }
296 
297 #endif /* !CONFIG_XENO_OPT_EXTCLOCK */
298 
299 #ifdef CONFIG_SMP
300 static inline struct xnsched *xntimer_sched(struct xntimer *timer)
301 {
302  return timer->sched;
303 }
304 #else /* !CONFIG_SMP */
305 #define xntimer_sched(t) xnsched_current()
306 #endif /* !CONFIG_SMP */
307 
308 #define xntimer_percpu_queue(__timer) \
309  ({ \
310  struct xntimerdata *tmd; \
311  int cpu = xnsched_cpu((__timer)->sched); \
312  tmd = xnclock_percpu_timerdata(xntimer_clock(__timer), cpu); \
313  &tmd->q; \
314  })
315 
316 static inline xntimerq_t *xntimer_this_queue(struct xntimer *timer)
317 {
318  struct xntimerdata *tmd;
319 
320  tmd = xnclock_this_timerdata(xntimer_clock(timer));
321 
322  return &tmd->q;
323 }
324 
325 static inline unsigned long xntimer_gravity(struct xntimer *timer)
326 {
327  struct xnclock *clock = xntimer_clock(timer);
328 
329  if (timer->status & XNTIMER_KGRAVITY)
330  return clock->gravity.kernel;
331 
332  if (timer->status & XNTIMER_UGRAVITY)
333  return clock->gravity.user;
334 
335  return clock->gravity.irq;
336 }
337 
338 static inline void xntimer_update_date(struct xntimer *timer)
339 {
340  xntimerh_date(&timer->aplink) = timer->start_date
341  + xnclock_ns_to_ticks(xntimer_clock(timer),
342  timer->periodic_ticks * timer->interval_ns)
343  - xntimer_gravity(timer);
344 }
345 
346 static inline xnticks_t xntimer_pexpect(struct xntimer *timer)
347 {
348  return timer->start_date +
349  xnclock_ns_to_ticks(xntimer_clock(timer),
350  timer->pexpect_ticks * timer->interval_ns);
351 }
352 
353 static inline void xntimer_set_priority(struct xntimer *timer,
354  int prio)
355 {
356  xntimerh_prio(&timer->aplink) = prio;
357 }
358 
359 static inline int xntimer_active_p(struct xntimer *timer)
360 {
361  return timer->sched != NULL;
362 }
363 
364 static inline int xntimer_running_p(struct xntimer *timer)
365 {
366  return (timer->status & XNTIMER_RUNNING) != 0;
367 }
368 
369 static inline int xntimer_fired_p(struct xntimer *timer)
370 {
371  return (timer->status & XNTIMER_FIRED) != 0;
372 }
373 
374 static inline int xntimer_periodic_p(struct xntimer *timer)
375 {
376  return (timer->status & XNTIMER_PERIODIC) != 0;
377 }
378 
379 void __xntimer_init(struct xntimer *timer,
380  struct xnclock *clock,
381  void (*handler)(struct xntimer *timer),
382  struct xnsched *sched,
383  int flags);
384 
385 void xntimer_set_gravity(struct xntimer *timer,
386  int gravity);
387 
388 #ifdef CONFIG_XENO_OPT_STATS
389 
390 #define xntimer_init(__timer, __clock, __handler, __sched, __flags) \
391 do { \
392  __xntimer_init(__timer, __clock, __handler, __sched, __flags); \
393  xntimer_set_name(__timer, #__handler); \
394 } while (0)
395 
396 static inline void xntimer_reset_stats(struct xntimer *timer)
397 {
398  xnstat_counter_set(&timer->scheduled, 0);
399  xnstat_counter_set(&timer->fired, 0);
400 }
401 
402 static inline void xntimer_account_scheduled(struct xntimer *timer)
403 {
404  xnstat_counter_inc(&timer->scheduled);
405 }
406 
407 static inline void xntimer_account_fired(struct xntimer *timer)
408 {
409  xnstat_counter_inc(&timer->fired);
410 }
411 
412 static inline void xntimer_set_name(struct xntimer *timer, const char *name)
413 {
414  knamecpy(timer->name, name);
415 }
416 
417 #else /* !CONFIG_XENO_OPT_STATS */
418 
419 #define xntimer_init __xntimer_init
420 
421 static inline void xntimer_reset_stats(struct xntimer *timer) { }
422 
423 static inline void xntimer_account_scheduled(struct xntimer *timer) { }
424 
425 static inline void xntimer_account_fired(struct xntimer *timer) { }
426 
427 static inline void xntimer_set_name(struct xntimer *timer, const char *name) { }
428 
429 #endif /* !CONFIG_XENO_OPT_STATS */
430 
431 #if defined(CONFIG_XENO_OPT_EXTCLOCK) && defined(CONFIG_XENO_OPT_STATS)
432 void xntimer_switch_tracking(struct xntimer *timer,
433  struct xnclock *newclock);
434 #else
435 static inline
436 void xntimer_switch_tracking(struct xntimer *timer,
437  struct xnclock *newclock) { }
438 #endif
439 
440 void xntimer_destroy(struct xntimer *timer);
441 
457 static inline xnticks_t xntimer_interval(struct xntimer *timer)
458 {
459  return timer->interval_ns;
460 }
461 
462 static inline xnticks_t xntimer_expiry(struct xntimer *timer)
463 {
464  /* Real expiry date in ticks without anticipation (no gravity) */
465  return xntimerh_date(&timer->aplink) + xntimer_gravity(timer);
466 }
467 
468 int xntimer_start(struct xntimer *timer,
469  xnticks_t value,
470  xnticks_t interval,
471  xntmode_t mode);
472 
473 void __xntimer_stop(struct xntimer *timer);
474 
475 xnticks_t xntimer_get_date(struct xntimer *timer);
476 
477 xnticks_t __xntimer_get_timeout(struct xntimer *timer);
478 
479 xnticks_t xntimer_get_interval(struct xntimer *timer);
480 
481 int xntimer_heading_p(struct xntimer *timer);
482 
483 static inline void xntimer_stop(struct xntimer *timer)
484 {
485  if (timer->status & XNTIMER_RUNNING)
486  __xntimer_stop(timer);
487 }
488 
489 static inline xnticks_t xntimer_get_timeout(struct xntimer *timer)
490 {
491  if (!xntimer_running_p(timer))
492  return XN_INFINITE;
493 
494  return __xntimer_get_timeout(timer);
495 }
496 
497 static inline xnticks_t xntimer_get_timeout_stopped(struct xntimer *timer)
498 {
499  return __xntimer_get_timeout(timer);
500 }
501 
502 static inline void xntimer_enqueue(struct xntimer *timer,
503  xntimerq_t *q)
504 {
505  xntimerq_insert(q, &timer->aplink);
506  timer->status &= ~XNTIMER_DEQUEUED;
507  xntimer_account_scheduled(timer);
508 }
509 
510 static inline void xntimer_dequeue(struct xntimer *timer,
511  xntimerq_t *q)
512 {
513  xntimerq_remove(q, &timer->aplink);
514  timer->status |= XNTIMER_DEQUEUED;
515 }
516 
519 unsigned long long xntimer_get_overruns(struct xntimer *timer, xnticks_t now);
520 
521 #ifdef CONFIG_SMP
522 
523 void __xntimer_migrate(struct xntimer *timer, struct xnsched *sched);
524 
525 static inline
526 void xntimer_migrate(struct xntimer *timer, struct xnsched *sched)
527 { /* nklocked, IRQs off */
528  if (timer->sched != sched)
529  __xntimer_migrate(timer, sched);
530 }
531 
532 int xntimer_setup_ipi(void);
533 
534 void xntimer_release_ipi(void);
535 
536 #else /* ! CONFIG_SMP */
537 
538 static inline void xntimer_migrate(struct xntimer *timer,
539  struct xnsched *sched)
540 { }
541 
542 static inline int xntimer_setup_ipi(void)
543 {
544  return 0;
545 }
546 
547 static inline void xntimer_release_ipi(void) { }
548 
549 #endif /* CONFIG_SMP */
550 
551 static inline void xntimer_set_sched(struct xntimer *timer,
552  struct xnsched *sched)
553 {
554  xntimer_migrate(timer, sched);
555 }
556 
557 char *xntimer_format_time(xnticks_t ns,
558  char *buf, size_t bufsz);
559 
560 int xntimer_grab_hardware(void);
561 
562 void xntimer_release_hardware(void);
563 
566 #endif /* !_COBALT_KERNEL_TIMER_H */
static xnticks_t xntimer_get_timeout(struct xntimer *timer)
Return the relative expiration date.
Definition: timer.h:489
xnticks_t xntimer_get_date(struct xntimer *timer)
Return the absolute expiration date.
Definition: timer.c:242
void __xntimer_migrate(struct xntimer *timer, struct xnsched *sched)
Migrate a timer.
Definition: timer.c:525
Scheduling information structure.
Definition: sched.h:57
int xntimer_start(struct xntimer *timer, xnticks_t value, xnticks_t interval, xntmode_t mode)
Arm a timer.
Definition: timer.c:113
void xntimer_destroy(struct xntimer *timer)
Release a timer object.
Definition: timer.c:491
unsigned long long xntimer_get_overruns(struct xntimer *timer, xnticks_t now)
Get the count of overruns for the last tick.
Definition: timer.c:590
void xntimer_release_hardware(void)
Release hardware timers.
Definition: timer.c:908
static xnticks_t xntimer_interval(struct xntimer *timer)
Return the timer interval value.
Definition: timer.h:457
static void xntimer_stop(struct xntimer *timer)
Disarm a timer.
Definition: timer.h:483
int xntimer_grab_hardware(void)
Grab the hardware timer on all real-time CPUs.
Definition: timer.c:811