diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2009-12-17 21:45:38 -0500 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-29 17:19:45 -0400 |
commit | c15be843778236e9f2fdbc207ab36ba996b2bb1b (patch) | |
tree | 985dc4c5f034a742e68c7df0ce47a1e43222e813 | |
parent | b085cafc43bc395e255626204169e20a587f28ba (diff) |
[ported from 2008.3] Add hrtimer_start_on() API
-rw-r--r-- | arch/x86/kernel/smp.c | 1 | ||||
-rw-r--r-- | include/linux/hrtimer.h | 25 | ||||
-rw-r--r-- | kernel/hrtimer.c | 80 |
3 files changed, 106 insertions, 0 deletions
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index e83f79de863c..a93528bc16e9 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c | |||
@@ -246,6 +246,7 @@ void smp_pull_timers_interrupt(struct pt_regs *regs) | |||
246 | { | 246 | { |
247 | ack_APIC_irq(); | 247 | ack_APIC_irq(); |
248 | TRACE("pull timer interrupt\n"); | 248 | TRACE("pull timer interrupt\n"); |
249 | hrtimer_pull(); | ||
249 | } | 250 | } |
250 | 251 | ||
251 | struct smp_ops smp_ops = { | 252 | struct smp_ops smp_ops = { |
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index ff037f0b1b4e..b984b947f5db 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h | |||
@@ -166,6 +166,7 @@ struct hrtimer_clock_base { | |||
166 | * event devices whether high resolution mode can be | 166 | * event devices whether high resolution mode can be |
167 | * activated. | 167 | * activated. |
168 | * @nr_events: Total number of timer interrupt events | 168 | * @nr_events: Total number of timer interrupt events |
169 | * @to_pull: LITMUS^RT list of timers to be pulled on this cpu | ||
169 | */ | 170 | */ |
170 | struct hrtimer_cpu_base { | 171 | struct hrtimer_cpu_base { |
171 | spinlock_t lock; | 172 | spinlock_t lock; |
@@ -175,6 +176,26 @@ struct hrtimer_cpu_base { | |||
175 | int hres_active; | 176 | int hres_active; |
176 | unsigned long nr_events; | 177 | unsigned long nr_events; |
177 | #endif | 178 | #endif |
179 | struct list_head to_pull; | ||
180 | }; | ||
181 | |||
182 | #define HRTIMER_START_ON_INACTIVE 0 | ||
183 | #define HRTIMER_START_ON_QUEUED 1 | ||
184 | |||
185 | /* | ||
186 | * struct hrtimer_start_on_info - save timer info on remote cpu | ||
187 | * @list: list of hrtimer_start_on_info on remote cpu (to_pull) | ||
188 | * @timer: timer to be triggered on remote cpu | ||
189 | * @time: time event | ||
190 | * @mode: timer mode | ||
191 | * @state: activity flag | ||
192 | */ | ||
193 | struct hrtimer_start_on_info { | ||
194 | struct list_head list; | ||
195 | struct hrtimer *timer; | ||
196 | ktime_t time; | ||
197 | enum hrtimer_mode mode; | ||
198 | atomic_t state; | ||
178 | }; | 199 | }; |
179 | 200 | ||
180 | static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time) | 201 | static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time) |
@@ -343,6 +364,10 @@ __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, | |||
343 | unsigned long delta_ns, | 364 | unsigned long delta_ns, |
344 | const enum hrtimer_mode mode, int wakeup); | 365 | const enum hrtimer_mode mode, int wakeup); |
345 | 366 | ||
367 | extern int hrtimer_start_on(int cpu, struct hrtimer_start_on_info *info, | ||
368 | struct hrtimer *timer, ktime_t time, | ||
369 | const enum hrtimer_mode mode); | ||
370 | |||
346 | extern int hrtimer_cancel(struct hrtimer *timer); | 371 | extern int hrtimer_cancel(struct hrtimer *timer); |
347 | extern int hrtimer_try_to_cancel(struct hrtimer *timer); | 372 | extern int hrtimer_try_to_cancel(struct hrtimer *timer); |
348 | 373 | ||
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 3e1c36e7998f..509ecaea3016 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c | |||
@@ -46,6 +46,8 @@ | |||
46 | #include <linux/sched.h> | 46 | #include <linux/sched.h> |
47 | #include <linux/timer.h> | 47 | #include <linux/timer.h> |
48 | 48 | ||
49 | #include <litmus/litmus.h> | ||
50 | |||
49 | #include <asm/uaccess.h> | 51 | #include <asm/uaccess.h> |
50 | 52 | ||
51 | #include <trace/events/timer.h> | 53 | #include <trace/events/timer.h> |
@@ -1016,6 +1018,83 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode) | |||
1016 | } | 1018 | } |
1017 | EXPORT_SYMBOL_GPL(hrtimer_start); | 1019 | EXPORT_SYMBOL_GPL(hrtimer_start); |
1018 | 1020 | ||
1021 | /** | ||
1022 | * hrtimer_pull - PULL_TIMERS_VECTOR callback on remote cpu | ||
1023 | */ | ||
1024 | void hrtimer_pull(void) | ||
1025 | { | ||
1026 | struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases); | ||
1027 | struct hrtimer_start_on_info *info; | ||
1028 | struct list_head *pos, *safe, list; | ||
1029 | |||
1030 | spin_lock(&base->lock); | ||
1031 | list_replace_init(&base->to_pull, &list); | ||
1032 | spin_unlock(&base->lock); | ||
1033 | |||
1034 | list_for_each_safe(pos, safe, &list) { | ||
1035 | info = list_entry(pos, struct hrtimer_start_on_info, list); | ||
1036 | TRACE("pulled timer 0x%x\n", info->timer); | ||
1037 | list_del(pos); | ||
1038 | hrtimer_start(info->timer, info->time, info->mode); | ||
1039 | } | ||
1040 | } | ||
1041 | |||
1042 | /** | ||
1043 | * hrtimer_start_on - trigger timer arming on remote cpu | ||
1044 | * @cpu: remote cpu | ||
1045 | * @info: save timer information for enqueuing on remote cpu | ||
1046 | * @timer: timer to be pulled | ||
1047 | * @time: expire time | ||
1048 | * @mode: timer mode | ||
1049 | */ | ||
1050 | int hrtimer_start_on(int cpu, struct hrtimer_start_on_info* info, | ||
1051 | struct hrtimer *timer, ktime_t time, | ||
1052 | const enum hrtimer_mode mode) | ||
1053 | { | ||
1054 | unsigned long flags; | ||
1055 | struct hrtimer_cpu_base* base; | ||
1056 | int in_use = 0, was_empty; | ||
1057 | |||
1058 | /* serialize access to info through the timer base */ | ||
1059 | lock_hrtimer_base(timer, &flags); | ||
1060 | |||
1061 | in_use = (atomic_read(&info->state) != HRTIMER_START_ON_INACTIVE); | ||
1062 | if (!in_use) { | ||
1063 | INIT_LIST_HEAD(&info->list); | ||
1064 | info->timer = timer; | ||
1065 | info->time = time; | ||
1066 | info->mode = mode; | ||
1067 | /* mark as in use */ | ||
1068 | atomic_set(&info->state, HRTIMER_START_ON_QUEUED); | ||
1069 | } | ||
1070 | |||
1071 | unlock_hrtimer_base(timer, &flags); | ||
1072 | |||
1073 | if (!in_use) { | ||
1074 | /* initiate pull */ | ||
1075 | preempt_disable(); | ||
1076 | if (cpu == smp_processor_id()) { | ||
1077 | /* start timer locally; we may get called | ||
1078 | * with rq->lock held, do not wake up anything | ||
1079 | */ | ||
1080 | __hrtimer_start_range_ns(info->timer, info->time, | ||
1081 | 0, info->mode, 0); | ||
1082 | } else { | ||
1083 | base = &per_cpu(hrtimer_bases, cpu); | ||
1084 | spin_lock_irqsave(&base->lock, flags); | ||
1085 | was_empty = list_empty(&base->to_pull); | ||
1086 | list_add(&info->list, &base->to_pull); | ||
1087 | spin_unlock_irqrestore(&base->lock, flags); | ||
1088 | if (was_empty) | ||
1089 | /* only send IPI if other no else | ||
1090 | * has done so already | ||
1091 | */ | ||
1092 | smp_send_pull_timers(cpu); | ||
1093 | } | ||
1094 | preempt_enable(); | ||
1095 | } | ||
1096 | return in_use; | ||
1097 | } | ||
1019 | 1098 | ||
1020 | /** | 1099 | /** |
1021 | * hrtimer_try_to_cancel - try to deactivate a timer | 1100 | * hrtimer_try_to_cancel - try to deactivate a timer |
@@ -1597,6 +1676,7 @@ static void __cpuinit init_hrtimers_cpu(int cpu) | |||
1597 | cpu_base->clock_base[i].cpu_base = cpu_base; | 1676 | cpu_base->clock_base[i].cpu_base = cpu_base; |
1598 | 1677 | ||
1599 | hrtimer_init_hres(cpu_base); | 1678 | hrtimer_init_hres(cpu_base); |
1679 | INIT_LIST_HEAD(&cpu_base->to_pull); | ||
1600 | } | 1680 | } |
1601 | 1681 | ||
1602 | #ifdef CONFIG_HOTPLUG_CPU | 1682 | #ifdef CONFIG_HOTPLUG_CPU |