Xenomai  3.0.2
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 {
106  struct xntlholder *h;
107 
108  if (list_empty(q))
109  return NULL;
110 
111  h = list_first_entry(q, struct xntlholder, link);
112 
113  return xntlist_next(q, h);
114 }
115 
116 static inline void xntlist_insert(struct list_head *q, struct xntlholder *holder)
117 {
118  struct xntlholder *p;
119 
120  if (list_empty(q)) {
121  list_add(&holder->link, q);
122  return;
123  }
124 
125  /*
126  * Insert the new timer at the proper place in the single
127  * queue. O(N) here, but this is the price for the increased
128  * flexibility...
129  */
130  list_for_each_entry_reverse(p, q, link) {
131  if ((xnsticks_t) (holder->key - p->key) > 0 ||
132  (holder->key == p->key && holder->prio <= p->prio))
133  break;
134  }
135 
136  list_add(&holder->link, &p->link);
137 }
138 
139 #define xntlist_remove(q, h) \
140  do { \
141  (void)(q); \
142  list_del(&(h)->link); \
143  } while (0)
144 
145 #if defined(CONFIG_XENO_OPT_TIMER_HEAP)
146 
147 #include <cobalt/kernel/bheap.h>
148 
149 typedef bheaph_t xntimerh_t;
150 
151 #define xntimerh_date(h) bheaph_key(h)
152 #define xntimerh_prio(h) bheaph_prio(h)
153 #define xntimerh_init(h) bheaph_init(h)
154 
155 typedef DECLARE_BHEAP_CONTAINER(xntimerq_t, CONFIG_XENO_OPT_TIMER_HEAP_CAPACITY);
156 
157 #define xntimerq_init(q) bheap_init((q), CONFIG_XENO_OPT_TIMER_HEAP_CAPACITY)
158 #define xntimerq_destroy(q) bheap_destroy(q)
159 #define xntimerq_empty(q) bheap_empty(q)
160 #define xntimerq_head(q) bheap_gethead(q)
161 #define xntimerq_second(q) bheap_second(q)
162 #define xntimerq_insert(q, h) bheap_insert((q),(h))
163 #define xntimerq_remove(q, h) bheap_delete((q),(h))
164 
165 typedef struct {} xntimerq_it_t;
166 
167 /*
168  * BIG FAT WARNING: the iterator does NOT guarantee any particular
169  * order when returning elements (typically, items may be returned in
170  * random timestamp order).
171  */
172 #define xntimerq_it_begin(q, i) ((void) (i), bheap_gethead(q))
173 #define xntimerq_it_next(q, i, h) ((void) (i), bheap_next((q),(h)))
174 
175 #else /* CONFIG_XENO_OPT_TIMER_LIST */
176 
177 typedef struct xntlholder xntimerh_t;
178 
179 #define xntimerh_date(h) xntlholder_date(h)
180 #define xntimerh_prio(h) xntlholder_prio(h)
181 #define xntimerh_init(h) do { } while (0)
182 
183 typedef struct list_head xntimerq_t;
184 
185 #define xntimerq_init(q) xntlist_init(q)
186 #define xntimerq_destroy(q) do { } while (0)
187 #define xntimerq_empty(q) xntlist_empty(q)
188 #define xntimerq_head(q) xntlist_head(q)
189 #define xntimerq_second(q) xntlist_second(q)
190 #define xntimerq_insert(q, h) xntlist_insert((q),(h))
191 #define xntimerq_remove(q, h) xntlist_remove((q),(h))
192 
193 typedef struct { } xntimerq_it_t;
194 
195 #define xntimerq_it_begin(q,i) ((void) (i), xntlist_head(q))
196 #define xntimerq_it_next(q,i,h) ((void) (i), xntlist_next((q),(h)))
197 
198 #endif /* CONFIG_XENO_OPT_TIMER_LIST */
199 
200 struct xnsched;
201 
202 struct xntimerdata {
203  xntimerq_t q;
204 };
205 
206 static inline struct xntimerdata *
207 xnclock_percpu_timerdata(struct xnclock *clock, int cpu)
208 {
209  return per_cpu_ptr(clock->timerdata, cpu);
210 }
211 
212 static inline struct xntimerdata *
213 xnclock_this_timerdata(struct xnclock *clock)
214 {
215  return raw_cpu_ptr(clock->timerdata);
216 }
217 
218 struct xntimer {
219 #ifdef CONFIG_XENO_OPT_EXTCLOCK
220  struct xnclock *clock;
221 #endif
222 
223  xntimerh_t aplink;
224  struct list_head adjlink;
226  unsigned long status;
228  xnticks_t interval;
230  xnticks_t interval_ns;
232  xnticks_t periodic_ticks;
234  xnticks_t start_date;
236  xnticks_t pexpect_ticks;
238  struct xnsched *sched;
240  void (*handler)(struct xntimer *timer);
241 #ifdef CONFIG_XENO_OPT_STATS
242 #ifdef CONFIG_XENO_OPT_EXTCLOCK
243  struct xnclock *tracker;
244 #endif
245 
246  char name[XNOBJECT_NAME_LEN];
248  struct list_head next_stat;
250  xnstat_counter_t scheduled;
252  xnstat_counter_t fired;
253 #endif /* CONFIG_XENO_OPT_STATS */
254 };
255 
256 #ifdef CONFIG_XENO_OPT_EXTCLOCK
257 
258 static inline struct xnclock *xntimer_clock(struct xntimer *timer)
259 {
260  return timer->clock;
261 }
262 
263 void xntimer_set_clock(struct xntimer *timer,
264  struct xnclock *newclock);
265 
266 #else /* !CONFIG_XENO_OPT_EXTCLOCK */
267 
268 static inline struct xnclock *xntimer_clock(struct xntimer *timer)
269 {
270  return &nkclock;
271 }
272 
273 static inline void xntimer_set_clock(struct xntimer *timer,
274  struct xnclock *newclock)
275 {
276  XENO_BUG_ON(COBALT, newclock != &nkclock);
277 }
278 
279 #endif /* !CONFIG_XENO_OPT_EXTCLOCK */
280 
281 #ifdef CONFIG_SMP
282 static inline struct xnsched *xntimer_sched(struct xntimer *timer)
283 {
284  return timer->sched;
285 }
286 #else /* !CONFIG_SMP */
287 #define xntimer_sched(t) xnsched_current()
288 #endif /* !CONFIG_SMP */
289 
290 #define xntimer_percpu_queue(__timer) \
291  ({ \
292  struct xntimerdata *tmd; \
293  int cpu = xnsched_cpu((__timer)->sched); \
294  tmd = xnclock_percpu_timerdata(xntimer_clock(__timer), cpu); \
295  &tmd->q; \
296  })
297 
298 static inline xntimerq_t *xntimer_this_queue(struct xntimer *timer)
299 {
300  struct xntimerdata *tmd;
301 
302  tmd = xnclock_this_timerdata(xntimer_clock(timer));
303 
304  return &tmd->q;
305 }
306 
307 static inline unsigned long xntimer_gravity(struct xntimer *timer)
308 {
309  struct xnclock *clock = xntimer_clock(timer);
310 
311  if (timer->status & XNTIMER_KGRAVITY)
312  return clock->gravity.kernel;
313 
314  if (timer->status & XNTIMER_UGRAVITY)
315  return clock->gravity.user;
316 
317  return clock->gravity.irq;
318 }
319 
320 static inline void xntimer_update_date(struct xntimer *timer)
321 {
322  xntimerh_date(&timer->aplink) = timer->start_date
323  + xnclock_ns_to_ticks(xntimer_clock(timer),
324  timer->periodic_ticks * timer->interval_ns)
325  - xntimer_gravity(timer);
326 }
327 
328 static inline xnticks_t xntimer_pexpect(struct xntimer *timer)
329 {
330  return timer->start_date +
331  xnclock_ns_to_ticks(xntimer_clock(timer),
332  timer->pexpect_ticks * timer->interval_ns);
333 }
334 
335 static inline void xntimer_set_priority(struct xntimer *timer,
336  int prio)
337 {
338  xntimerh_prio(&timer->aplink) = prio;
339 }
340 
341 static inline int xntimer_active_p(struct xntimer *timer)
342 {
343  return timer->sched != NULL;
344 }
345 
346 static inline int xntimer_running_p(struct xntimer *timer)
347 {
348  return (timer->status & XNTIMER_RUNNING) != 0;
349 }
350 
351 static inline int xntimer_fired_p(struct xntimer *timer)
352 {
353  return (timer->status & XNTIMER_FIRED) != 0;
354 }
355 
356 static inline int xntimer_periodic_p(struct xntimer *timer)
357 {
358  return (timer->status & XNTIMER_PERIODIC) != 0;
359 }
360 
361 void __xntimer_init(struct xntimer *timer,
362  struct xnclock *clock,
363  void (*handler)(struct xntimer *timer),
364  struct xnsched *sched,
365  int flags);
366 
367 void xntimer_set_gravity(struct xntimer *timer,
368  int gravity);
369 
370 #ifdef CONFIG_XENO_OPT_STATS
371 
372 #define xntimer_init(__timer, __clock, __handler, __sched, __flags) \
373 do { \
374  __xntimer_init(__timer, __clock, __handler, __sched, __flags); \
375  xntimer_set_name(__timer, #__handler); \
376 } while (0)
377 
378 static inline void xntimer_reset_stats(struct xntimer *timer)
379 {
380  xnstat_counter_set(&timer->scheduled, 0);
381  xnstat_counter_set(&timer->fired, 0);
382 }
383 
384 static inline void xntimer_account_scheduled(struct xntimer *timer)
385 {
386  xnstat_counter_inc(&timer->scheduled);
387 }
388 
389 static inline void xntimer_account_fired(struct xntimer *timer)
390 {
391  xnstat_counter_inc(&timer->fired);
392 }
393 
394 static inline void xntimer_set_name(struct xntimer *timer, const char *name)
395 {
396  knamecpy(timer->name, name);
397 }
398 
399 #else /* !CONFIG_XENO_OPT_STATS */
400 
401 #define xntimer_init __xntimer_init
402 
403 static inline void xntimer_reset_stats(struct xntimer *timer) { }
404 
405 static inline void xntimer_account_scheduled(struct xntimer *timer) { }
406 
407 static inline void xntimer_account_fired(struct xntimer *timer) { }
408 
409 static inline void xntimer_set_name(struct xntimer *timer, const char *name) { }
410 
411 #endif /* !CONFIG_XENO_OPT_STATS */
412 
413 #if defined(CONFIG_XENO_OPT_EXTCLOCK) && defined(CONFIG_XENO_OPT_STATS)
414 void xntimer_switch_tracking(struct xntimer *timer,
415  struct xnclock *newclock);
416 #else
417 static inline
418 void xntimer_switch_tracking(struct xntimer *timer,
419  struct xnclock *newclock) { }
420 #endif
421 
422 void xntimer_destroy(struct xntimer *timer);
423 
439 static inline xnticks_t xntimer_interval(struct xntimer *timer)
440 {
441  return timer->interval_ns;
442 }
443 
444 static inline xnticks_t xntimer_expiry(struct xntimer *timer)
445 {
446  /* Real expiry date in ticks without anticipation (no gravity) */
447  return xntimerh_date(&timer->aplink) + xntimer_gravity(timer);
448 }
449 
450 int xntimer_start(struct xntimer *timer,
451  xnticks_t value,
452  xnticks_t interval,
453  xntmode_t mode);
454 
455 void __xntimer_stop(struct xntimer *timer);
456 
457 xnticks_t xntimer_get_date(struct xntimer *timer);
458 
459 xnticks_t xntimer_get_timeout(struct xntimer *timer);
460 
461 xnticks_t xntimer_get_interval(struct xntimer *timer);
462 
463 int xntimer_heading_p(struct xntimer *timer);
464 
465 static inline void xntimer_stop(struct xntimer *timer)
466 {
467  if (timer->status & XNTIMER_RUNNING)
468  __xntimer_stop(timer);
469 }
470 
471 static inline xnticks_t xntimer_get_timeout_stopped(struct xntimer *timer)
472 {
473  return xntimer_get_timeout(timer);
474 }
475 
476 static inline void xntimer_enqueue(struct xntimer *timer,
477  xntimerq_t *q)
478 {
479  xntimerq_insert(q, &timer->aplink);
480  timer->status &= ~XNTIMER_DEQUEUED;
481  xntimer_account_scheduled(timer);
482 }
483 
484 static inline void xntimer_dequeue(struct xntimer *timer,
485  xntimerq_t *q)
486 {
487  xntimerq_remove(q, &timer->aplink);
488  timer->status |= XNTIMER_DEQUEUED;
489 }
490 
493 unsigned long long xntimer_get_overruns(struct xntimer *timer, xnticks_t now);
494 
495 #ifdef CONFIG_SMP
496 
497 void __xntimer_migrate(struct xntimer *timer, struct xnsched *sched);
498 
499 static inline
500 void xntimer_migrate(struct xntimer *timer, struct xnsched *sched)
501 { /* nklocked, IRQs off */
502  if (timer->sched != sched)
503  __xntimer_migrate(timer, sched);
504 }
505 
506 int xntimer_setup_ipi(void);
507 
508 void xntimer_release_ipi(void);
509 
510 #else /* ! CONFIG_SMP */
511 
512 static inline void xntimer_migrate(struct xntimer *timer,
513  struct xnsched *sched)
514 { }
515 
516 static inline int xntimer_setup_ipi(void)
517 {
518  return 0;
519 }
520 
521 static inline void xntimer_release_ipi(void) { }
522 
523 #endif /* CONFIG_SMP */
524 
525 static inline void xntimer_set_sched(struct xntimer *timer,
526  struct xnsched *sched)
527 {
528  xntimer_migrate(timer, sched);
529 }
530 
531 char *xntimer_format_time(xnticks_t ns,
532  char *buf, size_t bufsz);
533 
534 int xntimer_grab_hardware(void);
535 
536 void xntimer_release_hardware(void);
537 
540 #endif /* !_COBALT_KERNEL_TIMER_H */
xnticks_t xntimer_get_timeout(struct xntimer *timer)
Return the relative expiration date.
Definition: timer.c:269
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:528
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:494
unsigned long long xntimer_get_overruns(struct xntimer *timer, xnticks_t now)
Get the count of overruns for the last tick.
Definition: timer.c:593
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:439
static void xntimer_stop(struct xntimer *timer)
Disarm a timer.
Definition: timer.h:465
int xntimer_grab_hardware(void)
Grab the hardware timer on all real-time CPUs.
Definition: timer.c:811