diff options
| author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-04-19 17:31:52 -0400 |
|---|---|---|
| committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-04-19 17:31:52 -0400 |
| commit | f70a290e8a889caa905ab7650c696f2bb299be1a (patch) | |
| tree | 56f0886d839499e9f522f189999024b3e86f9be2 /kernel | |
| parent | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (diff) | |
| parent | 7ef4a793a624c6e66c16ca1051847f75161f5bec (diff) | |
Merge branch 'wip-nested-locking' into tegra-nested-lockingwip-nested-locking
Conflicts:
Makefile
include/linux/fs.h
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/exit.c | 4 | ||||
| -rw-r--r-- | kernel/fork.c | 7 | ||||
| -rw-r--r-- | kernel/hrtimer.c | 95 | ||||
| -rw-r--r-- | kernel/printk.c | 14 | ||||
| -rw-r--r-- | kernel/sched.c | 152 | ||||
| -rw-r--r-- | kernel/sched_fair.c | 3 | ||||
| -rw-r--r-- | kernel/sched_rt.c | 15 | ||||
| -rw-r--r-- | kernel/softirq.c | 3 | ||||
| -rw-r--r-- | kernel/time/tick-sched.c | 47 |
9 files changed, 320 insertions, 20 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 9e316ae4984..9d13da8a8c2 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -57,6 +57,8 @@ | |||
| 57 | #include <asm/pgtable.h> | 57 | #include <asm/pgtable.h> |
| 58 | #include <asm/mmu_context.h> | 58 | #include <asm/mmu_context.h> |
| 59 | 59 | ||
| 60 | extern void exit_od_table(struct task_struct *t); | ||
| 61 | |||
| 60 | static void exit_mm(struct task_struct * tsk); | 62 | static void exit_mm(struct task_struct * tsk); |
| 61 | 63 | ||
| 62 | static void __unhash_process(struct task_struct *p, bool group_dead) | 64 | static void __unhash_process(struct task_struct *p, bool group_dead) |
| @@ -970,6 +972,8 @@ NORET_TYPE void do_exit(long code) | |||
| 970 | if (unlikely(tsk->audit_context)) | 972 | if (unlikely(tsk->audit_context)) |
| 971 | audit_free(tsk); | 973 | audit_free(tsk); |
| 972 | 974 | ||
| 975 | exit_od_table(tsk); | ||
| 976 | |||
| 973 | tsk->exit_code = code; | 977 | tsk->exit_code = code; |
| 974 | taskstats_exit(tsk, group_dead); | 978 | taskstats_exit(tsk, group_dead); |
| 975 | 979 | ||
diff --git a/kernel/fork.c b/kernel/fork.c index f65fa0627c0..067992d4838 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -76,6 +76,9 @@ | |||
| 76 | 76 | ||
| 77 | #include <trace/events/sched.h> | 77 | #include <trace/events/sched.h> |
| 78 | 78 | ||
| 79 | #include <litmus/litmus.h> | ||
| 80 | #include <litmus/sched_plugin.h> | ||
| 81 | |||
| 79 | /* | 82 | /* |
| 80 | * Protected counters by write_lock_irq(&tasklist_lock) | 83 | * Protected counters by write_lock_irq(&tasklist_lock) |
| 81 | */ | 84 | */ |
| @@ -205,6 +208,7 @@ void __put_task_struct(struct task_struct *tsk) | |||
| 205 | WARN_ON(atomic_read(&tsk->usage)); | 208 | WARN_ON(atomic_read(&tsk->usage)); |
| 206 | WARN_ON(tsk == current); | 209 | WARN_ON(tsk == current); |
| 207 | 210 | ||
| 211 | exit_litmus(tsk); | ||
| 208 | exit_creds(tsk); | 212 | exit_creds(tsk); |
| 209 | delayacct_tsk_free(tsk); | 213 | delayacct_tsk_free(tsk); |
| 210 | put_signal_struct(tsk->signal); | 214 | put_signal_struct(tsk->signal); |
| @@ -290,6 +294,9 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) | |||
| 290 | 294 | ||
| 291 | tsk->stack = ti; | 295 | tsk->stack = ti; |
| 292 | 296 | ||
| 297 | /* Don't let the new task be a real-time task. */ | ||
| 298 | litmus_fork(tsk); | ||
| 299 | |||
| 293 | err = prop_local_init_single(&tsk->dirties); | 300 | err = prop_local_init_single(&tsk->dirties); |
| 294 | if (err) | 301 | if (err) |
| 295 | goto out; | 302 | goto out; |
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 2043c08d36c..2391745f656 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> |
| @@ -1028,6 +1030,98 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode) | |||
| 1028 | } | 1030 | } |
| 1029 | EXPORT_SYMBOL_GPL(hrtimer_start); | 1031 | EXPORT_SYMBOL_GPL(hrtimer_start); |
| 1030 | 1032 | ||
| 1033 | #ifdef CONFIG_ARCH_HAS_SEND_PULL_TIMERS | ||
| 1034 | |||
| 1035 | /** | ||
| 1036 | * hrtimer_start_on_info_init - Initialize hrtimer_start_on_info | ||
| 1037 | */ | ||
| 1038 | void hrtimer_start_on_info_init(struct hrtimer_start_on_info *info) | ||
| 1039 | { | ||
| 1040 | memset(info, 0, sizeof(struct hrtimer_start_on_info)); | ||
| 1041 | atomic_set(&info->state, HRTIMER_START_ON_INACTIVE); | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | /** | ||
| 1045 | * hrtimer_pull - PULL_TIMERS_VECTOR callback on remote cpu | ||
| 1046 | */ | ||
| 1047 | void hrtimer_pull(void) | ||
| 1048 | { | ||
| 1049 | struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases); | ||
| 1050 | struct hrtimer_start_on_info *info; | ||
| 1051 | struct list_head *pos, *safe, list; | ||
| 1052 | |||
| 1053 | raw_spin_lock(&base->lock); | ||
| 1054 | list_replace_init(&base->to_pull, &list); | ||
| 1055 | raw_spin_unlock(&base->lock); | ||
| 1056 | |||
| 1057 | list_for_each_safe(pos, safe, &list) { | ||
| 1058 | info = list_entry(pos, struct hrtimer_start_on_info, list); | ||
| 1059 | TRACE("pulled timer 0x%x\n", info->timer); | ||
| 1060 | list_del(pos); | ||
| 1061 | hrtimer_start(info->timer, info->time, info->mode); | ||
| 1062 | } | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | /** | ||
| 1066 | * hrtimer_start_on - trigger timer arming on remote cpu | ||
| 1067 | * @cpu: remote cpu | ||
| 1068 | * @info: save timer information for enqueuing on remote cpu | ||
| 1069 | * @timer: timer to be pulled | ||
| 1070 | * @time: expire time | ||
| 1071 | * @mode: timer mode | ||
| 1072 | */ | ||
| 1073 | int hrtimer_start_on(int cpu, struct hrtimer_start_on_info* info, | ||
| 1074 | struct hrtimer *timer, ktime_t time, | ||
| 1075 | const enum hrtimer_mode mode) | ||
| 1076 | { | ||
| 1077 | unsigned long flags; | ||
| 1078 | struct hrtimer_cpu_base* base; | ||
| 1079 | int in_use = 0, was_empty; | ||
| 1080 | |||
| 1081 | /* serialize access to info through the timer base */ | ||
| 1082 | lock_hrtimer_base(timer, &flags); | ||
| 1083 | |||
| 1084 | in_use = (atomic_read(&info->state) != HRTIMER_START_ON_INACTIVE); | ||
| 1085 | if (!in_use) { | ||
| 1086 | INIT_LIST_HEAD(&info->list); | ||
| 1087 | info->timer = timer; | ||
| 1088 | info->time = time; | ||
| 1089 | info->mode = mode; | ||
| 1090 | /* mark as in use */ | ||
| 1091 | atomic_set(&info->state, HRTIMER_START_ON_QUEUED); | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | unlock_hrtimer_base(timer, &flags); | ||
| 1095 | |||
| 1096 | if (!in_use) { | ||
| 1097 | /* initiate pull */ | ||
| 1098 | preempt_disable(); | ||
| 1099 | if (cpu == smp_processor_id()) { | ||
| 1100 | /* start timer locally; we may get called | ||
| 1101 | * with rq->lock held, do not wake up anything | ||
| 1102 | */ | ||
| 1103 | TRACE("hrtimer_start_on: starting on local CPU\n"); | ||
| 1104 | __hrtimer_start_range_ns(info->timer, info->time, | ||
| 1105 | 0, info->mode, 0); | ||
| 1106 | } else { | ||
| 1107 | TRACE("hrtimer_start_on: pulling to remote CPU\n"); | ||
| 1108 | base = &per_cpu(hrtimer_bases, cpu); | ||
| 1109 | raw_spin_lock_irqsave(&base->lock, flags); | ||
| 1110 | was_empty = list_empty(&base->to_pull); | ||
| 1111 | list_add(&info->list, &base->to_pull); | ||
| 1112 | raw_spin_unlock_irqrestore(&base->lock, flags); | ||
| 1113 | if (was_empty) | ||
| 1114 | /* only send IPI if other no else | ||
| 1115 | * has done so already | ||
| 1116 | */ | ||
| 1117 | smp_send_pull_timers(cpu); | ||
| 1118 | } | ||
| 1119 | preempt_enable(); | ||
| 1120 | } | ||
| 1121 | return in_use; | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | #endif | ||
| 1031 | 1125 | ||
| 1032 | /** | 1126 | /** |
| 1033 | * hrtimer_try_to_cancel - try to deactivate a timer | 1127 | * hrtimer_try_to_cancel - try to deactivate a timer |
| @@ -1627,6 +1721,7 @@ static void __cpuinit init_hrtimers_cpu(int cpu) | |||
| 1627 | } | 1721 | } |
| 1628 | 1722 | ||
| 1629 | hrtimer_init_hres(cpu_base); | 1723 | hrtimer_init_hres(cpu_base); |
| 1724 | INIT_LIST_HEAD(&cpu_base->to_pull); | ||
| 1630 | } | 1725 | } |
| 1631 | 1726 | ||
| 1632 | #ifdef CONFIG_HOTPLUG_CPU | 1727 | #ifdef CONFIG_HOTPLUG_CPU |
diff --git a/kernel/printk.c b/kernel/printk.c index 1baace7d867..cbebc142be1 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
| @@ -74,6 +74,13 @@ int console_printk[4] = { | |||
| 74 | }; | 74 | }; |
| 75 | 75 | ||
| 76 | /* | 76 | /* |
| 77 | * divert printk() messages when there is a LITMUS^RT debug listener | ||
| 78 | */ | ||
| 79 | #include <litmus/litmus.h> | ||
| 80 | int trace_override = 0; | ||
| 81 | int trace_recurse = 0; | ||
| 82 | |||
| 83 | /* | ||
| 77 | * Low level drivers may need that to know if they can schedule in | 84 | * Low level drivers may need that to know if they can schedule in |
| 78 | * their unblank() callback or not. So let's export it. | 85 | * their unblank() callback or not. So let's export it. |
| 79 | */ | 86 | */ |
| @@ -926,6 +933,9 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
| 926 | /* Emit the output into the temporary buffer */ | 933 | /* Emit the output into the temporary buffer */ |
| 927 | printed_len += vscnprintf(printk_buf + printed_len, | 934 | printed_len += vscnprintf(printk_buf + printed_len, |
| 928 | sizeof(printk_buf) - printed_len, fmt, args); | 935 | sizeof(printk_buf) - printed_len, fmt, args); |
| 936 | /* if LITMUS^RT tracer is active divert printk() msgs */ | ||
| 937 | if (trace_override && !trace_recurse) | ||
| 938 | TRACE("%s", printk_buf); | ||
| 929 | 939 | ||
| 930 | #ifdef CONFIG_DEBUG_LL | 940 | #ifdef CONFIG_DEBUG_LL |
| 931 | printascii(printk_buf); | 941 | printascii(printk_buf); |
| @@ -1006,7 +1016,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
| 1006 | * Try to acquire and then immediately release the | 1016 | * Try to acquire and then immediately release the |
| 1007 | * console semaphore. The release will do all the | 1017 | * console semaphore. The release will do all the |
| 1008 | * actual magic (print out buffers, wake up klogd, | 1018 | * actual magic (print out buffers, wake up klogd, |
| 1009 | * etc). | 1019 | * etc). |
| 1010 | * | 1020 | * |
| 1011 | * The console_trylock_for_printk() function | 1021 | * The console_trylock_for_printk() function |
| 1012 | * will release 'logbuf_lock' regardless of whether it | 1022 | * will release 'logbuf_lock' regardless of whether it |
| @@ -1278,7 +1288,7 @@ int printk_needs_cpu(int cpu) | |||
| 1278 | 1288 | ||
| 1279 | void wake_up_klogd(void) | 1289 | void wake_up_klogd(void) |
| 1280 | { | 1290 | { |
| 1281 | if (waitqueue_active(&log_wait)) | 1291 | if (!trace_override && waitqueue_active(&log_wait)) |
| 1282 | this_cpu_write(printk_pending, 1); | 1292 | this_cpu_write(printk_pending, 1); |
| 1283 | } | 1293 | } |
| 1284 | 1294 | ||
diff --git a/kernel/sched.c b/kernel/sched.c index f6cf5cbc64b..a1bf2646d12 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
| @@ -87,6 +87,11 @@ | |||
| 87 | #define CREATE_TRACE_POINTS | 87 | #define CREATE_TRACE_POINTS |
| 88 | #include <trace/events/sched.h> | 88 | #include <trace/events/sched.h> |
| 89 | 89 | ||
| 90 | #include <litmus/sched_trace.h> | ||
| 91 | #include <litmus/trace.h> | ||
| 92 | |||
| 93 | static void litmus_tick(struct rq*, struct task_struct*); | ||
| 94 | |||
| 90 | /* | 95 | /* |
| 91 | * Convert user-nice values [ -20 ... 0 ... 19 ] | 96 | * Convert user-nice values [ -20 ... 0 ... 19 ] |
| 92 | * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ], | 97 | * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ], |
| @@ -414,6 +419,12 @@ struct rt_rq { | |||
| 414 | #endif | 419 | #endif |
| 415 | }; | 420 | }; |
| 416 | 421 | ||
| 422 | /* Litmus related fields in a runqueue */ | ||
| 423 | struct litmus_rq { | ||
| 424 | unsigned long nr_running; | ||
| 425 | struct task_struct *prev; | ||
| 426 | }; | ||
| 427 | |||
| 417 | #ifdef CONFIG_SMP | 428 | #ifdef CONFIG_SMP |
| 418 | 429 | ||
| 419 | /* | 430 | /* |
| @@ -479,6 +490,7 @@ struct rq { | |||
| 479 | 490 | ||
| 480 | struct cfs_rq cfs; | 491 | struct cfs_rq cfs; |
| 481 | struct rt_rq rt; | 492 | struct rt_rq rt; |
| 493 | struct litmus_rq litmus; | ||
| 482 | 494 | ||
| 483 | #ifdef CONFIG_FAIR_GROUP_SCHED | 495 | #ifdef CONFIG_FAIR_GROUP_SCHED |
| 484 | /* list of leaf cfs_rq on this cpu: */ | 496 | /* list of leaf cfs_rq on this cpu: */ |
| @@ -1054,6 +1066,7 @@ static enum hrtimer_restart hrtick(struct hrtimer *timer) | |||
| 1054 | raw_spin_lock(&rq->lock); | 1066 | raw_spin_lock(&rq->lock); |
| 1055 | update_rq_clock(rq); | 1067 | update_rq_clock(rq); |
| 1056 | rq->curr->sched_class->task_tick(rq, rq->curr, 1); | 1068 | rq->curr->sched_class->task_tick(rq, rq->curr, 1); |
| 1069 | litmus_tick(rq, rq->curr); | ||
| 1057 | raw_spin_unlock(&rq->lock); | 1070 | raw_spin_unlock(&rq->lock); |
| 1058 | 1071 | ||
| 1059 | return HRTIMER_NORESTART; | 1072 | return HRTIMER_NORESTART; |
| @@ -1750,7 +1763,7 @@ static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu) | |||
| 1750 | 1763 | ||
| 1751 | static const struct sched_class rt_sched_class; | 1764 | static const struct sched_class rt_sched_class; |
| 1752 | 1765 | ||
| 1753 | #define sched_class_highest (&stop_sched_class) | 1766 | #define sched_class_highest (&litmus_sched_class) |
| 1754 | #define for_each_class(class) \ | 1767 | #define for_each_class(class) \ |
| 1755 | for (class = sched_class_highest; class; class = class->next) | 1768 | for (class = sched_class_highest; class; class = class->next) |
| 1756 | 1769 | ||
| @@ -2044,6 +2057,7 @@ static int irqtime_account_si_update(void) | |||
| 2044 | #include "sched_rt.c" | 2057 | #include "sched_rt.c" |
| 2045 | #include "sched_autogroup.c" | 2058 | #include "sched_autogroup.c" |
| 2046 | #include "sched_stoptask.c" | 2059 | #include "sched_stoptask.c" |
| 2060 | #include "../litmus/sched_litmus.c" | ||
| 2047 | #ifdef CONFIG_SCHED_DEBUG | 2061 | #ifdef CONFIG_SCHED_DEBUG |
| 2048 | # include "sched_debug.c" | 2062 | # include "sched_debug.c" |
| 2049 | #endif | 2063 | #endif |
| @@ -2166,6 +2180,10 @@ static void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags) | |||
| 2166 | * A queue event has occurred, and we're going to schedule. In | 2180 | * A queue event has occurred, and we're going to schedule. In |
| 2167 | * this case, we can save a useless back to back clock update. | 2181 | * this case, we can save a useless back to back clock update. |
| 2168 | */ | 2182 | */ |
| 2183 | /* LITMUS^RT: | ||
| 2184 | * The "disable-clock-update" approach was buggy in Linux 2.6.36. | ||
| 2185 | * The issue has been solved in 2.6.37. | ||
| 2186 | */ | ||
| 2169 | if (rq->curr->on_rq && test_tsk_need_resched(rq->curr)) | 2187 | if (rq->curr->on_rq && test_tsk_need_resched(rq->curr)) |
| 2170 | rq->skip_clock_update = 1; | 2188 | rq->skip_clock_update = 1; |
| 2171 | } | 2189 | } |
| @@ -2592,8 +2610,12 @@ void scheduler_ipi(void) | |||
| 2592 | struct rq *rq = this_rq(); | 2610 | struct rq *rq = this_rq(); |
| 2593 | struct task_struct *list = xchg(&rq->wake_list, NULL); | 2611 | struct task_struct *list = xchg(&rq->wake_list, NULL); |
| 2594 | 2612 | ||
| 2595 | if (!list) | 2613 | if (!list) { |
| 2614 | /* If we don't call irq_enter(), we need to trigger the IRQ | ||
| 2615 | * tracing manually. */ | ||
| 2616 | ft_irq_fired(); | ||
| 2596 | return; | 2617 | return; |
| 2618 | } | ||
| 2597 | 2619 | ||
| 2598 | /* | 2620 | /* |
| 2599 | * Not all reschedule IPI handlers call irq_enter/irq_exit, since | 2621 | * Not all reschedule IPI handlers call irq_enter/irq_exit, since |
| @@ -2656,7 +2678,12 @@ static void ttwu_queue(struct task_struct *p, int cpu) | |||
| 2656 | struct rq *rq = cpu_rq(cpu); | 2678 | struct rq *rq = cpu_rq(cpu); |
| 2657 | 2679 | ||
| 2658 | #if defined(CONFIG_SMP) | 2680 | #if defined(CONFIG_SMP) |
| 2659 | if (sched_feat(TTWU_QUEUE) && cpu != smp_processor_id()) { | 2681 | /* |
| 2682 | * LITMUS^RT: whether to send an IPI to the remote CPU | ||
| 2683 | * is plugin specific. | ||
| 2684 | */ | ||
| 2685 | if (!is_realtime(p) && | ||
| 2686 | sched_feat(TTWU_QUEUE) && cpu != smp_processor_id()) { | ||
| 2660 | sched_clock_cpu(cpu); /* sync clocks x-cpu */ | 2687 | sched_clock_cpu(cpu); /* sync clocks x-cpu */ |
| 2661 | ttwu_queue_remote(p, cpu); | 2688 | ttwu_queue_remote(p, cpu); |
| 2662 | return; | 2689 | return; |
| @@ -2689,6 +2716,9 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) | |||
| 2689 | unsigned long flags; | 2716 | unsigned long flags; |
| 2690 | int cpu, success = 0; | 2717 | int cpu, success = 0; |
| 2691 | 2718 | ||
| 2719 | if (is_realtime(p)) | ||
| 2720 | TRACE_TASK(p, "try_to_wake_up() state:%d\n", p->state); | ||
| 2721 | |||
| 2692 | smp_wmb(); | 2722 | smp_wmb(); |
| 2693 | raw_spin_lock_irqsave(&p->pi_lock, flags); | 2723 | raw_spin_lock_irqsave(&p->pi_lock, flags); |
| 2694 | if (!(p->state & state)) | 2724 | if (!(p->state & state)) |
| @@ -2725,6 +2755,12 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) | |||
| 2725 | */ | 2755 | */ |
| 2726 | smp_rmb(); | 2756 | smp_rmb(); |
| 2727 | 2757 | ||
| 2758 | /* LITMUS^RT: once the task can be safely referenced by this | ||
| 2759 | * CPU, don't mess up with Linux load balancing stuff. | ||
| 2760 | */ | ||
| 2761 | if (is_realtime(p)) | ||
| 2762 | goto litmus_out_activate; | ||
| 2763 | |||
| 2728 | p->sched_contributes_to_load = !!task_contributes_to_load(p); | 2764 | p->sched_contributes_to_load = !!task_contributes_to_load(p); |
| 2729 | p->state = TASK_WAKING; | 2765 | p->state = TASK_WAKING; |
| 2730 | 2766 | ||
| @@ -2736,12 +2772,16 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) | |||
| 2736 | wake_flags |= WF_MIGRATED; | 2772 | wake_flags |= WF_MIGRATED; |
| 2737 | set_task_cpu(p, cpu); | 2773 | set_task_cpu(p, cpu); |
| 2738 | } | 2774 | } |
| 2775 | |||
| 2776 | litmus_out_activate: | ||
| 2739 | #endif /* CONFIG_SMP */ | 2777 | #endif /* CONFIG_SMP */ |
| 2740 | 2778 | ||
| 2741 | ttwu_queue(p, cpu); | 2779 | ttwu_queue(p, cpu); |
| 2742 | stat: | 2780 | stat: |
| 2743 | ttwu_stat(p, cpu, wake_flags); | 2781 | ttwu_stat(p, cpu, wake_flags); |
| 2744 | out: | 2782 | out: |
| 2783 | if (is_realtime(p)) | ||
| 2784 | TRACE_TASK(p, "try_to_wake_up() done state:%d\n", p->state); | ||
| 2745 | raw_spin_unlock_irqrestore(&p->pi_lock, flags); | 2785 | raw_spin_unlock_irqrestore(&p->pi_lock, flags); |
| 2746 | 2786 | ||
| 2747 | return success; | 2787 | return success; |
| @@ -2852,7 +2892,8 @@ void sched_fork(struct task_struct *p) | |||
| 2852 | * Revert to default priority/policy on fork if requested. | 2892 | * Revert to default priority/policy on fork if requested. |
| 2853 | */ | 2893 | */ |
| 2854 | if (unlikely(p->sched_reset_on_fork)) { | 2894 | if (unlikely(p->sched_reset_on_fork)) { |
| 2855 | if (p->policy == SCHED_FIFO || p->policy == SCHED_RR) { | 2895 | if (p->policy == SCHED_FIFO || p->policy == SCHED_RR || |
| 2896 | p->policy == SCHED_LITMUS) { | ||
| 2856 | p->policy = SCHED_NORMAL; | 2897 | p->policy = SCHED_NORMAL; |
| 2857 | p->normal_prio = p->static_prio; | 2898 | p->normal_prio = p->static_prio; |
| 2858 | } | 2899 | } |
| @@ -3063,6 +3104,8 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev) | |||
| 3063 | */ | 3104 | */ |
| 3064 | prev_state = prev->state; | 3105 | prev_state = prev->state; |
| 3065 | finish_arch_switch(prev); | 3106 | finish_arch_switch(prev); |
| 3107 | litmus->finish_switch(prev); | ||
| 3108 | prev->rt_param.stack_in_use = NO_CPU; | ||
| 3066 | #ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW | 3109 | #ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW |
| 3067 | local_irq_disable(); | 3110 | local_irq_disable(); |
| 3068 | #endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */ | 3111 | #endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */ |
| @@ -3092,6 +3135,15 @@ static inline void pre_schedule(struct rq *rq, struct task_struct *prev) | |||
| 3092 | { | 3135 | { |
| 3093 | if (prev->sched_class->pre_schedule) | 3136 | if (prev->sched_class->pre_schedule) |
| 3094 | prev->sched_class->pre_schedule(rq, prev); | 3137 | prev->sched_class->pre_schedule(rq, prev); |
| 3138 | |||
| 3139 | /* LITMUS^RT not very clean hack: we need to save the prev task | ||
| 3140 | * as our scheduling decision rely on it (as we drop the rq lock | ||
| 3141 | * something in prev can change...); there is no way to escape | ||
| 3142 | * this ack apart from modifying pick_nex_task(rq, _prev_) or | ||
| 3143 | * falling back on the previous solution of decoupling | ||
| 3144 | * scheduling decisions | ||
| 3145 | */ | ||
| 3146 | rq->litmus.prev = prev; | ||
| 3095 | } | 3147 | } |
| 3096 | 3148 | ||
| 3097 | /* rq->lock is NOT held, but preemption is disabled */ | 3149 | /* rq->lock is NOT held, but preemption is disabled */ |
| @@ -3128,16 +3180,26 @@ static inline void post_schedule(struct rq *rq) | |||
| 3128 | asmlinkage void schedule_tail(struct task_struct *prev) | 3180 | asmlinkage void schedule_tail(struct task_struct *prev) |
| 3129 | __releases(rq->lock) | 3181 | __releases(rq->lock) |
| 3130 | { | 3182 | { |
| 3131 | struct rq *rq = this_rq(); | 3183 | struct rq *rq; |
| 3132 | 3184 | ||
| 3185 | preempt_disable(); | ||
| 3186 | |||
| 3187 | rq = this_rq(); | ||
| 3133 | finish_task_switch(rq, prev); | 3188 | finish_task_switch(rq, prev); |
| 3134 | 3189 | ||
| 3190 | sched_trace_task_switch_to(current); | ||
| 3191 | |||
| 3135 | /* | 3192 | /* |
| 3136 | * FIXME: do we need to worry about rq being invalidated by the | 3193 | * FIXME: do we need to worry about rq being invalidated by the |
| 3137 | * task_switch? | 3194 | * task_switch? |
| 3138 | */ | 3195 | */ |
| 3139 | post_schedule(rq); | 3196 | post_schedule(rq); |
| 3140 | 3197 | ||
| 3198 | if (sched_state_validate_switch()) | ||
| 3199 | litmus_reschedule_local(); | ||
| 3200 | |||
| 3201 | preempt_enable(); | ||
| 3202 | |||
| 3141 | #ifdef __ARCH_WANT_UNLOCKED_CTXSW | 3203 | #ifdef __ARCH_WANT_UNLOCKED_CTXSW |
| 3142 | /* In this case, finish_task_switch does not reenable preemption */ | 3204 | /* In this case, finish_task_switch does not reenable preemption */ |
| 3143 | preempt_enable(); | 3205 | preempt_enable(); |
| @@ -4108,18 +4170,26 @@ void scheduler_tick(void) | |||
| 4108 | 4170 | ||
| 4109 | sched_clock_tick(); | 4171 | sched_clock_tick(); |
| 4110 | 4172 | ||
| 4173 | TS_TICK_START(current); | ||
| 4174 | |||
| 4111 | raw_spin_lock(&rq->lock); | 4175 | raw_spin_lock(&rq->lock); |
| 4112 | update_rq_clock(rq); | 4176 | update_rq_clock(rq); |
| 4113 | update_cpu_load_active(rq); | 4177 | update_cpu_load_active(rq); |
| 4114 | curr->sched_class->task_tick(rq, curr, 0); | 4178 | curr->sched_class->task_tick(rq, curr, 0); |
| 4179 | |||
| 4180 | /* litmus_tick may force current to resched */ | ||
| 4181 | litmus_tick(rq, curr); | ||
| 4182 | |||
| 4115 | raw_spin_unlock(&rq->lock); | 4183 | raw_spin_unlock(&rq->lock); |
| 4116 | 4184 | ||
| 4117 | perf_event_task_tick(); | 4185 | perf_event_task_tick(); |
| 4118 | 4186 | ||
| 4119 | #ifdef CONFIG_SMP | 4187 | #ifdef CONFIG_SMP |
| 4120 | rq->idle_at_tick = idle_cpu(cpu); | 4188 | rq->idle_at_tick = idle_cpu(cpu); |
| 4121 | trigger_load_balance(rq, cpu); | 4189 | if (!is_realtime(current)) |
| 4190 | trigger_load_balance(rq, cpu); | ||
| 4122 | #endif | 4191 | #endif |
| 4192 | TS_TICK_END(current); | ||
| 4123 | } | 4193 | } |
| 4124 | 4194 | ||
| 4125 | notrace unsigned long get_parent_ip(unsigned long addr) | 4195 | notrace unsigned long get_parent_ip(unsigned long addr) |
| @@ -4239,12 +4309,20 @@ pick_next_task(struct rq *rq) | |||
| 4239 | /* | 4309 | /* |
| 4240 | * Optimization: we know that if all tasks are in | 4310 | * Optimization: we know that if all tasks are in |
| 4241 | * the fair class we can call that function directly: | 4311 | * the fair class we can call that function directly: |
| 4242 | */ | 4312 | |
| 4243 | if (likely(rq->nr_running == rq->cfs.nr_running)) { | 4313 | * NOT IN LITMUS^RT! |
| 4314 | |||
| 4315 | * This breaks many assumptions in the plugins. | ||
| 4316 | * Do not uncomment without thinking long and hard | ||
| 4317 | * about how this affects global plugins such as GSN-EDF. | ||
| 4318 | |||
| 4319 | if (rq->nr_running == rq->cfs.nr_running) { | ||
| 4320 | TRACE("taking shortcut in pick_next_task()\n"); | ||
| 4244 | p = fair_sched_class.pick_next_task(rq); | 4321 | p = fair_sched_class.pick_next_task(rq); |
| 4245 | if (likely(p)) | 4322 | if (likely(p)) |
| 4246 | return p; | 4323 | return p; |
| 4247 | } | 4324 | } |
| 4325 | */ | ||
| 4248 | 4326 | ||
| 4249 | for_each_class(class) { | 4327 | for_each_class(class) { |
| 4250 | p = class->pick_next_task(rq); | 4328 | p = class->pick_next_task(rq); |
| @@ -4267,11 +4345,19 @@ static void __sched __schedule(void) | |||
| 4267 | 4345 | ||
| 4268 | need_resched: | 4346 | need_resched: |
| 4269 | preempt_disable(); | 4347 | preempt_disable(); |
| 4348 | sched_state_entered_schedule(); | ||
| 4270 | cpu = smp_processor_id(); | 4349 | cpu = smp_processor_id(); |
| 4271 | rq = cpu_rq(cpu); | 4350 | rq = cpu_rq(cpu); |
| 4272 | rcu_note_context_switch(cpu); | 4351 | rcu_note_context_switch(cpu); |
| 4273 | prev = rq->curr; | 4352 | prev = rq->curr; |
| 4274 | 4353 | ||
| 4354 | /* LITMUS^RT: quickly re-evaluate the scheduling decision | ||
| 4355 | * if the previous one is no longer valid after CTX. | ||
| 4356 | */ | ||
| 4357 | litmus_need_resched_nonpreemptible: | ||
| 4358 | TS_SCHED_START; | ||
| 4359 | sched_trace_task_switch_away(prev); | ||
| 4360 | |||
| 4275 | schedule_debug(prev); | 4361 | schedule_debug(prev); |
| 4276 | 4362 | ||
| 4277 | if (sched_feat(HRTICK)) | 4363 | if (sched_feat(HRTICK)) |
| @@ -4318,7 +4404,10 @@ need_resched: | |||
| 4318 | rq->curr = next; | 4404 | rq->curr = next; |
| 4319 | ++*switch_count; | 4405 | ++*switch_count; |
| 4320 | 4406 | ||
| 4407 | TS_SCHED_END(next); | ||
| 4408 | TS_CXS_START(next); | ||
| 4321 | context_switch(rq, prev, next); /* unlocks the rq */ | 4409 | context_switch(rq, prev, next); /* unlocks the rq */ |
| 4410 | TS_CXS_END(current); | ||
| 4322 | /* | 4411 | /* |
| 4323 | * The context switch have flipped the stack from under us | 4412 | * The context switch have flipped the stack from under us |
| 4324 | * and restored the local variables which were saved when | 4413 | * and restored the local variables which were saved when |
| @@ -4327,14 +4416,29 @@ need_resched: | |||
| 4327 | */ | 4416 | */ |
| 4328 | cpu = smp_processor_id(); | 4417 | cpu = smp_processor_id(); |
| 4329 | rq = cpu_rq(cpu); | 4418 | rq = cpu_rq(cpu); |
| 4330 | } else | 4419 | } else { |
| 4420 | TS_SCHED_END(prev); | ||
| 4331 | raw_spin_unlock_irq(&rq->lock); | 4421 | raw_spin_unlock_irq(&rq->lock); |
| 4422 | } | ||
| 4423 | |||
| 4424 | TS_SCHED2_START(prev); | ||
| 4425 | sched_trace_task_switch_to(current); | ||
| 4332 | 4426 | ||
| 4333 | post_schedule(rq); | 4427 | post_schedule(rq); |
| 4334 | 4428 | ||
| 4429 | if (sched_state_validate_switch()) { | ||
| 4430 | TS_SCHED2_END(prev); | ||
| 4431 | goto litmus_need_resched_nonpreemptible; | ||
| 4432 | } | ||
| 4433 | |||
| 4335 | preempt_enable_no_resched(); | 4434 | preempt_enable_no_resched(); |
| 4435 | |||
| 4436 | TS_SCHED2_END(prev); | ||
| 4437 | |||
| 4336 | if (need_resched()) | 4438 | if (need_resched()) |
| 4337 | goto need_resched; | 4439 | goto need_resched; |
| 4440 | |||
| 4441 | srp_ceiling_block(); | ||
| 4338 | } | 4442 | } |
| 4339 | 4443 | ||
| 4340 | static inline void sched_submit_work(struct task_struct *tsk) | 4444 | static inline void sched_submit_work(struct task_struct *tsk) |
| @@ -5056,7 +5160,9 @@ __setscheduler(struct rq *rq, struct task_struct *p, int policy, int prio) | |||
| 5056 | p->normal_prio = normal_prio(p); | 5160 | p->normal_prio = normal_prio(p); |
| 5057 | /* we are holding p->pi_lock already */ | 5161 | /* we are holding p->pi_lock already */ |
| 5058 | p->prio = rt_mutex_getprio(p); | 5162 | p->prio = rt_mutex_getprio(p); |
| 5059 | if (rt_prio(p->prio)) | 5163 | if (p->policy == SCHED_LITMUS) |
| 5164 | p->sched_class = &litmus_sched_class; | ||
| 5165 | else if (rt_prio(p->prio)) | ||
| 5060 | p->sched_class = &rt_sched_class; | 5166 | p->sched_class = &rt_sched_class; |
| 5061 | else | 5167 | else |
| 5062 | p->sched_class = &fair_sched_class; | 5168 | p->sched_class = &fair_sched_class; |
| @@ -5104,7 +5210,7 @@ recheck: | |||
| 5104 | 5210 | ||
| 5105 | if (policy != SCHED_FIFO && policy != SCHED_RR && | 5211 | if (policy != SCHED_FIFO && policy != SCHED_RR && |
| 5106 | policy != SCHED_NORMAL && policy != SCHED_BATCH && | 5212 | policy != SCHED_NORMAL && policy != SCHED_BATCH && |
| 5107 | policy != SCHED_IDLE) | 5213 | policy != SCHED_IDLE && policy != SCHED_LITMUS) |
| 5108 | return -EINVAL; | 5214 | return -EINVAL; |
| 5109 | } | 5215 | } |
| 5110 | 5216 | ||
| @@ -5119,6 +5225,8 @@ recheck: | |||
| 5119 | return -EINVAL; | 5225 | return -EINVAL; |
| 5120 | if (rt_policy(policy) != (param->sched_priority != 0)) | 5226 | if (rt_policy(policy) != (param->sched_priority != 0)) |
| 5121 | return -EINVAL; | 5227 | return -EINVAL; |
| 5228 | if (policy == SCHED_LITMUS && policy == p->policy) | ||
| 5229 | return -EINVAL; | ||
| 5122 | 5230 | ||
| 5123 | /* | 5231 | /* |
| 5124 | * Allow unprivileged RT tasks to decrease priority: | 5232 | * Allow unprivileged RT tasks to decrease priority: |
| @@ -5162,6 +5270,12 @@ recheck: | |||
| 5162 | return retval; | 5270 | return retval; |
| 5163 | } | 5271 | } |
| 5164 | 5272 | ||
| 5273 | if (policy == SCHED_LITMUS) { | ||
| 5274 | retval = litmus_admit_task(p); | ||
| 5275 | if (retval) | ||
| 5276 | return retval; | ||
| 5277 | } | ||
| 5278 | |||
| 5165 | /* | 5279 | /* |
| 5166 | * make sure no PI-waiters arrive (or leave) while we are | 5280 | * make sure no PI-waiters arrive (or leave) while we are |
| 5167 | * changing the priority of the task: | 5281 | * changing the priority of the task: |
| @@ -5220,10 +5334,19 @@ recheck: | |||
| 5220 | 5334 | ||
| 5221 | p->sched_reset_on_fork = reset_on_fork; | 5335 | p->sched_reset_on_fork = reset_on_fork; |
| 5222 | 5336 | ||
| 5337 | if (p->policy == SCHED_LITMUS) | ||
| 5338 | litmus_exit_task(p); | ||
| 5339 | |||
| 5223 | oldprio = p->prio; | 5340 | oldprio = p->prio; |
| 5224 | prev_class = p->sched_class; | 5341 | prev_class = p->sched_class; |
| 5225 | __setscheduler(rq, p, policy, param->sched_priority); | 5342 | __setscheduler(rq, p, policy, param->sched_priority); |
| 5226 | 5343 | ||
| 5344 | if (policy == SCHED_LITMUS) { | ||
| 5345 | p->rt_param.stack_in_use = running ? rq->cpu : NO_CPU; | ||
| 5346 | p->rt_param.present = running; | ||
| 5347 | litmus->task_new(p, on_rq, running); | ||
| 5348 | } | ||
| 5349 | |||
| 5227 | if (running) | 5350 | if (running) |
| 5228 | p->sched_class->set_curr_task(rq); | 5351 | p->sched_class->set_curr_task(rq); |
| 5229 | if (on_rq) | 5352 | if (on_rq) |
| @@ -5391,10 +5514,11 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask) | |||
| 5391 | rcu_read_lock(); | 5514 | rcu_read_lock(); |
| 5392 | 5515 | ||
| 5393 | p = find_process_by_pid(pid); | 5516 | p = find_process_by_pid(pid); |
| 5394 | if (!p) { | 5517 | /* Don't set affinity if task not found and for LITMUS tasks */ |
| 5518 | if (!p || is_realtime(p)) { | ||
| 5395 | rcu_read_unlock(); | 5519 | rcu_read_unlock(); |
| 5396 | put_online_cpus(); | 5520 | put_online_cpus(); |
| 5397 | return -ESRCH; | 5521 | return p ? -EPERM : -ESRCH; |
| 5398 | } | 5522 | } |
| 5399 | 5523 | ||
| 5400 | /* Prevent p going away */ | 5524 | /* Prevent p going away */ |
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index bc8ee999381..22999b257ad 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c | |||
| @@ -1872,6 +1872,9 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ | |||
| 1872 | int scale = cfs_rq->nr_running >= sched_nr_latency; | 1872 | int scale = cfs_rq->nr_running >= sched_nr_latency; |
| 1873 | int next_buddy_marked = 0; | 1873 | int next_buddy_marked = 0; |
| 1874 | 1874 | ||
| 1875 | if (unlikely(rt_prio(p->prio)) || p->policy == SCHED_LITMUS) | ||
| 1876 | goto preempt; | ||
| 1877 | |||
| 1875 | if (unlikely(se == pse)) | 1878 | if (unlikely(se == pse)) |
| 1876 | return; | 1879 | return; |
| 1877 | 1880 | ||
diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index af1177858be..b827550a0d0 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | * policies) | 3 | * policies) |
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | #include <litmus/litmus.h> | ||
| 7 | |||
| 6 | #ifdef CONFIG_RT_GROUP_SCHED | 8 | #ifdef CONFIG_RT_GROUP_SCHED |
| 7 | 9 | ||
| 8 | #define rt_entity_is_task(rt_se) (!(rt_se)->my_q) | 10 | #define rt_entity_is_task(rt_se) (!(rt_se)->my_q) |
| @@ -240,8 +242,11 @@ static void sched_rt_rq_enqueue(struct rt_rq *rt_rq) | |||
| 240 | if (rt_rq->rt_nr_running) { | 242 | if (rt_rq->rt_nr_running) { |
| 241 | if (rt_se && !on_rt_rq(rt_se)) | 243 | if (rt_se && !on_rt_rq(rt_se)) |
| 242 | enqueue_rt_entity(rt_se, false); | 244 | enqueue_rt_entity(rt_se, false); |
| 243 | if (rt_rq->highest_prio.curr < curr->prio) | 245 | if (rt_rq->highest_prio.curr < curr->prio && |
| 246 | /* Don't subject LITMUS tasks to remote reschedules */ | ||
| 247 | !is_realtime(curr)) { | ||
| 244 | resched_task(curr); | 248 | resched_task(curr); |
| 249 | } | ||
| 245 | } | 250 | } |
| 246 | } | 251 | } |
| 247 | 252 | ||
| @@ -334,8 +339,10 @@ static inline struct rt_rq *group_rt_rq(struct sched_rt_entity *rt_se) | |||
| 334 | 339 | ||
| 335 | static inline void sched_rt_rq_enqueue(struct rt_rq *rt_rq) | 340 | static inline void sched_rt_rq_enqueue(struct rt_rq *rt_rq) |
| 336 | { | 341 | { |
| 337 | if (rt_rq->rt_nr_running) | 342 | struct task_struct *curr = rq_of_rt_rq(rt_rq)->curr; |
| 338 | resched_task(rq_of_rt_rq(rt_rq)->curr); | 343 | |
| 344 | if (rt_rq->rt_nr_running && !is_realtime(curr)) | ||
| 345 | resched_task(curr); | ||
| 339 | } | 346 | } |
| 340 | 347 | ||
| 341 | static inline void sched_rt_rq_dequeue(struct rt_rq *rt_rq) | 348 | static inline void sched_rt_rq_dequeue(struct rt_rq *rt_rq) |
| @@ -1090,7 +1097,7 @@ static void check_preempt_equal_prio(struct rq *rq, struct task_struct *p) | |||
| 1090 | */ | 1097 | */ |
| 1091 | static void check_preempt_curr_rt(struct rq *rq, struct task_struct *p, int flags) | 1098 | static void check_preempt_curr_rt(struct rq *rq, struct task_struct *p, int flags) |
| 1092 | { | 1099 | { |
| 1093 | if (p->prio < rq->curr->prio) { | 1100 | if (p->prio < rq->curr->prio || p->policy == SCHED_LITMUS) { |
| 1094 | resched_task(rq->curr); | 1101 | resched_task(rq->curr); |
| 1095 | return; | 1102 | return; |
| 1096 | } | 1103 | } |
diff --git a/kernel/softirq.c b/kernel/softirq.c index fca82c32042..2f2df08df39 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c | |||
| @@ -211,6 +211,9 @@ asmlinkage void __do_softirq(void) | |||
| 211 | int max_restart = MAX_SOFTIRQ_RESTART; | 211 | int max_restart = MAX_SOFTIRQ_RESTART; |
| 212 | int cpu; | 212 | int cpu; |
| 213 | 213 | ||
| 214 | /* Mark Feather-Trace samples as "disturbed". */ | ||
| 215 | ft_irq_fired(); | ||
| 216 | |||
| 214 | pending = local_softirq_pending(); | 217 | pending = local_softirq_pending(); |
| 215 | account_system_vtime(current); | 218 | account_system_vtime(current); |
| 216 | 219 | ||
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index d5097c44b40..0c0e02f1b81 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c | |||
| @@ -766,12 +766,53 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) | |||
| 766 | } | 766 | } |
| 767 | 767 | ||
| 768 | /** | 768 | /** |
| 769 | * tick_set_quanta_type - get the quanta type as a boot option | ||
| 770 | * Default is standard setup with ticks staggered over first | ||
| 771 | * half of tick period. | ||
| 772 | */ | ||
| 773 | int quanta_type = LINUX_DEFAULT_TICKS; | ||
| 774 | static int __init tick_set_quanta_type(char *str) | ||
| 775 | { | ||
| 776 | if (strcmp("aligned", str) == 0) { | ||
| 777 | quanta_type = LITMUS_ALIGNED_TICKS; | ||
| 778 | printk(KERN_INFO "LITMUS^RT: setting aligned quanta\n"); | ||
| 779 | } | ||
| 780 | else if (strcmp("staggered", str) == 0) { | ||
| 781 | quanta_type = LITMUS_STAGGERED_TICKS; | ||
| 782 | printk(KERN_INFO "LITMUS^RT: setting staggered quanta\n"); | ||
| 783 | } | ||
| 784 | return 1; | ||
| 785 | } | ||
| 786 | __setup("quanta=", tick_set_quanta_type); | ||
| 787 | |||
| 788 | u64 cpu_stagger_offset(int cpu) | ||
| 789 | { | ||
| 790 | u64 offset = 0; | ||
| 791 | switch (quanta_type) { | ||
| 792 | case LITMUS_ALIGNED_TICKS: | ||
| 793 | offset = 0; | ||
| 794 | break; | ||
| 795 | case LITMUS_STAGGERED_TICKS: | ||
| 796 | offset = ktime_to_ns(tick_period); | ||
| 797 | do_div(offset, num_possible_cpus()); | ||
| 798 | offset *= cpu; | ||
| 799 | break; | ||
| 800 | default: | ||
| 801 | offset = ktime_to_ns(tick_period) >> 1; | ||
| 802 | do_div(offset, num_possible_cpus()); | ||
| 803 | offset *= cpu; | ||
| 804 | } | ||
| 805 | return offset; | ||
| 806 | } | ||
| 807 | |||
| 808 | /** | ||
| 769 | * tick_setup_sched_timer - setup the tick emulation timer | 809 | * tick_setup_sched_timer - setup the tick emulation timer |
| 770 | */ | 810 | */ |
| 771 | void tick_setup_sched_timer(void) | 811 | void tick_setup_sched_timer(void) |
| 772 | { | 812 | { |
| 773 | struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); | 813 | struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); |
| 774 | ktime_t now = ktime_get(); | 814 | ktime_t now = ktime_get(); |
| 815 | u64 offset; | ||
| 775 | 816 | ||
| 776 | /* | 817 | /* |
| 777 | * Emulate tick processing via per-CPU hrtimers: | 818 | * Emulate tick processing via per-CPU hrtimers: |
| @@ -782,6 +823,12 @@ void tick_setup_sched_timer(void) | |||
| 782 | /* Get the next period (per cpu) */ | 823 | /* Get the next period (per cpu) */ |
| 783 | hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update()); | 824 | hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update()); |
| 784 | 825 | ||
| 826 | /* Offset must be set correctly to achieve desired quanta type. */ | ||
| 827 | offset = cpu_stagger_offset(smp_processor_id()); | ||
| 828 | |||
| 829 | /* Add the correct offset to expiration time */ | ||
| 830 | hrtimer_add_expires_ns(&ts->sched_timer, offset); | ||
| 831 | |||
| 785 | for (;;) { | 832 | for (;;) { |
| 786 | hrtimer_forward(&ts->sched_timer, now, tick_period); | 833 | hrtimer_forward(&ts->sched_timer, now, tick_period); |
| 787 | hrtimer_start_expires(&ts->sched_timer, | 834 | hrtimer_start_expires(&ts->sched_timer, |
