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(laddr) \
00059     ((xntlholder_t *)(((char *)laddr) - offsetof(xntlholder_t, link)))
00060 
00061 } xntlholder_t;
00062 #define xntlholder_date(h)      ((h)->key)
00063 #define xntlholder_prio(h)      ((h)->prio)
00064 #define xntlholder_init(h)      inith(&(h)->link)
00065 #define xntlist_init(q)         initq(q)
00066 #define xntlist_head(q)                         \
00067     ({ xnholder_t *_h = getheadq(q);            \
00068         !_h ? NULL : link2tlholder(_h);         \
00069     })
00070 
00071 static inline void xntlist_insert(xnqueue_t *q, xntlholder_t *holder)
00072 {
00073     xnholder_t *p;
00074 
00075     /* Insert the new timer at the proper place in the single
00076        queue managed when running in aperiodic mode. O(N) here,
00077        but users of the aperiodic mode need to pay a price for
00078        the increased flexibility... */
00079 
00080     for (p = q->head.last; p != &q->head; p = p->last)
00081         if (holder->key > link2tlholder(p)->key ||
00082             (holder->key == link2tlholder(p)->key &&
00083              holder->prio <= link2tlholder(p)->prio))
00084             break;
00085 
00086     insertq(q,p->next,&holder->link);
00087 }
00088 
00089 #define xntlist_remove(q, h)  removeq((q),&(h)->link)
00090 
00091 #if defined(CONFIG_XENO_OPT_TIMER_HEAP)
00092 #include <nucleus/bheap.h>
00093 typedef bheaph_t xntimerh_t;
00094 #define xntimerh_date(h)       bheaph_key(h)
00095 #define xntimerh_prio(h)       bheaph_prio(h)
00096 #define xntimerh_init(h)       bheaph_init(h)
00097 typedef DECLARE_BHEAP_CONTAINER(xntimerq_t, CONFIG_XENO_OPT_TIMER_HEAP_CAPACITY);
00098 #define xntimerq_init(q)       bheap_init((q), CONFIG_XENO_OPT_TIMER_HEAP_CAPACITY)
00099 #define xntimerq_destroy(q)    bheap_destroy(q)
00100 #define xntimerq_head(q)       bheap_gethead(q)
00101 #define xntimerq_insert(q, h)  bheap_insert((q),(h))
00102 #define xntimerq_remove(q, h)  bheap_delete((q),(h))
00103 
00104 #elif defined(CONFIG_XENO_OPT_TIMER_WHEEL)
00105 typedef xntlholder_t xntimerh_t;
00106 #define xntimerh_date(h)       xntlholder_date(h)
00107 #define xntimerh_prio(h)       xntlholder_prio(h)
00108 #define xntimerh_init(h)       xntlholder_init(h)
00109 typedef struct {
00110         unsigned date_shift;
00111         unsigned long long next_shot;
00112         unsigned long long shot_wrap;
00113         xnqueue_t bucket[XNTIMER_WHEELSIZE];
00114 } xntimerq_t;
00115 
00116 static inline void xntimerq_init(xntimerq_t *q)
00117 {
00118         unsigned long long step_tsc;
00119         unsigned i;
00120 
00121         step_tsc = xnarch_ns_to_tsc(CONFIG_XENO_OPT_TIMER_WHEEL_STEP);
00122         /* q->date_shift = fls(step_tsc); */
00123         for (q->date_shift = 0; (1 << q->date_shift) < step_tsc; q->date_shift++)
00124                 ;
00125         q->next_shot = q->shot_wrap = ((~0ULL) >> q->date_shift) + 1;
00126         for (i = 0; i < sizeof(q->bucket)/sizeof(xnqueue_t); i++)
00127                 xntlist_init(&q->bucket[i]);
00128 }
00129 
00130 #define xntimerq_destroy(q)    do { } while (0)
00131 
00132 static inline xntlholder_t *xntimerq_head(xntimerq_t *q)
00133 {
00134         unsigned bucket = ((unsigned) q->next_shot) & XNTIMER_WHEELMASK;
00135         xntlholder_t *result;
00136         unsigned i;
00137 
00138         if (q->next_shot == q->shot_wrap)
00139                 return NULL;
00140 
00141         result = xntlist_head(&q->bucket[bucket]);
00142 
00143         if (result && (xntlholder_date(result) >> q->date_shift) == q->next_shot)
00144                 return result;
00145 
00146         /* We could not find the next timer in the first bucket, iterate over
00147            the other buckets. */
00148         for (i = (bucket + 1) & XNTIMER_WHEELMASK ;
00149              i != bucket; i = (i + 1) & XNTIMER_WHEELMASK) {
00150                 xntlholder_t *candidate = xntlist_head(&q->bucket[i]);
00151 
00152                 if(++q->next_shot == q->shot_wrap)
00153                         q->next_shot = 0;
00154 
00155                 if (!candidate)
00156                         continue;
00157 
00158                 if ((xntlholder_date(candidate) >> q->date_shift) == q->next_shot)
00159                         return candidate;
00160 
00161                 if (!result
00162                     || xntlholder_date(candidate) < xntlholder_date(result))
00163                         result = candidate;
00164         }
00165 
00166         if (result)
00167                 q->next_shot = (xntlholder_date(result) >> q->date_shift);
00168         else
00169                 q->next_shot = q->shot_wrap;
00170         return result;
00171 }
00172 
00173 static inline void xntimerq_insert(xntimerq_t *q, xntimerh_t *h)
00174 {
00175         unsigned long long shifted_date = xntlholder_date(h) >> q->date_shift;
00176         unsigned bucket = ((unsigned) shifted_date) & XNTIMER_WHEELMASK;
00177 
00178         if (shifted_date < q->next_shot)
00179                 q->next_shot = shifted_date;
00180         xntlist_insert(&q->bucket[bucket], h);
00181 }
00182 
00183 static inline void xntimerq_remove(xntimerq_t *q, xntimerh_t *h)
00184 {
00185         unsigned long long shifted_date = xntlholder_date(h) >> q->date_shift;
00186         unsigned bucket = ((unsigned) shifted_date) & XNTIMER_WHEELMASK;
00187 
00188         xntlist_remove(&q->bucket[bucket], h);
00189         /* Do not attempt to update q->next_shot, xntimerq_head will recover. */
00190 }
00191 
00192 #else /* CONFIG_XENO_OPT_TIMER_LIST */
00193 typedef xntlholder_t xntimerh_t;
00194 #define xntimerh_date(h)       xntlholder_date(h)
00195 #define xntimerh_prio(h)       xntlholder_prio(h)
00196 #define xntimerh_init(h)       xntlholder_init(h)
00197 typedef xnqueue_t xntimerq_t;
00198 #define xntimerq_init(q)       xntlist_init(q)
00199 #define xntimerq_destroy(q)    do { } while (0)
00200 #define xntimerq_head(q)       xntlist_head(q)
00201 #define xntimerq_insert(q,h)   xntlist_insert((q),(h))
00202 #define xntimerq_remove(q, h)  xntlist_remove((q),(h))
00203 
00204 #endif /* CONFIG_XENO_OPT_TIMER_LIST */
00205 
00206 struct xnsched;
00207 
00208 typedef struct xntimer {
00209 
00210     xntimerh_t aplink;          /* Link in aperiodic timers list. */
00211 
00212 #define aplink2timer(laddr) \
00213     ((xntimer_t *)(((char *)(laddr)) - (int)(&((xntimer_t *)0)->aplink)))
00214 
00215 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC
00216     xntlholder_t plink;         /* Link in periodic timers wheel. */
00217 
00218 #define plink2timer(laddr) \
00219     ((xntimer_t *)(((char *)(laddr)) - (int)(&((xntimer_t *)0)->plink)))
00220 #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC */
00221 
00222     xnflags_t status;           /* !< Timer status. */
00223 
00224     xnticks_t interval;         /* !< Periodic interval (in ticks, 0 == one shot). */
00225 
00226     struct xnsched *sched;      /* !< Sched structure to which the timer is
00227                                    attached. */
00228 
00229     void (*handler)(struct xntimer *timer); /* !< Timeout handler. */
00230 
00231     XNARCH_DECL_DISPLAY_CONTEXT();
00232 
00233 } xntimer_t;
00234 
00235 #if defined(CONFIG_SMP)
00236 #define xntimer_sched(t)          ((t)->sched)
00237 #else /* !CONFIG_SMP */
00238 #define xntimer_sched(t)          xnpod_current_sched()
00239 #endif /* !CONFIG_SMP */
00240 #define xntimer_interval(t)       ((t)->interval)
00241 #define xntimer_set_cookie(t,c)   ((t)->cookie = (c))
00242 
00243 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC
00244 #define xntimer_set_priority(t,p) ({                    \
00245             xntimer_t *_t = (t);                        \
00246             unsigned prio = (p);                        \
00247             xntimerh_prio(&(_t)->aplink) = prio;        \
00248             xntlholder_prio(&(_t)->plink) = prio;       \
00249         })
00250 #else /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
00251 #define xntimer_set_priority(t,p) (xntimerh_prio(&(t)->aplink) = (p))
00252 #endif /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
00253 
00254 static inline int xntimer_active_p (xntimer_t *timer)
00255 {
00256     return timer->sched != NULL;
00257 }
00258 
00259 static inline int xntimer_running_p (xntimer_t *timer)
00260 {
00261     return !testbits(timer->status,XNTIMER_DEQUEUED);
00262 }
00263 
00264 typedef struct xntmops {
00265 
00266     void (*do_tick)(void);
00267     xnticks_t (*get_jiffies)(void);
00268     xnticks_t (*get_raw_clock)(void);
00269     void (*do_timer_start)(xntimer_t *timer,
00270                            xnticks_t value,
00271                            xnticks_t interval);
00272     void (*do_timer_stop)(xntimer_t *timer);
00273     xnticks_t (*get_timer_date)(xntimer_t *timer);
00274     xnticks_t (*get_timer_timeout)(xntimer_t *timer);
00275     xnticks_t (*get_timer_interval)(xntimer_t *timer);
00276     xnticks_t (*get_timer_raw_expiry)(xntimer_t *timer);
00277     void (*set_timer_remote)(xntimer_t *timer);
00278     const char *(*get_type)(void);
00279     void (*freeze)(void);
00280 
00281 } xntmops_t;
00282 
00283 #ifdef __cplusplus
00284 extern "C" {
00285 #endif
00286 
00287 extern xntmops_t *nktimer;
00288 
00289 void xntimer_init(xntimer_t *timer,
00290                   void (*handler)(xntimer_t *timer));
00291 
00292 void xntimer_destroy(xntimer_t *timer);
00293 
00335 static inline void xntimer_start(xntimer_t *timer,
00336                                  xnticks_t value, xnticks_t interval)
00337 {
00338     nktimer->do_timer_start(timer, value, interval);
00339 }
00340 
00366 static inline void xntimer_stop(xntimer_t *timer)
00367 {
00368     /* Careful: the do_timer_stop() helper is expected to preserve the
00369        date field of the stopped timer, so that subsequent calls to
00370        xntimer_get_timeout() would still work on such timer as
00371        expected. */
00372     if (!testbits(timer->status,XNTIMER_DEQUEUED))
00373         nktimer->do_timer_stop(timer);
00374 }
00375 
00376 static inline xnticks_t xntimer_get_jiffies(void)
00377 {
00378 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC
00379     return nktimer->get_jiffies();
00380 #else /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
00381     return xnarch_get_cpu_time();
00382 #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC */
00383 }
00384 
00385 static inline xnticks_t xntimer_get_rawclock(void)
00386 {
00387 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC
00388     return nktimer->get_raw_clock();
00389 #else /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
00390     return xnarch_get_cpu_tsc();
00391 #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC */
00392 }
00393 
00394 static inline xnticks_t xntimer_get_raw_expiry (xntimer_t *timer)
00395 {
00396 #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC
00397     return nktimer->get_timer_raw_expiry(timer);
00398 #else /* !CONFIG_XENO_OPT_TIMING_PERIODIC */
00399     return xntimerh_date(&timer->aplink);
00400 #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC */
00401 }
00402 
00403 void xntimer_freeze(void);
00404 
00405 xnticks_t xntimer_get_date(xntimer_t *timer);
00406 
00407 xnticks_t xntimer_get_timeout(xntimer_t *timer);
00408 
00409 xnticks_t xntimer_get_interval(xntimer_t *timer);
00410 
00411 void xntimer_set_periodic_mode(void);
00412 
00413 void xntimer_set_aperiodic_mode(void);
00414 
00415 #if defined(CONFIG_SMP)
00416 int xntimer_set_sched(xntimer_t *timer, struct xnsched *sched);
00417 #else /* ! CONFIG_SMP */
00418 #define xntimer_set_sched(timer,sched)
00419 #endif /* CONFIG_SMP */
00420 
00421 #ifdef __cplusplus
00422 }
00423 #endif
00424 
00425 #endif /* __KERNEL__ || __XENO_SIM__ */
00426 
00427 #endif /* !_XENO_NUCLEUS_TIMER_H */

Generated on Mon Dec 25 13:57:10 2006 for Xenomai API by  doxygen 1.4.6