|
@@ -929,8 +929,11 @@ static struct timer_base *lock_timer_base(struct timer_list *timer,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+#define MOD_TIMER_PENDING_ONLY 0x01
|
|
|
+#define MOD_TIMER_REDUCE 0x02
|
|
|
+
|
|
|
static inline int
|
|
|
-__mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
|
|
|
+__mod_timer(struct timer_list *timer, unsigned long expires, unsigned int options)
|
|
|
{
|
|
|
struct timer_base *base, *new_base;
|
|
|
unsigned int idx = UINT_MAX;
|
|
@@ -950,7 +953,11 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
|
|
|
* larger granularity than you would get from adding a new
|
|
|
* timer with this expiry.
|
|
|
*/
|
|
|
- if (timer->expires == expires)
|
|
|
+ long diff = timer->expires - expires;
|
|
|
+
|
|
|
+ if (!diff)
|
|
|
+ return 1;
|
|
|
+ if (options & MOD_TIMER_REDUCE && diff <= 0)
|
|
|
return 1;
|
|
|
|
|
|
/*
|
|
@@ -962,6 +969,12 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
|
|
|
base = lock_timer_base(timer, &flags);
|
|
|
forward_timer_base(base);
|
|
|
|
|
|
+ if (timer_pending(timer) && (options & MOD_TIMER_REDUCE) &&
|
|
|
+ time_before_eq(timer->expires, expires)) {
|
|
|
+ ret = 1;
|
|
|
+ goto out_unlock;
|
|
|
+ }
|
|
|
+
|
|
|
clk = base->clk;
|
|
|
idx = calc_wheel_index(expires, clk);
|
|
|
|
|
@@ -971,7 +984,10 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
|
|
|
* subsequent call will exit in the expires check above.
|
|
|
*/
|
|
|
if (idx == timer_get_idx(timer)) {
|
|
|
- timer->expires = expires;
|
|
|
+ if (!(options & MOD_TIMER_REDUCE))
|
|
|
+ timer->expires = expires;
|
|
|
+ else if (time_after(timer->expires, expires))
|
|
|
+ timer->expires = expires;
|
|
|
ret = 1;
|
|
|
goto out_unlock;
|
|
|
}
|
|
@@ -981,7 +997,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
|
|
|
}
|
|
|
|
|
|
ret = detach_if_pending(timer, base, false);
|
|
|
- if (!ret && pending_only)
|
|
|
+ if (!ret && (options & MOD_TIMER_PENDING_ONLY))
|
|
|
goto out_unlock;
|
|
|
|
|
|
debug_activate(timer, expires);
|
|
@@ -1042,7 +1058,7 @@ out_unlock:
|
|
|
*/
|
|
|
int mod_timer_pending(struct timer_list *timer, unsigned long expires)
|
|
|
{
|
|
|
- return __mod_timer(timer, expires, true);
|
|
|
+ return __mod_timer(timer, expires, MOD_TIMER_PENDING_ONLY);
|
|
|
}
|
|
|
EXPORT_SYMBOL(mod_timer_pending);
|
|
|
|
|
@@ -1068,10 +1084,25 @@ EXPORT_SYMBOL(mod_timer_pending);
|
|
|
*/
|
|
|
int mod_timer(struct timer_list *timer, unsigned long expires)
|
|
|
{
|
|
|
- return __mod_timer(timer, expires, false);
|
|
|
+ return __mod_timer(timer, expires, 0);
|
|
|
}
|
|
|
EXPORT_SYMBOL(mod_timer);
|
|
|
|
|
|
+/**
|
|
|
+ * timer_reduce - Modify a timer's timeout if it would reduce the timeout
|
|
|
+ * @timer: The timer to be modified
|
|
|
+ * @expires: New timeout in jiffies
|
|
|
+ *
|
|
|
+ * timer_reduce() is very similar to mod_timer(), except that it will only
|
|
|
+ * modify a running timer if that would reduce the expiration time (it will
|
|
|
+ * start a timer that isn't running).
|
|
|
+ */
|
|
|
+int timer_reduce(struct timer_list *timer, unsigned long expires)
|
|
|
+{
|
|
|
+ return __mod_timer(timer, expires, MOD_TIMER_REDUCE);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(timer_reduce);
|
|
|
+
|
|
|
/**
|
|
|
* add_timer - start a timer
|
|
|
* @timer: the timer to be added
|
|
@@ -1754,7 +1785,7 @@ signed long __sched schedule_timeout(signed long timeout)
|
|
|
|
|
|
timer.task = current;
|
|
|
timer_setup_on_stack(&timer.timer, process_timeout, 0);
|
|
|
- __mod_timer(&timer.timer, expire, false);
|
|
|
+ __mod_timer(&timer.timer, expire, 0);
|
|
|
schedule();
|
|
|
del_singleshot_timer_sync(&timer.timer);
|
|
|
|