diff options
Diffstat (limited to 'kernel/time/timer.c')
| -rw-r--r-- | kernel/time/timer.c | 45 | 
1 files changed, 38 insertions, 7 deletions
diff --git a/kernel/time/timer.c b/kernel/time/timer.c index fbb1f85327bf..af0b8bae4502 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -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,11 +1084,26 @@ 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);  | 
