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