aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern B. Brandenburg <bbb@cs.unc.edu>2009-12-08 12:29:29 -0500
committerBjoern B. Brandenburg <bbb@cs.unc.edu>2009-12-08 12:47:34 -0500
commitb4891d7e031755438817db2415e4ec77be135e01 (patch)
treec9c161cb96a4c273993bc112c7fe72a5b1d11ae0
parentb6b52a7f2cf9f741beda70a129f8ecf3bcb4ae32 (diff)
add hrtimer_start_on() API
-rw-r--r--arch/x86/kernel/smp_32.c3
-rw-r--r--include/linux/hrtimer.h15
-rw-r--r--kernel/hrtimer.c68
3 files changed, 86 insertions, 0 deletions
diff --git a/arch/x86/kernel/smp_32.c b/arch/x86/kernel/smp_32.c
index 3d16decc15..8d28cee0de 100644
--- a/arch/x86/kernel/smp_32.c
+++ b/arch/x86/kernel/smp_32.c
@@ -656,10 +656,13 @@ fastcall void smp_reschedule_interrupt(struct pt_regs *regs)
656 TS_SEND_RESCHED_END; 656 TS_SEND_RESCHED_END;
657} 657}
658 658
659extern void hrtimer_pull(void);
660
659fastcall void smp_pull_timers_interrupt(struct pt_regs *regs) 661fastcall void smp_pull_timers_interrupt(struct pt_regs *regs)
660{ 662{
661 ack_APIC_irq(); 663 ack_APIC_irq();
662 TRACE("pull timers interrupt\n"); 664 TRACE("pull timers interrupt\n");
665 hrtimer_pull();
663} 666}
664 667
665fastcall void smp_call_function_interrupt(struct pt_regs *regs) 668fastcall void smp_call_function_interrupt(struct pt_regs *regs)
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 7a9398e197..32d456e01d 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -200,6 +200,18 @@ struct hrtimer_cpu_base {
200 struct list_head cb_pending; 200 struct list_head cb_pending;
201 unsigned long nr_events; 201 unsigned long nr_events;
202#endif 202#endif
203 struct list_head to_pull;
204};
205
206#define HRTIMER_START_ON_INACTIVE 0
207#define HRTIMER_START_ON_QUEUED 1
208
209struct hrtimer_start_on_info {
210 struct list_head list;
211 struct hrtimer* timer;
212 ktime_t time;
213 enum hrtimer_mode mode;
214 atomic_t state;
203}; 215};
204 216
205#ifdef CONFIG_HIGH_RES_TIMERS 217#ifdef CONFIG_HIGH_RES_TIMERS
@@ -262,6 +274,9 @@ extern void hrtimer_init(struct hrtimer *timer, clockid_t which_clock,
262/* Basic timer operations: */ 274/* Basic timer operations: */
263extern int hrtimer_start(struct hrtimer *timer, ktime_t tim, 275extern int hrtimer_start(struct hrtimer *timer, ktime_t tim,
264 const enum hrtimer_mode mode); 276 const enum hrtimer_mode mode);
277extern int hrtimer_start_on(int cpu, struct hrtimer_start_on_info* info,
278 struct hrtimer *timer, ktime_t time,
279 const enum hrtimer_mode mode);
265extern int hrtimer_cancel(struct hrtimer *timer); 280extern int hrtimer_cancel(struct hrtimer *timer);
266extern int hrtimer_try_to_cancel(struct hrtimer *timer); 281extern int hrtimer_try_to_cancel(struct hrtimer *timer);
267 282
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index f994bb8065..3165b48101 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -46,6 +46,9 @@
46 46
47#include <asm/uaccess.h> 47#include <asm/uaccess.h>
48 48
49#include <litmus/litmus.h>
50
51
49/** 52/**
50 * ktime_get - get the monotonic time in ktime_t format 53 * ktime_get - get the monotonic time in ktime_t format
51 * 54 *
@@ -813,6 +816,70 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base)
813 return 0; 816 return 0;
814} 817}
815 818
819void hrtimer_pull(void)
820{
821 struct hrtimer_cpu_base* base = &__get_cpu_var(hrtimer_bases);
822 struct hrtimer_start_on_info* info;
823 struct list_head *pos, *safe, list;
824
825 spin_lock(&base->lock);
826 list_replace_init(&base->to_pull, &list);
827 spin_unlock(&base->lock);
828
829 list_for_each_safe(pos, safe, &list) {
830 info = list_entry(pos, struct hrtimer_start_on_info, list);
831 TRACE("pulled timer 0x%x\n", info->timer);
832 list_del(pos);
833 hrtimer_start(info->timer, info->time, info->mode);
834 }
835}
836
837int hrtimer_start_on(int cpu, struct hrtimer_start_on_info* info,
838 struct hrtimer *timer, ktime_t time,
839 const enum hrtimer_mode mode)
840{
841 unsigned long flags;
842 struct hrtimer_cpu_base* base;
843 int in_use = 0, was_empty;
844
845 /* serialize access to info through the timer base */
846 lock_hrtimer_base(timer, &flags);
847
848 in_use = atomic_read(&info->state) != HRTIMER_START_ON_INACTIVE;
849 if (!in_use) {
850 INIT_LIST_HEAD(&info->list);
851 info->timer = timer;
852 info->time = time;
853 info->mode = mode;
854 /* mark as in use */
855 atomic_set(&info->state, HRTIMER_START_ON_QUEUED);
856 }
857
858 unlock_hrtimer_base(timer, &flags);
859
860 if (!in_use) {
861 /* initiate pull */
862 preempt_disable();
863 if (cpu == smp_processor_id()) {
864 /* start timer locally */
865 hrtimer_start(info->timer, info->time, info->mode);
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
@@ -1390,6 +1457,7 @@ static void __cpuinit init_hrtimers_cpu(int cpu)
1390 cpu_base->clock_base[i].cpu_base = cpu_base; 1457 cpu_base->clock_base[i].cpu_base = cpu_base;
1391 1458
1392 hrtimer_init_hres(cpu_base); 1459 hrtimer_init_hres(cpu_base);
1460 INIT_LIST_HEAD(&cpu_base->to_pull);
1393} 1461}
1394 1462
1395#ifdef CONFIG_HOTPLUG_CPU 1463#ifdef CONFIG_HOTPLUG_CPU