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