diff options
Diffstat (limited to 'kernel/timer.c')
| -rw-r--r-- | kernel/timer.c | 24 | 
1 files changed, 23 insertions, 1 deletions
diff --git a/kernel/timer.c b/kernel/timer.c index a7f07d5a624..33fc9d175f4 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -72,6 +72,7 @@ struct tvec_base {  	spinlock_t lock;  	struct timer_list *running_timer;  	unsigned long timer_jiffies; +	unsigned long next_timer;  	struct tvec_root tv1;  	struct tvec tv2;  	struct tvec tv3; @@ -622,6 +623,9 @@ __mod_timer(struct timer_list *timer, unsigned long expires,  	if (timer_pending(timer)) {  		detach_timer(timer, 0); +		if (timer->expires == base->next_timer && +		    !tbase_get_deferrable(timer->base)) +			base->next_timer = base->timer_jiffies;  		ret = 1;  	} else {  		if (pending_only) @@ -663,6 +667,9 @@ __mod_timer(struct timer_list *timer, unsigned long expires,  	}  	timer->expires = expires; +	if (time_before(timer->expires, base->next_timer) && +	    !tbase_get_deferrable(timer->base)) +		base->next_timer = timer->expires;  	internal_add_timer(base, timer);  out_unlock: @@ -781,6 +788,9 @@ void add_timer_on(struct timer_list *timer, int cpu)  	spin_lock_irqsave(&base->lock, flags);  	timer_set_base(timer, base);  	debug_timer_activate(timer); +	if (time_before(timer->expires, base->next_timer) && +	    !tbase_get_deferrable(timer->base)) +		base->next_timer = timer->expires;  	internal_add_timer(base, timer);  	/*  	 * Check whether the other CPU is idle and needs to be @@ -817,6 +827,9 @@ int del_timer(struct timer_list *timer)  		base = lock_timer_base(timer, &flags);  		if (timer_pending(timer)) {  			detach_timer(timer, 1); +			if (timer->expires == base->next_timer && +			    !tbase_get_deferrable(timer->base)) +				base->next_timer = base->timer_jiffies;  			ret = 1;  		}  		spin_unlock_irqrestore(&base->lock, flags); @@ -850,6 +863,9 @@ int try_to_del_timer_sync(struct timer_list *timer)  	ret = 0;  	if (timer_pending(timer)) {  		detach_timer(timer, 1); +		if (timer->expires == base->next_timer && +		    !tbase_get_deferrable(timer->base)) +			base->next_timer = base->timer_jiffies;  		ret = 1;  	}  out: @@ -1134,7 +1150,9 @@ unsigned long get_next_timer_interrupt(unsigned long now)  	unsigned long expires;  	spin_lock(&base->lock); -	expires = __next_timer_interrupt(base); +	if (time_before_eq(base->next_timer, base->timer_jiffies)) +		base->next_timer = __next_timer_interrupt(base); +	expires = base->next_timer;  	spin_unlock(&base->lock);  	if (time_before_eq(expires, now)) @@ -1523,6 +1541,7 @@ static int __cpuinit init_timers_cpu(int cpu)  		INIT_LIST_HEAD(base->tv1.vec + j);  	base->timer_jiffies = jiffies; +	base->next_timer = base->timer_jiffies;  	return 0;  } @@ -1535,6 +1554,9 @@ static void migrate_timer_list(struct tvec_base *new_base, struct list_head *hea  		timer = list_first_entry(head, struct timer_list, entry);  		detach_timer(timer, 0);  		timer_set_base(timer, new_base); +		if (time_before(timer->expires, new_base->next_timer) && +		    !tbase_get_deferrable(timer->base)) +			new_base->next_timer = timer->expires;  		internal_add_timer(new_base, timer);  	}  }  |