|
@@ -318,6 +318,24 @@ unsigned long round_jiffies_up_relative(unsigned long j)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(round_jiffies_up_relative);
|
|
|
|
|
|
+/**
|
|
|
+ * set_timer_slack - set the allowed slack for a timer
|
|
|
+ * @slack_hz: the amount of time (in jiffies) allowed for rounding
|
|
|
+ *
|
|
|
+ * Set the amount of time, in jiffies, that a certain timer has
|
|
|
+ * in terms of slack. By setting this value, the timer subsystem
|
|
|
+ * will schedule the actual timer somewhere between
|
|
|
+ * the time mod_timer() asks for, and that time plus the slack.
|
|
|
+ *
|
|
|
+ * By setting the slack to -1, a percentage of the delay is used
|
|
|
+ * instead.
|
|
|
+ */
|
|
|
+void set_timer_slack(struct timer_list *timer, int slack_hz)
|
|
|
+{
|
|
|
+ timer->slack = slack_hz;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(set_timer_slack);
|
|
|
+
|
|
|
|
|
|
static inline void set_running_timer(struct tvec_base *base,
|
|
|
struct timer_list *timer)
|
|
@@ -549,6 +567,7 @@ static void __init_timer(struct timer_list *timer,
|
|
|
{
|
|
|
timer->entry.next = NULL;
|
|
|
timer->base = __raw_get_cpu_var(tvec_bases);
|
|
|
+ timer->slack = -1;
|
|
|
#ifdef CONFIG_TIMER_STATS
|
|
|
timer->start_site = NULL;
|
|
|
timer->start_pid = -1;
|
|
@@ -714,6 +733,41 @@ int mod_timer_pending(struct timer_list *timer, unsigned long expires)
|
|
|
}
|
|
|
EXPORT_SYMBOL(mod_timer_pending);
|
|
|
|
|
|
+/*
|
|
|
+ * Decide where to put the timer while taking the slack into account
|
|
|
+ *
|
|
|
+ * Algorithm:
|
|
|
+ * 1) calculate the maximum (absolute) time
|
|
|
+ * 2) calculate the highest bit where the expires and new max are different
|
|
|
+ * 3) use this bit to make a mask
|
|
|
+ * 4) use the bitmask to round down the maximum time, so that all last
|
|
|
+ * bits are zeros
|
|
|
+ */
|
|
|
+static inline
|
|
|
+unsigned long apply_slack(struct timer_list *timer, unsigned long expires)
|
|
|
+{
|
|
|
+ unsigned long expires_limit, mask;
|
|
|
+ int bit;
|
|
|
+
|
|
|
+ expires_limit = expires + timer->slack;
|
|
|
+
|
|
|
+ if (timer->slack < 0) /* auto slack: use 0.4% */
|
|
|
+ expires_limit = expires + (expires - jiffies)/256;
|
|
|
+
|
|
|
+ mask = expires ^ expires_limit;
|
|
|
+
|
|
|
+ if (mask == 0)
|
|
|
+ return expires;
|
|
|
+
|
|
|
+ bit = find_last_bit(&mask, BITS_PER_LONG);
|
|
|
+
|
|
|
+ mask = (1 << bit) - 1;
|
|
|
+
|
|
|
+ expires_limit = expires_limit & ~(mask);
|
|
|
+
|
|
|
+ return expires_limit;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* mod_timer - modify a timer's timeout
|
|
|
* @timer: the timer to be modified
|
|
@@ -744,6 +798,8 @@ int mod_timer(struct timer_list *timer, unsigned long expires)
|
|
|
if (timer_pending(timer) && timer->expires == expires)
|
|
|
return 1;
|
|
|
|
|
|
+ expires = apply_slack(timer, expires);
|
|
|
+
|
|
|
return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
|
|
|
}
|
|
|
EXPORT_SYMBOL(mod_timer);
|