include/nucleus/timer.h

00001 /*
00002  * Copyright (C) 2001,2002,2003 Philippe Gerum <rpm@xenomai.org>.
00003  *
00004  * Xenomai is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published
00006  * by the Free Software Foundation; either version 2 of the License,
00007  * or (at your option) any later version.
00008  *
00009  * Xenomai is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with Xenomai; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00017  * 02111-1307, USA.
00018  */
00019 
00020 #ifndef _XENO_NUCLEUS_TIMER_H
00021 #define _XENO_NUCLEUS_TIMER_H
00022 
00023 #include <nucleus/queue.h>
00024 
00025 #if defined(__KERNEL__) || defined(__XENO_SIM__)
00026 
00027 #if defined(CONFIG_XENO_OPT_TIMING_PERIODIC) \
00028         || defined(CONFIG_XENO_OPT_TIMER_WHEEL)
00029 /* Number of outstanding timers (hint only) -- must be ^2 */
00030 #define XNTIMER_WHEELSIZE 64
00031 #define XNTIMER_WHEELMASK (XNTIMER_WHEELSIZE - 1)
00032 #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC || CONFIG_XENO_OPT_TIMER_WHEEL */
00033 
00034 #define XNTIMER_DEQUEUED  0x00000001
00035 #define XNTIMER_KILLED    0x00000002
00036 
00037 /* These flags are available to the real-time interfaces */
00038 #define XNTIMER_SPARE0  0x01000000
00039 #define XNTIMER_SPARE1  0x02000000
00040 #define XNTIMER_SPARE2  0x04000000
00041 #define XNTIMER_SPARE3  0x08000000
00042 #define XNTIMER_SPARE4  0x10000000
00043 #define XNTIMER_SPARE5  0x20000000
00044 #define XNTIMER_SPARE6  0x40000000
00045 #define XNTIMER_SPARE7  0x80000000
00046 
00047 #define XNTIMER_LOPRIO  (-999999999)
00048 #define XNTIMER_STDPRIO 0
00049 #define XNTIMER_HIPRIO  999999999
00050 
00051 #define XNTIMER_KEEPER_ID 0
00052 
00053 typedef struct {
00054     xnholder_t link;
00055     xnticks_t key;
00056     int prio;
00057 
00058 #define link2tlholder(ln)       container_of(ln, xntlholder_t, link)
00059 
00060 } xntlholder_t;
00061 #define xntlholder_date(h)      ((h)->key)
00062 #define xntlholder_prio(h)      ((h)->prio)
00063 #define xntlholder_init(h)      inith(&(h)->link)
00064 #define xntlist_init(q)         initq(q)
00065 #define xntlist_head(q)                         \
00066     ({ xnholder_t *_h = getheadq(q);            \
00067         !_h ? NULL : link2tlholder(_h);         \
00068     })
00069 
00070 static inline void xntlist_insert(xnqueue_t *q, xntlholder_t *holder)
00071 {
00072     xnholder_t *p;
00073 
00074     /* Insert the new timer at the proper place in the single
00075        queue managed when running in aperiodic mode. O(N) here,
00076        but users of the aperiodic mode need to pay a price for
00077        the increased flexibility... */
00078 
00079     for (p = q->head.last; p != &q->head; p = p->last)
00080         if (holder->key > link2tlholder(p)->key ||
00081             (holder->key == link2tlholder(p)->key &&
00082              holder->prio <= link2tlholder(p)->prio))
00083             break;
00084 
00085     insertq(q,p->next,&holder->link);
00086 }
00087 
00088 #define xntlist_remove(q, h)  removeq((q),&(h)->link)
00089 
00090 #if defined(CONFIG_XENO_OPT_TIMER_HEAP)
00091 #include <nucleus/bheap.h>
00092 typedef bheaph_t xntimerh_t;
00093 #define xntimerh_date(h)       bheaph_key(h)
00094 #define xntimerh_prio(h)       bheaph_prio(h)
00095 #define xntimerh_init(h)       bheaph_init(h)
00096 typedef DECLARE_BHEAP_CONTAINER(xntimerq_t, CONFIG_XENO_OPT_TIMER_HEAP_CAPACITY);
00097 #define xntimerq_init(q)       bheap_init((q), CONFIG_XENO_OPT_TIMER_HEAP_CAPACITY)
00098 #define xntimerq_destroy(q)    bheap_destroy(q)
00099 #define xntimerq_head(q)       bheap_gethead(q)
00100 #define xntimerq_insert(q, h)  bheap_insert((q),(h))
00101 #define xntimerq_remove(q, h)  bheap_delete((q),(h))
00102 
00103 #elif defined(CONFIG_XENO_OPT_TIMER_WHEEL)
00104 typedef xntlholder_t xntimerh_t;
00105 #define xntimerh_date(h)       xntlholder_date(h)
00106 #define xntimerh_prio(h)       xntlholder_prio(h)
00107 #define xntimerh_init(h)       xntlholder_init(h)
00108 typedef struct {
00109         unsigned date_shift;
00110         unsigned long long next_shot;
00111         unsigned long long shot_wrap;
00112         xnqueue_t bucket[XNTIMER_WHEELSIZE];
00113 } xntimerq_t;
00114 
00115 static inline void xntimerq_init(xntimerq_t *q)
00116 {
00117         unsigned long long step_tsc;
00118         unsigned i;
00119 
00120         step_tsc = xnarch_ns_to_tsc(CONFIG_XENO_OPT_TIMER_WHEEL_STEP);
00121         /* q->date_shift = fls(step_tsc); */
00122         for (q->date_shift = 0; (1 << q->date_shift) < step_tsc; q->date_shift++)
00123                 ;
00124         q->next_shot = q->shot_wrap = ((~0ULL) >> q->date_shift) + 1;
00125         for (i = 0; i < sizeof(q->bucket)/sizeof(xnqueue_t); i++)
00126                 xntlist_init(&q->bucket[i]);
00127 }
00128 
00129 #define xntimerq_destroy(q)    do { } while (0)
00130 
00131 static inline xntlholder_t *xntimerq_head(xntimerq_t *q)
00132 {
00133         unsigned bucket = ((unsigned) q->next_shot) & XNTIMER_WHEELMASK;
00134         xntlholder_t *result;
00135         unsigned i;
00136 
00137         if (q->next_shot == q->shot_wrap)
00138                 return NULL;
00139 
00140         result = xntlist_head(&q->bucket[bucket]);
00141 
00142         if (result && (xntlholder_date(result) >> q->date_shift) == q->next_shot)
00143                 return result;
00144 
00145         /* We could not find the next timer in the first bucket, iterate over
00146            the other buckets. */
00147         for (i = (bucket + 1) & XNTIMER_WHEELMASK ;
00148              i != bucket; i = (i + 1) & XNTIMER_WHEELMASK) {
00149                 xntlholder_t *candidate = xntlist_head(&q->bucket[i]);
00150 
00151                 if(++q->next_shot == q->shot_wrap)
00152                         q->next_shot = 0;
00153 
00154                 if (!candidate)
00155                         continue;
00156 
00157                 if ((xntlholder_date(candidate) >> q->date_shift) == q->next_shot)
00158                         return candidate;
00159 
00160                 if (!result
00161                     || xntlholder_date(candidate) < xntlholder_date(result))
00162                         result = candidate;
00163         }
00164 
00165         if (result)
00166                 q->next_shot = (xntlholder_date(result) >> q->date_shift);
00167         else
00168                 q->next_shot = q->shot_wrap;
00169         return result;
00170 }
00171 
00172 static inline void xntimerq_insert(xntimerq_t *q, xntimerh_t *h)
00173 {
00174         unsigned long long shifted_date = xntlholder_date(h) >> q->date_shift;
00175         unsigned bucket = ((unsigned) shifted_date) & XNTIMER_WHEELMASK;
00176 
00177         if (shifted_date < q->next_shot)
00178                 q->next_shot = shifted_date;
00179         xntlist_insert(&q->bucket[bucket], h);
00180 }
00181 
00182 static inline void xntimerq_remove(xntimerq_t *q, xntimerh_t *h)
00183 {
00184         unsigned long long shifted_date = xntlholder_date(h) >> q->date_shift;
00185         unsigned bucket = ((unsigned) shifted_date) & XNTIMER_WHEELMASK;
00186 
00187         xntlist_remove(&q->bucket[bucket], h);
00188         /* Do not attempt to update q->next_shot, xntimerq_head will recover. */
00189 }
00190 
00191 #else /* CONFIG_XENO_OPT_TIMER_LIST */
00192 typedef xntlholder_t xntimerh_t;
00193 #define xntimerh_date(h)       xntlholder_date(h)
00194 #define xntimerh_prio(h)       xntlholder_prio(h)
00195 #define xntimerh_init(h)       xntlholder_init(h)
00196 typedef xnqueue_t xntimerq_t;
00197 #define xntimerq_init(q)       xntlist_init(q)
00198 #define xntimerq_destroy(q)    do { } while (0)
00199 #define xntimerq_head(q)       xntlist_head(q)
00200 #define xntimerq_insert(q,h)   xntlist_insert((q),(h))
00201 #define xntimerq_remove(q, h)  xntlist_remove((q),(h))
00202 
00203 #endif /* CONFIG_XENO_OPT_TIMER_LIST */
00204 
00205 struct xnsched;
00206 
00207 typedef struct xntimer {
00208 
00209     xntimerh_t aplink;          /* Link in aperiodic timers list. */
00210 
00211 #define aplink2timer(ln) container_of(ln, xntimer_t, aplink)
00212 
00213 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC
00214     xntlholder_t plink;         /* Link in periodic timers wheel. */
00215 
00216 #define plink2timer(ln) container_of(ln, xntimer_t, plink)
00217 #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC */
00218 
00219     xnflags_t status;           /* !< Timer status. */
00220 
00221     xnticks_t interval;         /* !< Periodic interval (in ticks, 0 == one shot). */
00222 
00223     struct xnsched *sched;      /* !< Sched structure to which the timer is
00224                                    attached. */
00225 
00226     void (*handler)(struct xntimer *timer); /* !< Timeout handler. */
00227 
00228     XNARCH_DECL_DISPLAY_CONTEXT();
00229 
00230 } xntimer_t;
00231 
00232 #if defined(CONFIG_SMP)
00233 #define xntimer_sched(t)          ((t)->sched)
00234 #else /* !CONFIG_SMP */
00235 #define xntimer_sched(t)          xnpod_current_sched()
00236 #endif /* !CONFIG_SMP */
00237 #define xntimer_interval(t)       ((t)->interval)
00238 #define xntimer_set_cookie(t,c)   ((t)->cookie = (c))
00239 
00240 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC
00241 #define xntimer_set_priority(t,p) ({                    \
00242             xntimer_t *_t = (t);                        \
00243             unsigned prio = (p);                        \
00244             xntimerh_prio(&(_t)->aplink) = prio;        \
00245             xntlholder_prio(&(_t)->plink) = prio;       \
00246         })
00247 #else /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
00248 #define xntimer_set_priority(t,p) (xntimerh_prio(&(t)->aplink) = (p))
00249 #endif /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
00250 
00251 static inline int xntimer_active_p (xntimer_t *timer)
00252 {
00253     return timer->sched != NULL;
00254 }
00255 
00256 static inline int xntimer_running_p (xntimer_t *timer)
00257 {
00258     return !testbits(timer->status,XNTIMER_DEQUEUED);
00259 }
00260 
00261 typedef struct xntmops {
00262 
00263     void (*do_tick)(void);
00264     xnticks_t (*get_jiffies)(void);
00265     xnticks_t (*get_raw_clock)(void);
00266     void (*do_timer_start)(xntimer_t *timer,
00267                            xnticks_t value,
00268                            xnticks_t interval);
00269     void (*do_timer_stop)(xntimer_t *timer);
00270     xnticks_t (*get_timer_date)(xntimer_t *timer);
00271     xnticks_t (*get_timer_timeout)(xntimer_t *timer);
00272     xnticks_t (*get_timer_interval)(xntimer_t *timer);
00273     xnticks_t (*get_timer_raw_expiry)(xntimer_t *timer);
00274     void (*set_timer_remote)(xntimer_t *timer);
00275     const char *(*get_type)(void);
00276     void (*freeze)(void);
00277 
00278 } xntmops_t;
00279 
00280 #ifdef __cplusplus
00281 extern "C" {
00282 #endif
00283 
00284 extern xntmops_t *nktimer;
00285 
00286 void xntimer_init(xntimer_t *timer,
00287                   void (*handler)(xntimer_t *timer));
00288 
00289 void xntimer_destroy(xntimer_t *timer);
00290 
00332 static inline void xntimer_start(xntimer_t *timer,
00333                                  xnticks_t value, xnticks_t interval)
00334 {
00335     nktimer->do_timer_start(timer, value, interval);
00336 }
00337 
00363 static inline void xntimer_stop(xntimer_t *timer)
00364 {
00365     /* Careful: the do_timer_stop() helper is expected to preserve the
00366        date field of the stopped timer, so that subsequent calls to
00367        xntimer_get_timeout() would still work on such timer as
00368        expected. */
00369     if (!testbits(timer->status,XNTIMER_DEQUEUED))
00370         nktimer->do_timer_stop(timer);
00371 }
00372 
00373 static inline xnticks_t xntimer_get_jiffies(void)
00374 {
00375 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC
00376     return nktimer->get_jiffies();
00377 #else /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
00378     return xnarch_get_cpu_time();
00379 #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC */
00380 }
00381 
00382 static inline xnticks_t xntimer_get_rawclock(void)
00383 {
00384 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC
00385     return nktimer->get_raw_clock();
00386 #else /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
00387     return xnarch_get_cpu_tsc();
00388 #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC */
00389 }
00390 
00391 static inline xnticks_t xntimer_get_raw_expiry (xntimer_t *timer)
00392 {
00393 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC
00394     return nktimer->get_timer_raw_expiry(timer);
00395 #else /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
00396     return xntimerh_date(&timer->aplink);
00397 #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC */
00398 }
00399 
00400 void xntimer_freeze(void);
00401 
00402 xnticks_t xntimer_get_date(xntimer_t *timer);
00403 
00404 xnticks_t xntimer_get_timeout(xntimer_t *timer);
00405 
00406 xnticks_t xntimer_get_interval(xntimer_t *timer);
00407 
00408 void xntimer_set_periodic_mode(void);
00409 
00410 void xntimer_set_aperiodic_mode(void);
00411 
00412 #if defined(CONFIG_SMP)
00413 int xntimer_set_sched(xntimer_t *timer, struct xnsched *sched);
00414 #else /* ! CONFIG_SMP */
00415 #define xntimer_set_sched(timer,sched)
00416 #endif /* CONFIG_SMP */
00417 
00418 #ifdef __cplusplus
00419 }
00420 #endif
00421 
00422 #endif /* __KERNEL__ || __XENO_SIM__ */
00423 
00424 #endif /* !_XENO_NUCLEUS_TIMER_H */

Generated on Sun Dec 9 10:37:17 2007 for Xenomai API by  doxygen 1.5.3