diff options
| author | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2009-04-22 23:01:44 -0400 |
|---|---|---|
| committer | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2009-04-22 23:01:44 -0400 |
| commit | b5c4ababa76ce94cfa276f620b81d7d0f1d8ebf1 (patch) | |
| tree | bc8c705a7b1b8e11c6789cecb5f6d9c3be09dad0 /kernel/hrtimer.c | |
| parent | fc757f4223edfab215d6e49cee479a09ecc17962 (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.c | 67 |
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 | ||
| 816 | void 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 | |||
| 836 | int 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 |
