timers: Framework for identifying pinned timers
[safe/jmp/linux-2.6] / include / linux / hrtimer.h
index 1ad56a7..7400900 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/wait.h>
+#include <linux/percpu.h>
+
 
 struct hrtimer_clock_base;
 struct hrtimer_cpu_base;
@@ -28,8 +30,11 @@ struct hrtimer_cpu_base;
  * Mode arguments of xxx_hrtimer functions:
  */
 enum hrtimer_mode {
-       HRTIMER_MODE_ABS,       /* Time value is absolute */
-       HRTIMER_MODE_REL,       /* Time value is relative to now */
+       HRTIMER_MODE_ABS = 0x0,         /* Time value is absolute */
+       HRTIMER_MODE_REL = 0x1,         /* Time value is relative to now */
+       HRTIMER_MODE_PINNED = 0x02,     /* Timer is bound to CPU */
+       HRTIMER_MODE_ABS_PINNED = 0x02,
+       HRTIMER_MODE_REL_PINNED = 0x03,
 };
 
 /*
@@ -41,23 +46,6 @@ enum hrtimer_restart {
 };
 
 /*
- * hrtimer callback modes:
- *
- *     HRTIMER_CB_SOFTIRQ:             Callback must run in softirq context
- *     HRTIMER_CB_IRQSAFE:             Callback may run in hardirq context
- *     HRTIMER_CB_IRQSAFE_NO_RESTART:  Callback may run in hardirq context and
- *                                     does not restart the timer
- *     HRTIMER_CB_IRQSAFE_NO_SOFTIRQ:  Callback must run in hardirq context
- *                                     Special mode for tick emultation
- */
-enum hrtimer_cb_mode {
-       HRTIMER_CB_SOFTIRQ,
-       HRTIMER_CB_IRQSAFE,
-       HRTIMER_CB_IRQSAFE_NO_RESTART,
-       HRTIMER_CB_IRQSAFE_NO_SOFTIRQ,
-};
-
-/*
  * Values to track state of the timer
  *
  * Possible states:
@@ -65,11 +53,11 @@ enum hrtimer_cb_mode {
  * 0x00                inactive
  * 0x01                enqueued into rbtree
  * 0x02                callback function running
- * 0x04                callback pending (high resolution mode)
  *
- * Special case:
+ * Special cases:
  * 0x03                callback function running and enqueued
  *             (was requeued on another CPU)
+ * 0x09                timer was migrated on CPU hotunplug
  * The "callback function running and enqueued" status is only possible on
  * SMP. It happens for example when a posix timer expired and the callback
  * queued a signal. Between dropping the lock which protects the posix timer
@@ -86,19 +74,22 @@ enum hrtimer_cb_mode {
 #define HRTIMER_STATE_INACTIVE 0x00
 #define HRTIMER_STATE_ENQUEUED 0x01
 #define HRTIMER_STATE_CALLBACK 0x02
-#define HRTIMER_STATE_PENDING  0x04
+#define HRTIMER_STATE_MIGRATE  0x04
 
 /**
  * struct hrtimer - the basic hrtimer structure
  * @node:      red black tree node for time ordered insertion
- * @expires:   the absolute expiry time in the hrtimers internal
+ * @_expires:  the absolute expiry time in the hrtimers internal
  *             representation. The time is related to the clock on
- *             which the timer is based.
+ *             which the timer is based. Is setup by adding
+ *             slack to the _softexpires value. For non range timers
+ *             identical to _softexpires.
+ * @_softexpires: the absolute earliest expiry time of the hrtimer.
+ *             The time which was given as expiry time when the timer
+ *             was armed.
  * @function:  timer expiry callback function
  * @base:      pointer to the timer base (per cpu and per clock)
  * @state:     state information (See bit values above)
- * @cb_mode:   high resolution timer feature to select the callback execution
- *              mode
  * @cb_entry:  list head to enqueue an expired timer into the callback list
  * @start_site:        timer statistics field to store the site where the timer
  *             was started
@@ -111,16 +102,16 @@ enum hrtimer_cb_mode {
  */
 struct hrtimer {
        struct rb_node                  node;
-       ktime_t                         expires;
+       ktime_t                         _expires;
+       ktime_t                         _softexpires;
        enum hrtimer_restart            (*function)(struct hrtimer *);
        struct hrtimer_clock_base       *base;
        unsigned long                   state;
-       enum hrtimer_cb_mode            cb_mode;
        struct list_head                cb_entry;
 #ifdef CONFIG_TIMER_STATS
+       int                             start_pid;
        void                            *start_site;
        char                            start_comm[16];
-       int                             start_pid;
 #endif
 };
 
@@ -145,10 +136,8 @@ struct hrtimer_sleeper {
  * @first:             pointer to the timer node which expires first
  * @resolution:                the resolution of the clock, in nanoseconds
  * @get_time:          function to retrieve the current time of the clock
- * @get_softirq_time:  function to retrieve the current time from the softirq
  * @softirq_time:      the time when running the hrtimer queue in the softirq
  * @offset:            offset of this clock to the monotonic base
- * @reprogram:         function to reprogram the timer event
  */
 struct hrtimer_clock_base {
        struct hrtimer_cpu_base *cpu_base;
@@ -157,13 +146,9 @@ struct hrtimer_clock_base {
        struct rb_node          *first;
        ktime_t                 resolution;
        ktime_t                 (*get_time)(void);
-       ktime_t                 (*get_softirq_time)(void);
        ktime_t                 softirq_time;
 #ifdef CONFIG_HIGH_RES_TIMERS
        ktime_t                 offset;
-       int                     (*reprogram)(struct hrtimer *t,
-                                            struct hrtimer_clock_base *b,
-                                            ktime_t n);
 #endif
 };
 
@@ -173,7 +158,6 @@ struct hrtimer_clock_base {
  * struct hrtimer_cpu_base - the per cpu clock bases
  * @lock:              lock protecting the base and associated clock bases
  *                     and timers
- * @lock_key:          the lock_class_key for use with lockdep
  * @clock_base:                array of clock bases for this cpu
  * @curr_timer:                the timer which is executing a callback right now
  * @expires_next:      absolute time of the next event which was scheduled
@@ -182,16 +166,11 @@ struct hrtimer_clock_base {
  * @check_clocks:      Indictator, when set evaluate time source and clock
  *                     event devices whether high resolution mode can be
  *                     activated.
- * @cb_pending:                Expired timers are moved from the rbtree to this
- *                     list in the timer interrupt. The list is processed
- *                     in the softirq.
  * @nr_events:         Total number of timer interrupt events
  */
 struct hrtimer_cpu_base {
        spinlock_t                      lock;
-       struct lock_class_key           lock_key;
        struct hrtimer_clock_base       clock_base[HRTIMER_MAX_CLOCK_BASES];
-       struct list_head                cb_pending;
 #ifdef CONFIG_HIGH_RES_TIMERS
        ktime_t                         expires_next;
        int                             hres_active;
@@ -199,6 +178,71 @@ struct hrtimer_cpu_base {
 #endif
 };
 
+static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time)
+{
+       timer->_expires = time;
+       timer->_softexpires = time;
+}
+
+static inline void hrtimer_set_expires_range(struct hrtimer *timer, ktime_t time, ktime_t delta)
+{
+       timer->_softexpires = time;
+       timer->_expires = ktime_add_safe(time, delta);
+}
+
+static inline void hrtimer_set_expires_range_ns(struct hrtimer *timer, ktime_t time, unsigned long delta)
+{
+       timer->_softexpires = time;
+       timer->_expires = ktime_add_safe(time, ns_to_ktime(delta));
+}
+
+static inline void hrtimer_set_expires_tv64(struct hrtimer *timer, s64 tv64)
+{
+       timer->_expires.tv64 = tv64;
+       timer->_softexpires.tv64 = tv64;
+}
+
+static inline void hrtimer_add_expires(struct hrtimer *timer, ktime_t time)
+{
+       timer->_expires = ktime_add_safe(timer->_expires, time);
+       timer->_softexpires = ktime_add_safe(timer->_softexpires, time);
+}
+
+static inline void hrtimer_add_expires_ns(struct hrtimer *timer, u64 ns)
+{
+       timer->_expires = ktime_add_ns(timer->_expires, ns);
+       timer->_softexpires = ktime_add_ns(timer->_softexpires, ns);
+}
+
+static inline ktime_t hrtimer_get_expires(const struct hrtimer *timer)
+{
+       return timer->_expires;
+}
+
+static inline ktime_t hrtimer_get_softexpires(const struct hrtimer *timer)
+{
+       return timer->_softexpires;
+}
+
+static inline s64 hrtimer_get_expires_tv64(const struct hrtimer *timer)
+{
+       return timer->_expires.tv64;
+}
+static inline s64 hrtimer_get_softexpires_tv64(const struct hrtimer *timer)
+{
+       return timer->_softexpires.tv64;
+}
+
+static inline s64 hrtimer_get_expires_ns(const struct hrtimer *timer)
+{
+       return ktime_to_ns(timer->_expires);
+}
+
+static inline ktime_t hrtimer_expires_remaining(const struct hrtimer *timer)
+{
+    return ktime_sub(timer->_expires, timer->base->get_time());
+}
+
 #ifdef CONFIG_HIGH_RES_TIMERS
 struct clock_event_device;
 
@@ -219,6 +263,8 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer)
        return timer->base->cpu_base->hres_active;
 }
 
+extern void hrtimer_peek_ahead_timers(void);
+
 /*
  * The resolution of the clocks. The resolution value is returned in
  * the clock_getres() system call to give application programmers an
@@ -241,6 +287,7 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer)
  * is expired in the next softirq when the clock was advanced.
  */
 static inline void clock_was_set(void) { }
+static inline void hrtimer_peek_ahead_timers(void) { }
 
 static inline void hres_timers_resume(void) { }
 
@@ -262,21 +309,58 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer)
 extern ktime_t ktime_get(void);
 extern ktime_t ktime_get_real(void);
 
+
+DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
+
+
 /* Exported timer functions: */
 
 /* Initialize timers: */
 extern void hrtimer_init(struct hrtimer *timer, clockid_t which_clock,
                         enum hrtimer_mode mode);
 
+#ifdef CONFIG_DEBUG_OBJECTS_TIMERS
+extern void hrtimer_init_on_stack(struct hrtimer *timer, clockid_t which_clock,
+                                 enum hrtimer_mode mode);
+
+extern void destroy_hrtimer_on_stack(struct hrtimer *timer);
+#else
+static inline void hrtimer_init_on_stack(struct hrtimer *timer,
+                                        clockid_t which_clock,
+                                        enum hrtimer_mode mode)
+{
+       hrtimer_init(timer, which_clock, mode);
+}
+static inline void destroy_hrtimer_on_stack(struct hrtimer *timer) { }
+#endif
+
 /* Basic timer operations: */
 extern int hrtimer_start(struct hrtimer *timer, ktime_t tim,
                         const enum hrtimer_mode mode);
+extern int hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
+                       unsigned long range_ns, const enum hrtimer_mode mode);
+extern int
+__hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
+                        unsigned long delta_ns,
+                        const enum hrtimer_mode mode, int wakeup);
+
 extern int hrtimer_cancel(struct hrtimer *timer);
 extern int hrtimer_try_to_cancel(struct hrtimer *timer);
 
+static inline int hrtimer_start_expires(struct hrtimer *timer,
+                                               enum hrtimer_mode mode)
+{
+       unsigned long delta;
+       ktime_t soft, hard;
+       soft = hrtimer_get_softexpires(timer);
+       hard = hrtimer_get_expires(timer);
+       delta = ktime_to_ns(ktime_sub(hard, soft));
+       return hrtimer_start_range_ns(timer, soft, delta, mode);
+}
+
 static inline int hrtimer_restart(struct hrtimer *timer)
 {
-       return hrtimer_start(timer, timer->expires, HRTIMER_MODE_ABS);
+       return hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
 }
 
 /* Query timers: */
@@ -299,8 +383,16 @@ static inline int hrtimer_active(const struct hrtimer *timer)
  */
 static inline int hrtimer_is_queued(struct hrtimer *timer)
 {
-       return timer->state &
-               (HRTIMER_STATE_ENQUEUED | HRTIMER_STATE_PENDING);
+       return timer->state & HRTIMER_STATE_ENQUEUED;
+}
+
+/*
+ * Helper function to check, whether the timer is running the callback
+ * function
+ */
+static inline int hrtimer_callback_running(struct hrtimer *timer)
+{
+       return timer->state & HRTIMER_STATE_CALLBACK;
 }
 
 /* Forward a hrtimer so it expires after now: */
@@ -324,6 +416,10 @@ extern long hrtimer_nanosleep_restart(struct restart_block *restart_block);
 extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl,
                                 struct task_struct *tsk);
 
+extern int schedule_hrtimeout_range(ktime_t *expires, unsigned long delta,
+                                               const enum hrtimer_mode mode);
+extern int schedule_hrtimeout(ktime_t *expires, const enum hrtimer_mode mode);
+
 /* Soft interrupt function to run the hrtimer queues: */
 extern void hrtimer_run_queues(void);
 extern void hrtimer_run_pending(void);