Xenomai  3.1
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_RUNNING 0x00000020
51 #define XNTIMER_KGRAVITY 0x00000040
52 #define XNTIMER_UGRAVITY 0x00000080
53 #define XNTIMER_IGRAVITY 0 /* most conservative */
54 
55 #define XNTIMER_GRAVITY_MASK (XNTIMER_KGRAVITY|XNTIMER_UGRAVITY)
56 #define XNTIMER_INIT_MASK XNTIMER_GRAVITY_MASK
57 
58 /* These flags are available to the real-time interfaces */
59 #define XNTIMER_SPARE0 0x01000000
60 #define XNTIMER_SPARE1 0x02000000
61 #define XNTIMER_SPARE2 0x04000000
62 #define XNTIMER_SPARE3 0x08000000
63 #define XNTIMER_SPARE4 0x10000000
64 #define XNTIMER_SPARE5 0x20000000
65 #define XNTIMER_SPARE6 0x40000000
66 #define XNTIMER_SPARE7 0x80000000
67 
68 /* Timer priorities */
69 #define XNTIMER_LOPRIO (-999999999)
70 #define XNTIMER_STDPRIO 0
71 #define XNTIMER_HIPRIO 999999999
72 
73 struct xntlholder {
74  struct list_head link;
75  xnticks_t key;
76  int prio;
77 };
78 
79 #define xntlholder_date(h) ((h)->key)
80 #define xntlholder_prio(h) ((h)->prio)
81 #define xntlist_init(q) INIT_LIST_HEAD(q)
82 #define xntlist_empty(q) list_empty(q)
83 
84 static inline struct xntlholder *xntlist_head(struct list_head *q)
85 {
86  if (list_empty(q))
87  return NULL;
88 
89  return list_first_entry(q, struct xntlholder, link);
90 }
91 
92 static inline struct xntlholder *xntlist_next(struct list_head *q,
93  struct xntlholder *h)
94 {
95  if (list_is_last(&h->link, q))
96  return NULL;
97 
98  return list_entry(h->link.next, struct xntlholder, link);
99 }
100 
101 static inline struct xntlholder *xntlist_second(struct list_head *q,
102  struct xntlholder *h)
103 {
104  return xntlist_next(q, h);
105 }
106 
107 static inline void xntlist_insert(struct list_head *q, struct xntlholder *holder)
108 {
109  struct xntlholder *p;
110 
111  if (list_empty(q)) {
112  list_add(&holder->link, q);
113  return;
114  }
115 
116  /*
117  * Insert the new timer at the proper place in the single
118  * queue. O(N) here, but this is the price for the increased
119  * flexibility...
120  */
121  list_for_each_entry_reverse(p, q, link) {
122  if ((xnsticks_t) (holder->key - p->key) > 0 ||
123  (holder->key == p->key && holder->prio <= p->prio))
124  break;
125  }
126 
127  list_add(&holder->link, &p->link);
128 }
129 
130 #define xntlist_remove(q, h) \
131  do { \
132  (void)(q); \
133  list_del(&(h)->link); \
134  } while (0)
135 
136 #if defined(CONFIG_XENO_OPT_TIMER_RBTREE)
137 
138 #include <linux/rbtree.h>
139 
140 typedef struct {
141  unsigned long long date;
142  unsigned prio;
143  struct rb_node link;
144 } xntimerh_t;
145 
146 #define xntimerh_date(h) ((h)->date)
147 #define xntimerh_prio(h) ((h)->prio)
148 #define xntimerh_init(h) do { } while (0)
149 
150 typedef struct {
151  struct rb_root root;
152  xntimerh_t *head;
153 } xntimerq_t;
154 
155 #define xntimerq_init(q) \
156  ({ \
157  xntimerq_t *_q = (q); \
158  _q->root = RB_ROOT; \
159  _q->head = NULL; \
160  })
161 
162 #define xntimerq_destroy(q) do { } while (0)
163 #define xntimerq_empty(q) ((q)->head == NULL)
164 
165 #define xntimerq_head(q) ((q)->head)
166 
167 #define xntimerq_next(q, h) \
168  ({ \
169  struct rb_node *_node = rb_next(&(h)->link); \
170  _node ? (container_of(_node, xntimerh_t, link)) : NULL; \
171  })
172 
173 #define xntimerq_second(q, h) xntimerq_next(q, h)
174 
175 void xntimerq_insert(xntimerq_t *q, xntimerh_t *holder);
176 
177 static inline void xntimerq_remove(xntimerq_t *q, xntimerh_t *holder)
178 {
179  if (holder == q->head)
180  q->head = xntimerq_second(q, holder);
181 
182  rb_erase(&holder->link, &q->root);
183 }
184 
185 typedef struct { } xntimerq_it_t;
186 
187 #define xntimerq_it_begin(q,i) ((void) (i), xntimerq_head(q))
188 #define xntimerq_it_next(q,i,h) ((void) (i), xntimerq_next((q),(h)))
189 
190 #else /* CONFIG_XENO_OPT_TIMER_LIST */
191 
192 typedef struct xntlholder xntimerh_t;
193 
194 #define xntimerh_date(h) xntlholder_date(h)
195 #define xntimerh_prio(h) xntlholder_prio(h)
196 #define xntimerh_init(h) do { } while (0)
197 
198 typedef struct list_head xntimerq_t;
199 
200 #define xntimerq_init(q) xntlist_init(q)
201 #define xntimerq_destroy(q) do { } while (0)
202 #define xntimerq_empty(q) xntlist_empty(q)
203 #define xntimerq_head(q) xntlist_head(q)
204 #define xntimerq_second(q, h) xntlist_second((q),(h))
205 #define xntimerq_insert(q, h) xntlist_insert((q),(h))
206 #define xntimerq_remove(q, h) xntlist_remove((q),(h))
207 
208 typedef struct { } xntimerq_it_t;
209 
210 #define xntimerq_it_begin(q,i) ((void) (i), xntlist_head(q))
211 #define xntimerq_it_next(q,i,h) ((void) (i), xntlist_next((q),(h)))
212 
213 #endif /* CONFIG_XENO_OPT_TIMER_LIST */
214 
215 struct xnsched;
216 
217 struct xntimerdata {
218  xntimerq_t q;
219 };
220 
221 static inline struct xntimerdata *
222 xnclock_percpu_timerdata(struct xnclock *clock, int cpu)
223 {
224  return per_cpu_ptr(clock->timerdata, cpu);
225 }
226 
227 static inline struct xntimerdata *
228 xnclock_this_timerdata(struct xnclock *clock)
229 {
230  return raw_cpu_ptr(clock->timerdata);
231 }
232 
233 struct xntimer {
234 #ifdef CONFIG_XENO_OPT_EXTCLOCK
235  struct xnclock *clock;
236 #endif
237 
238  xntimerh_t aplink;
239  struct list_head adjlink;
241  unsigned long status;
243  xnticks_t interval;
245  xnticks_t interval_ns;
247  xnticks_t periodic_ticks;
249  xnticks_t start_date;
251  xnticks_t pexpect_ticks;
253  struct xnsched *sched;
255  void (*handler)(struct xntimer *timer);
256 #ifdef CONFIG_XENO_OPT_STATS
257 #ifdef CONFIG_XENO_OPT_EXTCLOCK
258  struct xnclock *tracker;
259 #endif
260 
261  char name[XNOBJECT_NAME_LEN];
263  struct list_head next_stat;
265  xnstat_counter_t scheduled;
267  xnstat_counter_t fired;
268 #endif /* CONFIG_XENO_OPT_STATS */
269 };
270 
271 #ifdef CONFIG_XENO_OPT_EXTCLOCK
272 
273 static inline struct xnclock *xntimer_clock(struct xntimer *timer)
274 {
275  return timer->clock;
276 }
277 
278 void xntimer_set_clock(struct xntimer *timer,
279  struct xnclock *newclock);
280 
281 #else /* !CONFIG_XENO_OPT_EXTCLOCK */
282 
283 static inline struct xnclock *xntimer_clock(struct xntimer *timer)
284 {
285  return &nkclock;
286 }
287 
288 static inline void xntimer_set_clock(struct xntimer *timer,
289  struct xnclock *newclock)
290 {
291  XENO_BUG_ON(COBALT, newclock != &nkclock);
292 }
293 
294 #endif /* !CONFIG_XENO_OPT_EXTCLOCK */
295 
296 #ifdef CONFIG_SMP
297 static inline struct xnsched *xntimer_sched(struct xntimer *timer)
298 {
299  return timer->sched;
300 }
301 #else /* !CONFIG_SMP */
302 #define xntimer_sched(t) xnsched_current()
303 #endif /* !CONFIG_SMP */
304 
305 #define xntimer_percpu_queue(__timer) \
306  ({ \
307  struct xntimerdata *tmd; \
308  int cpu = xnsched_cpu((__timer)->sched); \
309  tmd = xnclock_percpu_timerdata(xntimer_clock(__timer), cpu); \
310  &tmd->q; \
311  })
312 
313 static inline unsigned long xntimer_gravity(struct xntimer *timer)
314 {
315  struct xnclock *clock = xntimer_clock(timer);
316 
317  if (timer->status & XNTIMER_KGRAVITY)
318  return clock->gravity.kernel;
319 
320  if (timer->status & XNTIMER_UGRAVITY)
321  return clock->gravity.user;
322 
323  return clock->gravity.irq;
324 }
325 
326 static inline void xntimer_update_date(struct xntimer *timer)
327 {
328  xntimerh_date(&timer->aplink) = timer->start_date
329  + xnclock_ns_to_ticks(xntimer_clock(timer),
330  timer->periodic_ticks * timer->interval_ns)
331  - xntimer_gravity(timer);
332 }
333 
334 static inline xnticks_t xntimer_pexpect(struct xntimer *timer)
335 {
336  return timer->start_date +
337  xnclock_ns_to_ticks(xntimer_clock(timer),
338  timer->pexpect_ticks * timer->interval_ns);
339 }
340 
341 static inline void xntimer_set_priority(struct xntimer *timer,
342  int prio)
343 {
344  xntimerh_prio(&timer->aplink) = prio;
345 }
346 
347 static inline int xntimer_active_p(struct xntimer *timer)
348 {
349  return timer->sched != NULL;
350 }
351 
352 static inline int xntimer_running_p(struct xntimer *timer)
353 {
354  return (timer->status & XNTIMER_RUNNING) != 0;
355 }
356 
357 static inline int xntimer_fired_p(struct xntimer *timer)
358 {
359  return (timer->status & XNTIMER_FIRED) != 0;
360 }
361 
362 static inline int xntimer_periodic_p(struct xntimer *timer)
363 {
364  return (timer->status & XNTIMER_PERIODIC) != 0;
365 }
366 
367 void __xntimer_init(struct xntimer *timer,
368  struct xnclock *clock,
369  void (*handler)(struct xntimer *timer),
370  struct xnsched *sched,
371  int flags);
372 
373 void xntimer_set_gravity(struct xntimer *timer,
374  int gravity);
375 
376 #ifdef CONFIG_XENO_OPT_STATS
377 
378 #define xntimer_init(__timer, __clock, __handler, __sched, __flags) \
379 do { \
380  __xntimer_init(__timer, __clock, __handler, __sched, __flags); \
381  xntimer_set_name(__timer, #__handler); \
382 } while (0)
383 
384 static inline void xntimer_reset_stats(struct xntimer *timer)
385 {
386  xnstat_counter_set(&timer->scheduled, 0);
387  xnstat_counter_set(&timer->fired, 0);
388 }
389 
390 static inline void xntimer_account_scheduled(struct xntimer *timer)
391 {
392  xnstat_counter_inc(&timer->scheduled);
393 }
394 
395 static inline void xntimer_account_fired(struct xntimer *timer)
396 {
397  xnstat_counter_inc(&timer->fired);
398 }
399 
400 static inline void xntimer_set_name(struct xntimer *timer, const char *name)
401 {
402  knamecpy(timer->name, name);
403 }
404 
405 #else /* !CONFIG_XENO_OPT_STATS */
406 
407 #define xntimer_init __xntimer_init
408 
409 static inline void xntimer_reset_stats(struct xntimer *timer) { }
410 
411 static inline void xntimer_account_scheduled(struct xntimer *timer) { }
412 
413 static inline void xntimer_account_fired(struct xntimer *timer) { }
414 
415 static inline void xntimer_set_name(struct xntimer *timer, const char *name) { }
416 
417 #endif /* !CONFIG_XENO_OPT_STATS */
418 
419 #if defined(CONFIG_XENO_OPT_EXTCLOCK) && defined(CONFIG_XENO_OPT_STATS)
420 void xntimer_switch_tracking(struct xntimer *timer,
421  struct xnclock *newclock);
422 #else
423 static inline
424 void xntimer_switch_tracking(struct xntimer *timer,
425  struct xnclock *newclock) { }
426 #endif
427 
428 void xntimer_destroy(struct xntimer *timer);
429 
445 static inline xnticks_t xntimer_interval(struct xntimer *timer)
446 {
447  return timer->interval_ns;
448 }
449 
450 static inline xnticks_t xntimer_expiry(struct xntimer *timer)
451 {
452  /* Real expiry date in ticks without anticipation (no gravity) */
453  return xntimerh_date(&timer->aplink) + xntimer_gravity(timer);
454 }
455 
456 int xntimer_start(struct xntimer *timer,
457  xnticks_t value,
458  xnticks_t interval,
459  xntmode_t mode);
460 
461 void __xntimer_stop(struct xntimer *timer);
462 
463 xnticks_t xntimer_get_date(struct xntimer *timer);
464 
465 xnticks_t __xntimer_get_timeout(struct xntimer *timer);
466 
467 xnticks_t xntimer_get_interval(struct xntimer *timer);
468 
469 int xntimer_heading_p(struct xntimer *timer);
470 
471 static inline void xntimer_stop(struct xntimer *timer)
472 {
473  if (timer->status & XNTIMER_RUNNING)
474  __xntimer_stop(timer);
475 }
476 
477 static inline xnticks_t xntimer_get_timeout(struct xntimer *timer)
478 {
479  if (!xntimer_running_p(timer))
480  return XN_INFINITE;
481 
482  return __xntimer_get_timeout(timer);
483 }
484 
485 static inline xnticks_t xntimer_get_timeout_stopped(struct xntimer *timer)
486 {
487  return __xntimer_get_timeout(timer);
488 }
489 
490 static inline void xntimer_enqueue(struct xntimer *timer,
491  xntimerq_t *q)
492 {
493  xntimerq_insert(q, &timer->aplink);
494  timer->status &= ~XNTIMER_DEQUEUED;
495  xntimer_account_scheduled(timer);
496 }
497 
498 static inline void xntimer_dequeue(struct xntimer *timer,
499  xntimerq_t *q)
500 {
501  xntimerq_remove(q, &timer->aplink);
502  timer->status |= XNTIMER_DEQUEUED;
503 }
504 
505 unsigned long long xntimer_get_overruns(struct xntimer *timer,
506  struct xnthread *waiter,
507  xnticks_t now);
508 
509 #ifdef CONFIG_SMP
510 
511 void __xntimer_migrate(struct xntimer *timer, struct xnsched *sched);
512 
513 static inline
514 void xntimer_migrate(struct xntimer *timer, struct xnsched *sched)
515 { /* nklocked, IRQs off */
516  if (timer->sched != sched)
517  __xntimer_migrate(timer, sched);
518 }
519 
520 int xntimer_setup_ipi(void);
521 
522 void xntimer_release_ipi(void);
523 
524 void __xntimer_set_affinity(struct xntimer *timer,
525  struct xnsched *sched);
526 
527 static inline void xntimer_set_affinity(struct xntimer *timer,
528  struct xnsched *sched)
529 {
530  if (sched != xntimer_sched(timer))
531  __xntimer_set_affinity(timer, sched);
532 }
533 
534 #else /* ! CONFIG_SMP */
535 
536 static inline void xntimer_migrate(struct xntimer *timer,
537  struct xnsched *sched)
538 {
539  timer->sched = 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 static inline void xntimer_set_affinity(struct xntimer *timer,
550  struct xnsched *sched)
551 {
552  xntimer_migrate(timer, sched);
553 }
554 
555 #endif /* CONFIG_SMP */
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:478
xnticks_t xntimer_get_date(struct xntimer *timer)
Return the absolute expiration date.
Definition: timer.c:245
void __xntimer_migrate(struct xntimer *timer, struct xnsched *sched)
Migrate a timer.
Definition: timer.c:503
Scheduling information structure.
Definition: sched.h:58
int xntimer_start(struct xntimer *timer, xnticks_t value, xnticks_t interval, xntmode_t mode)
Arm a timer.
Definition: timer.c:114
void xntimer_destroy(struct xntimer *timer)
Release a timer object.
Definition: timer.c:468
void xntimer_release_hardware(void)
Release hardware timers.
Definition: timer.c:942
static xnticks_t xntimer_interval(struct xntimer *timer)
Return the timer interval value.
Definition: timer.h:446
static void xntimer_stop(struct xntimer *timer)
Disarm a timer.
Definition: timer.h:472
int xntimer_grab_hardware(void)
Grab the hardware timer on all real-time CPUs.
Definition: timer.c:851
unsigned long long xntimer_get_overruns(struct xntimer *timer, struct xnthread *waiter, xnticks_t now)
Get the count of overruns for the last tick.
Definition: timer.c:622