aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/hrtimer.c
diff options
context:
space:
mode:
authorBjoern B. Brandenburg <bbb@cs.unc.edu>2009-04-22 23:01:44 -0400
committerBjoern B. Brandenburg <bbb@cs.unc.edu>2009-04-22 23:01:44 -0400
commitb5c4ababa76ce94cfa276f620b81d7d0f1d8ebf1 (patch)
treebc8c705a7b1b8e11c6789cecb5f6d9c3be09dad0 /kernel/hrtimer.c
parentfc757f4223edfab215d6e49cee479a09ecc17962 (diff)
hrtimer: add support for starting timers on remote CPUs
This depends on the ability to send the special 'pull_timers' IPI even with IRQs disabled.
Diffstat (limited to 'kernel/hrtimer.c')
-rw-r--r--kernel/hrtimer.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index f994bb8065..c47baab445 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -813,6 +813,73 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base)
813 return 0; 813 return 0;
814} 814}
815 815
816void hrtimer_pull(void)
817{
818 struct hrtimer_cpu_base* base = &__get_cpu_var(hrtimer_bases);
819 struct hrtimer_start_on_info* info;
820 struct list_head *pos, *safe, list;
821
822 spin_lock(&base->lock);
823 list_replace_init(&base->to_pull, &list);
824 spin_unlock(&base->lock);
825
826 list_for_each_safe(pos, safe, &list) {
827 info = list_entry(pos, struct hrtimer_start_on_info, list);
828 TRACE("pulled timer 0x%x\n", info->timer);
829 list_del(pos);
830 hrtimer_start(info->timer, info->time, info->mode);
831 mb();
832 atomic_set(&info->state, HRTIMER_START_ON_PROCESSED);
833 }
834}
835
836int hrtimer_start_on(int cpu, struct hrtimer_start_on_info* info,
837 struct hrtimer *timer, ktime_t time,
838 const enum hrtimer_mode mode)
839{
840 unsigned long flags;
841 struct hrtimer_cpu_base* base;
842 int in_use = 0, was_empty;
843
844 /* serialize access to info through the timer base */
845 lock_hrtimer_base(timer, &flags);
846
847 in_use = atomic_read(&info->state) != HRTIMER_START_ON_INACTIVE;
848 if (!in_use) {
849 INIT_LIST_HEAD(&info->list);
850 info->timer = timer;
851 info->time = time;
852 info->mode = mode;
853 /* mark as in use */
854 atomic_set(&info->state, HRTIMER_START_ON_QUEUED);
855 }
856
857 unlock_hrtimer_base(timer, &flags);
858
859 if (!in_use) {
860 /* initiate pull */
861 preempt_disable();
862 if (cpu == smp_processor_id()) {
863 /* start timer locally */
864 hrtimer_start(info->timer, info->time, info->mode);
865 atomic_set(&info->state, HRTIMER_START_ON_PROCESSED);
866 } else {
867 base = &per_cpu(hrtimer_bases, cpu);
868 spin_lock_irqsave(&base->lock, flags);
869 was_empty = list_empty(&base->to_pull);
870 list_add(&info->list, &base->to_pull);
871 spin_unlock_irqrestore(&base->lock, flags);
872 if (was_empty)
873 /* only send IPI if other no else
874 * has done so already
875 */
876 smp_send_pull_timers(cpu);
877 }
878 preempt_enable();
879 }
880 return in_use;
881}
882
816/** 883/**
817 * hrtimer_start - (re)start an relative timer on the current CPU 884 * hrtimer_start - (re)start an relative timer on the current CPU
818 * @timer: the timer to be added 885 * @timer: the timer to be added