aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/timer.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-06-15 13:06:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-15 13:06:19 -0400
commit19035e5b5d1e3127b4925d86f6a77964f91f2c3c (patch)
treec9e7e9073970176a5b0970da715cb6430c3c9069 /kernel/timer.c
parentf9db6e095115f9411b9647bdb9d81fe11f3d8b54 (diff)
parenteea08f32adb3f97553d49a4f79a119833036000a (diff)
Merge branch 'timers-for-linus-migration' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'timers-for-linus-migration' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: timers: Logic to move non pinned timers timers: /proc/sys sysctl hook to enable timer migration timers: Identifying the existing pinned timers timers: Framework for identifying pinned timers timers: allow deferrable timers for intervals tv2-tv5 to be deferred Fix up conflicts in kernel/sched.c and kernel/timer.c manually
Diffstat (limited to 'kernel/timer.c')
-rw-r--r--kernel/timer.c51
1 files changed, 44 insertions, 7 deletions
diff --git a/kernel/timer.c b/kernel/timer.c
index faf2db897de4..54d3912f8cad 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -38,6 +38,7 @@
38#include <linux/tick.h> 38#include <linux/tick.h>
39#include <linux/kallsyms.h> 39#include <linux/kallsyms.h>
40#include <linux/perf_counter.h> 40#include <linux/perf_counter.h>
41#include <linux/sched.h>
41 42
42#include <asm/uaccess.h> 43#include <asm/uaccess.h>
43#include <asm/unistd.h> 44#include <asm/unistd.h>
@@ -605,13 +606,12 @@ static struct tvec_base *lock_timer_base(struct timer_list *timer,
605} 606}
606 607
607static inline int 608static inline int
608__mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) 609__mod_timer(struct timer_list *timer, unsigned long expires,
610 bool pending_only, int pinned)
609{ 611{
610 struct tvec_base *base, *new_base; 612 struct tvec_base *base, *new_base;
611 unsigned long flags; 613 unsigned long flags;
612 int ret; 614 int ret = 0 , cpu;
613
614 ret = 0;
615 615
616 timer_stats_timer_set_start_info(timer); 616 timer_stats_timer_set_start_info(timer);
617 BUG_ON(!timer->function); 617 BUG_ON(!timer->function);
@@ -630,6 +630,18 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
630 630
631 new_base = __get_cpu_var(tvec_bases); 631 new_base = __get_cpu_var(tvec_bases);
632 632
633 cpu = smp_processor_id();
634
635#if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP)
636 if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu)) {
637 int preferred_cpu = get_nohz_load_balancer();
638
639 if (preferred_cpu >= 0)
640 cpu = preferred_cpu;
641 }
642#endif
643 new_base = per_cpu(tvec_bases, cpu);
644
633 if (base != new_base) { 645 if (base != new_base) {
634 /* 646 /*
635 * We are trying to schedule the timer on the local CPU. 647 * We are trying to schedule the timer on the local CPU.
@@ -669,7 +681,7 @@ out_unlock:
669 */ 681 */
670int mod_timer_pending(struct timer_list *timer, unsigned long expires) 682int mod_timer_pending(struct timer_list *timer, unsigned long expires)
671{ 683{
672 return __mod_timer(timer, expires, true); 684 return __mod_timer(timer, expires, true, TIMER_NOT_PINNED);
673} 685}
674EXPORT_SYMBOL(mod_timer_pending); 686EXPORT_SYMBOL(mod_timer_pending);
675 687
@@ -703,11 +715,33 @@ int mod_timer(struct timer_list *timer, unsigned long expires)
703 if (timer->expires == expires && timer_pending(timer)) 715 if (timer->expires == expires && timer_pending(timer))
704 return 1; 716 return 1;
705 717
706 return __mod_timer(timer, expires, false); 718 return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
707} 719}
708EXPORT_SYMBOL(mod_timer); 720EXPORT_SYMBOL(mod_timer);
709 721
710/** 722/**
723 * mod_timer_pinned - modify a timer's timeout
724 * @timer: the timer to be modified
725 * @expires: new timeout in jiffies
726 *
727 * mod_timer_pinned() is a way to update the expire field of an
728 * active timer (if the timer is inactive it will be activated)
729 * and not allow the timer to be migrated to a different CPU.
730 *
731 * mod_timer_pinned(timer, expires) is equivalent to:
732 *
733 * del_timer(timer); timer->expires = expires; add_timer(timer);
734 */
735int mod_timer_pinned(struct timer_list *timer, unsigned long expires)
736{
737 if (timer->expires == expires && timer_pending(timer))
738 return 1;
739
740 return __mod_timer(timer, expires, false, TIMER_PINNED);
741}
742EXPORT_SYMBOL(mod_timer_pinned);
743
744/**
711 * add_timer - start a timer 745 * add_timer - start a timer
712 * @timer: the timer to be added 746 * @timer: the timer to be added
713 * 747 *
@@ -1017,6 +1051,9 @@ cascade:
1017 index = slot = timer_jiffies & TVN_MASK; 1051 index = slot = timer_jiffies & TVN_MASK;
1018 do { 1052 do {
1019 list_for_each_entry(nte, varp->vec + slot, entry) { 1053 list_for_each_entry(nte, varp->vec + slot, entry) {
1054 if (tbase_get_deferrable(nte->base))
1055 continue;
1056
1020 found = 1; 1057 found = 1;
1021 if (time_before(nte->expires, expires)) 1058 if (time_before(nte->expires, expires))
1022 expires = nte->expires; 1059 expires = nte->expires;
@@ -1307,7 +1344,7 @@ signed long __sched schedule_timeout(signed long timeout)
1307 expire = timeout + jiffies; 1344 expire = timeout + jiffies;
1308 1345
1309 setup_timer_on_stack(&timer, process_timeout, (unsigned long)current); 1346 setup_timer_on_stack(&timer, process_timeout, (unsigned long)current);
1310 __mod_timer(&timer, expire, false); 1347 __mod_timer(&timer, expire, false, TIMER_NOT_PINNED);
1311 schedule(); 1348 schedule();
1312 del_singleshot_timer_sync(&timer); 1349 del_singleshot_timer_sync(&timer);
1313 1350