diff options
-rw-r--r-- | include/linux/sched.h | 2 | ||||
-rw-r--r-- | include/litmus/preempt.h | 164 | ||||
-rw-r--r-- | kernel/sched.c | 3 | ||||
-rw-r--r-- | litmus/Makefile | 1 | ||||
-rw-r--r-- | litmus/budget.c | 3 | ||||
-rw-r--r-- | litmus/preempt.c | 131 | ||||
-rw-r--r-- | litmus/sched_cedf.c | 4 | ||||
-rw-r--r-- | litmus/sched_gsn_edf.c | 19 | ||||
-rw-r--r-- | litmus/sched_litmus.c | 5 | ||||
-rw-r--r-- | litmus/sched_pfair.c | 11 | ||||
-rw-r--r-- | litmus/sched_plugin.c | 45 | ||||
-rw-r--r-- | litmus/sched_psn_edf.c | 4 |
12 files changed, 341 insertions, 51 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index 708523b0692..c9ac4fc837b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -96,6 +96,7 @@ struct sched_param { | |||
96 | #include <asm/processor.h> | 96 | #include <asm/processor.h> |
97 | 97 | ||
98 | #include <litmus/rt_param.h> | 98 | #include <litmus/rt_param.h> |
99 | #include <litmus/preempt.h> | ||
99 | 100 | ||
100 | struct exec_domain; | 101 | struct exec_domain; |
101 | struct futex_pi_state; | 102 | struct futex_pi_state; |
@@ -2301,6 +2302,7 @@ static inline int test_tsk_thread_flag(struct task_struct *tsk, int flag) | |||
2301 | static inline void set_tsk_need_resched(struct task_struct *tsk) | 2302 | static inline void set_tsk_need_resched(struct task_struct *tsk) |
2302 | { | 2303 | { |
2303 | set_tsk_thread_flag(tsk,TIF_NEED_RESCHED); | 2304 | set_tsk_thread_flag(tsk,TIF_NEED_RESCHED); |
2305 | sched_state_will_schedule(tsk); | ||
2304 | } | 2306 | } |
2305 | 2307 | ||
2306 | static inline void clear_tsk_need_resched(struct task_struct *tsk) | 2308 | static inline void clear_tsk_need_resched(struct task_struct *tsk) |
diff --git a/include/litmus/preempt.h b/include/litmus/preempt.h new file mode 100644 index 00000000000..260c6fe1798 --- /dev/null +++ b/include/litmus/preempt.h | |||
@@ -0,0 +1,164 @@ | |||
1 | #ifndef LITMUS_PREEMPT_H | ||
2 | #define LITMUS_PREEMPT_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | #include <linux/cache.h> | ||
6 | #include <linux/percpu.h> | ||
7 | #include <asm/atomic.h> | ||
8 | |||
9 | #include <litmus/debug_trace.h> | ||
10 | |||
11 | extern DEFINE_PER_CPU_SHARED_ALIGNED(atomic_t, resched_state); | ||
12 | |||
13 | #ifdef CONFIG_DEBUG_KERNEL | ||
14 | const char* sched_state_name(int s); | ||
15 | #define TRACE_STATE(fmt, args...) TRACE("SCHED_STATE " fmt, args) | ||
16 | #else | ||
17 | #define TRACE_STATE(fmt, args...) /* ignore */ | ||
18 | #endif | ||
19 | |||
20 | #define VERIFY_SCHED_STATE(x) \ | ||
21 | do { int __s = get_sched_state(); \ | ||
22 | if ((__s & (x)) == 0) \ | ||
23 | TRACE_STATE("INVALID s=0x%x (%s) not " \ | ||
24 | "in 0x%x (%s) [%s]\n", \ | ||
25 | __s, sched_state_name(__s), \ | ||
26 | (x), #x, __FUNCTION__); \ | ||
27 | } while (0); | ||
28 | |||
29 | #define TRACE_SCHED_STATE_CHANGE(x, y, cpu) \ | ||
30 | TRACE_STATE("[P%d] 0x%x (%s) -> 0x%x (%s)\n", \ | ||
31 | cpu, (x), sched_state_name(x), \ | ||
32 | (y), sched_state_name(y)) | ||
33 | |||
34 | |||
35 | typedef enum scheduling_state { | ||
36 | TASK_SCHEDULED = (1 << 0), /* The currently scheduled task is the one that | ||
37 | * should be scheduled, and the processor does not | ||
38 | * plan to invoke schedule(). */ | ||
39 | SHOULD_SCHEDULE = (1 << 1), /* A remote processor has determined that the | ||
40 | * processor should reschedule, but this has not | ||
41 | * been communicated yet (IPI still pending). */ | ||
42 | WILL_SCHEDULE = (1 << 2), /* The processor has noticed that it has to | ||
43 | * reschedule and will do so shortly. */ | ||
44 | TASK_PICKED = (1 << 3), /* The processor is currently executing schedule(), | ||
45 | * has selected a new task to schedule, but has not | ||
46 | * yet performed the actual context switch. */ | ||
47 | PICKED_WRONG_TASK = (1 << 4), /* The processor has not yet performed the context | ||
48 | * switch, but a remote processor has already | ||
49 | * determined that a higher-priority task became | ||
50 | * eligible after the task was picked. */ | ||
51 | } sched_state_t; | ||
52 | |||
53 | static inline sched_state_t get_sched_state_on(int cpu) | ||
54 | { | ||
55 | return atomic_read(&per_cpu(resched_state, cpu)); | ||
56 | } | ||
57 | |||
58 | static inline sched_state_t get_sched_state(void) | ||
59 | { | ||
60 | return atomic_read(&__get_cpu_var(resched_state)); | ||
61 | } | ||
62 | |||
63 | static inline int is_in_sched_state(int possible_states) | ||
64 | { | ||
65 | return get_sched_state() & possible_states; | ||
66 | } | ||
67 | |||
68 | static inline int cpu_is_in_sched_state(int cpu, int possible_states) | ||
69 | { | ||
70 | return get_sched_state_on(cpu) & possible_states; | ||
71 | } | ||
72 | |||
73 | static inline void set_sched_state(sched_state_t s) | ||
74 | { | ||
75 | TRACE_SCHED_STATE_CHANGE(get_sched_state(), s, smp_processor_id()); | ||
76 | atomic_set(&__get_cpu_var(resched_state), s); | ||
77 | } | ||
78 | |||
79 | static inline int sched_state_transition(sched_state_t from, sched_state_t to) | ||
80 | { | ||
81 | sched_state_t old_state; | ||
82 | |||
83 | old_state = atomic_cmpxchg(&__get_cpu_var(resched_state), from, to); | ||
84 | if (old_state == from) { | ||
85 | TRACE_SCHED_STATE_CHANGE(from, to, smp_processor_id()); | ||
86 | return 1; | ||
87 | } else | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static inline int sched_state_transition_on(int cpu, | ||
92 | sched_state_t from, | ||
93 | sched_state_t to) | ||
94 | { | ||
95 | sched_state_t old_state; | ||
96 | |||
97 | old_state = atomic_cmpxchg(&per_cpu(resched_state, cpu), from, to); | ||
98 | if (old_state == from) { | ||
99 | TRACE_SCHED_STATE_CHANGE(from, to, cpu); | ||
100 | return 1; | ||
101 | } else | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | /* Plugins must call this function after they have decided which job to | ||
106 | * schedule next. IMPORTANT: this function must be called while still holding | ||
107 | * the lock that is used to serialize scheduling decisions. | ||
108 | * | ||
109 | * (Ideally, we would like to use runqueue locks for this purpose, but that | ||
110 | * would lead to deadlocks with the migration code.) | ||
111 | */ | ||
112 | static inline void sched_state_task_picked(void) | ||
113 | { | ||
114 | VERIFY_SCHED_STATE(WILL_SCHEDULE); | ||
115 | |||
116 | /* WILL_SCHEDULE has only a local tansition => simple store is ok */ | ||
117 | set_sched_state(TASK_PICKED); | ||
118 | } | ||
119 | |||
120 | static inline void sched_state_entered_schedule(void) | ||
121 | { | ||
122 | /* Update state for the case that we entered schedule() not due to | ||
123 | * set_tsk_need_resched() */ | ||
124 | set_sched_state(WILL_SCHEDULE); | ||
125 | } | ||
126 | |||
127 | /* Called by schedule() to check if the scheduling decision is still valid | ||
128 | * after a context switch. Returns 1 if the CPU needs to reschdule. */ | ||
129 | static inline int sched_state_validate_switch(void) | ||
130 | { | ||
131 | int left_state_ok = 0; | ||
132 | |||
133 | VERIFY_SCHED_STATE(PICKED_WRONG_TASK | TASK_PICKED); | ||
134 | |||
135 | if (is_in_sched_state(TASK_PICKED)) { | ||
136 | /* Might be good; let's try to transition out of this | ||
137 | * state. This must be done atomically since remote processors | ||
138 | * may try to change the state, too. */ | ||
139 | left_state_ok = sched_state_transition(TASK_PICKED, TASK_SCHEDULED); | ||
140 | } | ||
141 | |||
142 | if (!left_state_ok) { | ||
143 | /* We raced with a higher-priority task arrival => not | ||
144 | * valid. The CPU needs to reschedule. */ | ||
145 | set_sched_state(WILL_SCHEDULE); | ||
146 | return 1; | ||
147 | } else | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | /* State transition events. See litmus/preempt.c for details. */ | ||
152 | void sched_state_will_schedule(struct task_struct* tsk); | ||
153 | void sched_state_ipi(void); | ||
154 | /* Cause a CPU (remote or local) to reschedule. */ | ||
155 | void litmus_reschedule(int cpu); | ||
156 | void litmus_reschedule_local(void); | ||
157 | |||
158 | #ifdef CONFIG_DEBUG_KERNEL | ||
159 | void sched_state_plugin_check(void); | ||
160 | #else | ||
161 | #define sched_state_plugin_check() /* no check */ | ||
162 | #endif | ||
163 | |||
164 | #endif | ||
diff --git a/kernel/sched.c b/kernel/sched.c index a9dd6f96c73..60fbae0c747 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -3794,6 +3794,7 @@ asmlinkage void __sched schedule(void) | |||
3794 | 3794 | ||
3795 | need_resched: | 3795 | need_resched: |
3796 | preempt_disable(); | 3796 | preempt_disable(); |
3797 | sched_state_entered_schedule(); | ||
3797 | cpu = smp_processor_id(); | 3798 | cpu = smp_processor_id(); |
3798 | rq = cpu_rq(cpu); | 3799 | rq = cpu_rq(cpu); |
3799 | rcu_note_context_switch(cpu); | 3800 | rcu_note_context_switch(cpu); |
@@ -3872,7 +3873,7 @@ need_resched_nonpreemptible: | |||
3872 | 3873 | ||
3873 | post_schedule(rq); | 3874 | post_schedule(rq); |
3874 | 3875 | ||
3875 | if (unlikely(reacquire_kernel_lock(prev))) | 3876 | if (sched_state_validate_switch() || unlikely(reacquire_kernel_lock(prev))) |
3876 | goto need_resched_nonpreemptible; | 3877 | goto need_resched_nonpreemptible; |
3877 | 3878 | ||
3878 | preempt_enable_no_resched(); | 3879 | preempt_enable_no_resched(); |
diff --git a/litmus/Makefile b/litmus/Makefile index 7bd1abdcb84..b7366b53074 100644 --- a/litmus/Makefile +++ b/litmus/Makefile | |||
@@ -3,6 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y = sched_plugin.o litmus.o \ | 5 | obj-y = sched_plugin.o litmus.o \ |
6 | preempt.o \ | ||
6 | litmus_proc.o \ | 7 | litmus_proc.o \ |
7 | budget.o \ | 8 | budget.o \ |
8 | jobs.o \ | 9 | jobs.o \ |
diff --git a/litmus/budget.c b/litmus/budget.c index f6f5ca81c9d..310e9a3d417 100644 --- a/litmus/budget.c +++ b/litmus/budget.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <linux/hrtimer.h> | 3 | #include <linux/hrtimer.h> |
4 | 4 | ||
5 | #include <litmus/litmus.h> | 5 | #include <litmus/litmus.h> |
6 | #include <litmus/preempt.h> | ||
6 | 7 | ||
7 | struct enforcement_timer { | 8 | struct enforcement_timer { |
8 | /* The enforcement timer is used to accurately police | 9 | /* The enforcement timer is used to accurately police |
@@ -24,7 +25,7 @@ static enum hrtimer_restart on_enforcement_timeout(struct hrtimer *timer) | |||
24 | TRACE("enforcement timer fired.\n"); | 25 | TRACE("enforcement timer fired.\n"); |
25 | et->armed = 0; | 26 | et->armed = 0; |
26 | /* activate scheduler */ | 27 | /* activate scheduler */ |
27 | set_tsk_need_resched(current); | 28 | litmus_reschedule_local(); |
28 | local_irq_restore(flags); | 29 | local_irq_restore(flags); |
29 | 30 | ||
30 | return HRTIMER_NORESTART; | 31 | return HRTIMER_NORESTART; |
diff --git a/litmus/preempt.c b/litmus/preempt.c new file mode 100644 index 00000000000..ebe2e346189 --- /dev/null +++ b/litmus/preempt.c | |||
@@ -0,0 +1,131 @@ | |||
1 | #include <linux/sched.h> | ||
2 | |||
3 | #include <litmus/litmus.h> | ||
4 | #include <litmus/preempt.h> | ||
5 | |||
6 | /* The rescheduling state of each processor. | ||
7 | */ | ||
8 | DEFINE_PER_CPU_SHARED_ALIGNED(atomic_t, resched_state); | ||
9 | |||
10 | void sched_state_will_schedule(struct task_struct* tsk) | ||
11 | { | ||
12 | /* Litmus hack: we only care about processor-local invocations of | ||
13 | * set_tsk_need_resched(). We can't reliably set the flag remotely | ||
14 | * since it might race with other updates to the scheduling state. We | ||
15 | * can't rely on the runqueue lock protecting updates to the sched | ||
16 | * state since processors do not acquire the runqueue locks for all | ||
17 | * updates to the sched state (to avoid acquiring two runqueue locks at | ||
18 | * the same time). Further, if tsk is residing on a remote processor, | ||
19 | * then that processor doesn't actually know yet that it is going to | ||
20 | * reschedule; it still must receive an IPI (unless a local invocation | ||
21 | * races). | ||
22 | */ | ||
23 | if (likely(task_cpu(tsk) == smp_processor_id())) { | ||
24 | VERIFY_SCHED_STATE(TASK_SCHEDULED | SHOULD_SCHEDULE | TASK_PICKED | WILL_SCHEDULE); | ||
25 | if (is_in_sched_state(TASK_PICKED | PICKED_WRONG_TASK)) | ||
26 | set_sched_state(PICKED_WRONG_TASK); | ||
27 | else | ||
28 | set_sched_state(WILL_SCHEDULE); | ||
29 | } else | ||
30 | /* Litmus tasks should never be subject to a remote | ||
31 | * set_tsk_need_resched(). */ | ||
32 | BUG_ON(is_realtime(tsk)); | ||
33 | TRACE_TASK(tsk, "set_tsk_need_resched() ret:%p\n", | ||
34 | __builtin_return_address(0)); | ||
35 | } | ||
36 | |||
37 | /* Called by the IPI handler after another CPU called smp_send_resched(). */ | ||
38 | void sched_state_ipi(void) | ||
39 | { | ||
40 | /* If the IPI was slow, we might be in any state right now. The IPI is | ||
41 | * only meaningful if we are in SHOULD_SCHEDULE. */ | ||
42 | if (is_in_sched_state(SHOULD_SCHEDULE)) { | ||
43 | /* Cause scheduler to be invoked. | ||
44 | * This will cause a transition to WILL_SCHEDULE. */ | ||
45 | set_tsk_need_resched(current); | ||
46 | TRACE_STATE("IPI -> set_tsk_need_resched(%s/%d)\n", | ||
47 | current->comm, current->pid); | ||
48 | } else { | ||
49 | /* ignore */ | ||
50 | TRACE_STATE("ignoring IPI in state %x (%s)\n", | ||
51 | get_sched_state(), | ||
52 | sched_state_name(get_sched_state())); | ||
53 | } | ||
54 | } | ||
55 | |||
56 | /* Called by plugins to cause a CPU to reschedule. IMPORTANT: the caller must | ||
57 | * hold the lock that is used to serialize scheduling decisions. */ | ||
58 | void litmus_reschedule(int cpu) | ||
59 | { | ||
60 | int picked_transition_ok = 0; | ||
61 | int scheduled_transition_ok = 0; | ||
62 | |||
63 | /* The (remote) CPU could be in any state. */ | ||
64 | |||
65 | /* The critical states are TASK_PICKED and TASK_SCHEDULED, as the CPU | ||
66 | * is not aware of the need to reschedule at this point. */ | ||
67 | |||
68 | /* is a context switch in progress? */ | ||
69 | if (cpu_is_in_sched_state(cpu, TASK_PICKED)) | ||
70 | picked_transition_ok = sched_state_transition_on( | ||
71 | cpu, TASK_PICKED, PICKED_WRONG_TASK); | ||
72 | |||
73 | if (!picked_transition_ok && | ||
74 | cpu_is_in_sched_state(cpu, TASK_SCHEDULED)) { | ||
75 | /* We either raced with the end of the context switch, or the | ||
76 | * CPU was in TASK_SCHEDULED anyway. */ | ||
77 | scheduled_transition_ok = sched_state_transition_on( | ||
78 | cpu, TASK_SCHEDULED, SHOULD_SCHEDULE); | ||
79 | } | ||
80 | |||
81 | /* If the CPU was in state TASK_SCHEDULED, then we need to cause the | ||
82 | * scheduler to be invoked. */ | ||
83 | if (scheduled_transition_ok) { | ||
84 | if (smp_processor_id() == cpu) | ||
85 | set_tsk_need_resched(current); | ||
86 | else | ||
87 | smp_send_reschedule(cpu); | ||
88 | } | ||
89 | |||
90 | TRACE_STATE("%s picked-ok:%d sched-ok:%d\n", | ||
91 | __FUNCTION__, | ||
92 | picked_transition_ok, | ||
93 | scheduled_transition_ok); | ||
94 | } | ||
95 | |||
96 | void litmus_reschedule_local(void) | ||
97 | { | ||
98 | if (is_in_sched_state(TASK_PICKED)) | ||
99 | set_sched_state(PICKED_WRONG_TASK); | ||
100 | else if (is_in_sched_state(TASK_SCHEDULED | SHOULD_SCHEDULE)) { | ||
101 | set_sched_state(WILL_SCHEDULE); | ||
102 | set_tsk_need_resched(current); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | #ifdef CONFIG_DEBUG_KERNEL | ||
107 | |||
108 | void sched_state_plugin_check(void) | ||
109 | { | ||
110 | if (!is_in_sched_state(TASK_PICKED | PICKED_WRONG_TASK)) { | ||
111 | TRACE("!!!! plugin did not call sched_state_task_picked()!" | ||
112 | "Calling sched_state_task_picked() is mandatory---fix this.\n"); | ||
113 | set_sched_state(TASK_PICKED); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | #define NAME_CHECK(x) case x: return #x | ||
118 | const char* sched_state_name(int s) | ||
119 | { | ||
120 | switch (s) { | ||
121 | NAME_CHECK(TASK_SCHEDULED); | ||
122 | NAME_CHECK(SHOULD_SCHEDULE); | ||
123 | NAME_CHECK(WILL_SCHEDULE); | ||
124 | NAME_CHECK(TASK_PICKED); | ||
125 | NAME_CHECK(PICKED_WRONG_TASK); | ||
126 | default: | ||
127 | return "UNKNOWN"; | ||
128 | }; | ||
129 | } | ||
130 | |||
131 | #endif | ||
diff --git a/litmus/sched_cedf.c b/litmus/sched_cedf.c index a729d97535e..615560f21d6 100644 --- a/litmus/sched_cedf.c +++ b/litmus/sched_cedf.c | |||
@@ -34,6 +34,7 @@ | |||
34 | 34 | ||
35 | #include <litmus/litmus.h> | 35 | #include <litmus/litmus.h> |
36 | #include <litmus/jobs.h> | 36 | #include <litmus/jobs.h> |
37 | #include <litmus/preempt.h> | ||
37 | #include <litmus/sched_plugin.h> | 38 | #include <litmus/sched_plugin.h> |
38 | #include <litmus/edf_common.h> | 39 | #include <litmus/edf_common.h> |
39 | #include <litmus/sched_trace.h> | 40 | #include <litmus/sched_trace.h> |
@@ -341,7 +342,7 @@ static void cedf_tick(struct task_struct* t) | |||
341 | /* np tasks will be preempted when they become | 342 | /* np tasks will be preempted when they become |
342 | * preemptable again | 343 | * preemptable again |
343 | */ | 344 | */ |
344 | set_tsk_need_resched(t); | 345 | litmus_reschedule_local(); |
345 | set_will_schedule(); | 346 | set_will_schedule(); |
346 | TRACE("cedf_scheduler_tick: " | 347 | TRACE("cedf_scheduler_tick: " |
347 | "%d is preemptable " | 348 | "%d is preemptable " |
@@ -466,6 +467,7 @@ static struct task_struct* cedf_schedule(struct task_struct * prev) | |||
466 | if (exists) | 467 | if (exists) |
467 | next = prev; | 468 | next = prev; |
468 | 469 | ||
470 | sched_state_task_picked(); | ||
469 | raw_spin_unlock(&cluster->lock); | 471 | raw_spin_unlock(&cluster->lock); |
470 | 472 | ||
471 | #ifdef WANT_ALL_SCHED_EVENTS | 473 | #ifdef WANT_ALL_SCHED_EVENTS |
diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c index e101768740a..f0337cfd863 100644 --- a/litmus/sched_gsn_edf.c +++ b/litmus/sched_gsn_edf.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <litmus/edf_common.h> | 18 | #include <litmus/edf_common.h> |
19 | #include <litmus/sched_trace.h> | 19 | #include <litmus/sched_trace.h> |
20 | 20 | ||
21 | #include <litmus/preempt.h> | ||
22 | |||
21 | #include <litmus/bheap.h> | 23 | #include <litmus/bheap.h> |
22 | 24 | ||
23 | #include <linux/module.h> | 25 | #include <linux/module.h> |
@@ -95,21 +97,12 @@ typedef struct { | |||
95 | int cpu; | 97 | int cpu; |
96 | struct task_struct* linked; /* only RT tasks */ | 98 | struct task_struct* linked; /* only RT tasks */ |
97 | struct task_struct* scheduled; /* only RT tasks */ | 99 | struct task_struct* scheduled; /* only RT tasks */ |
98 | atomic_t will_schedule; /* prevent unneeded IPIs */ | ||
99 | struct bheap_node* hn; | 100 | struct bheap_node* hn; |
100 | } cpu_entry_t; | 101 | } cpu_entry_t; |
101 | DEFINE_PER_CPU(cpu_entry_t, gsnedf_cpu_entries); | 102 | DEFINE_PER_CPU(cpu_entry_t, gsnedf_cpu_entries); |
102 | 103 | ||
103 | cpu_entry_t* gsnedf_cpus[NR_CPUS]; | 104 | cpu_entry_t* gsnedf_cpus[NR_CPUS]; |
104 | 105 | ||
105 | #define set_will_schedule() \ | ||
106 | (atomic_set(&__get_cpu_var(gsnedf_cpu_entries).will_schedule, 1)) | ||
107 | #define clear_will_schedule() \ | ||
108 | (atomic_set(&__get_cpu_var(gsnedf_cpu_entries).will_schedule, 0)) | ||
109 | #define test_will_schedule(cpu) \ | ||
110 | (atomic_read(&per_cpu(gsnedf_cpu_entries, cpu).will_schedule)) | ||
111 | |||
112 | |||
113 | /* the cpus queue themselves according to priority in here */ | 106 | /* the cpus queue themselves according to priority in here */ |
114 | static struct bheap_node gsnedf_heap_node[NR_CPUS]; | 107 | static struct bheap_node gsnedf_heap_node[NR_CPUS]; |
115 | static struct bheap gsnedf_cpu_heap; | 108 | static struct bheap gsnedf_cpu_heap; |
@@ -341,8 +334,7 @@ static void gsnedf_tick(struct task_struct* t) | |||
341 | /* np tasks will be preempted when they become | 334 | /* np tasks will be preempted when they become |
342 | * preemptable again | 335 | * preemptable again |
343 | */ | 336 | */ |
344 | set_tsk_need_resched(t); | 337 | litmus_reschedule_local(); |
345 | set_will_schedule(); | ||
346 | TRACE("gsnedf_scheduler_tick: " | 338 | TRACE("gsnedf_scheduler_tick: " |
347 | "%d is preemptable " | 339 | "%d is preemptable " |
348 | " => FORCE_RESCHED\n", t->pid); | 340 | " => FORCE_RESCHED\n", t->pid); |
@@ -391,7 +383,6 @@ static struct task_struct* gsnedf_schedule(struct task_struct * prev) | |||
391 | #endif | 383 | #endif |
392 | 384 | ||
393 | raw_spin_lock(&gsnedf_lock); | 385 | raw_spin_lock(&gsnedf_lock); |
394 | clear_will_schedule(); | ||
395 | 386 | ||
396 | /* sanity checking */ | 387 | /* sanity checking */ |
397 | BUG_ON(entry->scheduled && entry->scheduled != prev); | 388 | BUG_ON(entry->scheduled && entry->scheduled != prev); |
@@ -473,6 +464,8 @@ static struct task_struct* gsnedf_schedule(struct task_struct * prev) | |||
473 | if (exists) | 464 | if (exists) |
474 | next = prev; | 465 | next = prev; |
475 | 466 | ||
467 | sched_state_task_picked(); | ||
468 | |||
476 | raw_spin_unlock(&gsnedf_lock); | 469 | raw_spin_unlock(&gsnedf_lock); |
477 | 470 | ||
478 | #ifdef WANT_ALL_SCHED_EVENTS | 471 | #ifdef WANT_ALL_SCHED_EVENTS |
@@ -780,7 +773,6 @@ static long gsnedf_activate_plugin(void) | |||
780 | for_each_online_cpu(cpu) { | 773 | for_each_online_cpu(cpu) { |
781 | entry = &per_cpu(gsnedf_cpu_entries, cpu); | 774 | entry = &per_cpu(gsnedf_cpu_entries, cpu); |
782 | bheap_node_init(&entry->hn, entry); | 775 | bheap_node_init(&entry->hn, entry); |
783 | atomic_set(&entry->will_schedule, 0); | ||
784 | entry->linked = NULL; | 776 | entry->linked = NULL; |
785 | entry->scheduled = NULL; | 777 | entry->scheduled = NULL; |
786 | #ifdef CONFIG_RELEASE_MASTER | 778 | #ifdef CONFIG_RELEASE_MASTER |
@@ -829,7 +821,6 @@ static int __init init_gsn_edf(void) | |||
829 | for (cpu = 0; cpu < NR_CPUS; cpu++) { | 821 | for (cpu = 0; cpu < NR_CPUS; cpu++) { |
830 | entry = &per_cpu(gsnedf_cpu_entries, cpu); | 822 | entry = &per_cpu(gsnedf_cpu_entries, cpu); |
831 | gsnedf_cpus[cpu] = entry; | 823 | gsnedf_cpus[cpu] = entry; |
832 | atomic_set(&entry->will_schedule, 0); | ||
833 | entry->cpu = cpu; | 824 | entry->cpu = cpu; |
834 | entry->hn = &gsnedf_heap_node[cpu]; | 825 | entry->hn = &gsnedf_heap_node[cpu]; |
835 | bheap_node_init(&entry->hn, entry); | 826 | bheap_node_init(&entry->hn, entry); |
diff --git a/litmus/sched_litmus.c b/litmus/sched_litmus.c index 65873152e68..e6952896dc4 100644 --- a/litmus/sched_litmus.c +++ b/litmus/sched_litmus.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <litmus/litmus.h> | 3 | #include <litmus/litmus.h> |
4 | #include <litmus/budget.h> | 4 | #include <litmus/budget.h> |
5 | #include <litmus/sched_plugin.h> | 5 | #include <litmus/sched_plugin.h> |
6 | #include <litmus/preempt.h> | ||
6 | 7 | ||
7 | static void update_time_litmus(struct rq *rq, struct task_struct *p) | 8 | static void update_time_litmus(struct rq *rq, struct task_struct *p) |
8 | { | 9 | { |
@@ -52,6 +53,8 @@ litmus_schedule(struct rq *rq, struct task_struct *prev) | |||
52 | /* let the plugin schedule */ | 53 | /* let the plugin schedule */ |
53 | next = litmus->schedule(prev); | 54 | next = litmus->schedule(prev); |
54 | 55 | ||
56 | sched_state_plugin_check(); | ||
57 | |||
55 | /* check if a global plugin pulled a task from a different RQ */ | 58 | /* check if a global plugin pulled a task from a different RQ */ |
56 | if (next && task_rq(next) != rq) { | 59 | if (next && task_rq(next) != rq) { |
57 | /* we need to migrate the task */ | 60 | /* we need to migrate the task */ |
@@ -198,7 +201,7 @@ static void yield_task_litmus(struct rq *rq) | |||
198 | * then determine if a preemption is still required. | 201 | * then determine if a preemption is still required. |
199 | */ | 202 | */ |
200 | clear_exit_np(current); | 203 | clear_exit_np(current); |
201 | set_tsk_need_resched(current); | 204 | litmus_reschedule_local(); |
202 | } | 205 | } |
203 | 206 | ||
204 | /* Plugins are responsible for this. | 207 | /* Plugins are responsible for this. |
diff --git a/litmus/sched_pfair.c b/litmus/sched_pfair.c index ea77d329529..c7d5cf7aa2b 100644 --- a/litmus/sched_pfair.c +++ b/litmus/sched_pfair.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <litmus/litmus.h> | 17 | #include <litmus/litmus.h> |
18 | #include <litmus/jobs.h> | 18 | #include <litmus/jobs.h> |
19 | #include <litmus/preempt.h> | ||
19 | #include <litmus/rt_domain.h> | 20 | #include <litmus/rt_domain.h> |
20 | #include <litmus/sched_plugin.h> | 21 | #include <litmus/sched_plugin.h> |
21 | #include <litmus/sched_trace.h> | 22 | #include <litmus/sched_trace.h> |
@@ -241,11 +242,7 @@ static void check_preempt(struct task_struct* t) | |||
241 | PTRACE_TASK(t, "linked_on:%d, scheduled_on:%d\n", | 242 | PTRACE_TASK(t, "linked_on:%d, scheduled_on:%d\n", |
242 | tsk_rt(t)->linked_on, tsk_rt(t)->scheduled_on); | 243 | tsk_rt(t)->linked_on, tsk_rt(t)->scheduled_on); |
243 | /* preempt */ | 244 | /* preempt */ |
244 | if (cpu == smp_processor_id()) | 245 | litmus_reschedule(cpu); |
245 | set_tsk_need_resched(current); | ||
246 | else { | ||
247 | smp_send_reschedule(cpu); | ||
248 | } | ||
249 | } | 246 | } |
250 | } | 247 | } |
251 | 248 | ||
@@ -545,7 +542,7 @@ static void pfair_tick(struct task_struct* t) | |||
545 | 542 | ||
546 | if (state->local != current | 543 | if (state->local != current |
547 | && (is_realtime(current) || is_present(state->local))) | 544 | && (is_realtime(current) || is_present(state->local))) |
548 | set_tsk_need_resched(current); | 545 | litmus_reschedule_local(); |
549 | } | 546 | } |
550 | 547 | ||
551 | static int safe_to_schedule(struct task_struct* t, int cpu) | 548 | static int safe_to_schedule(struct task_struct* t, int cpu) |
@@ -577,7 +574,7 @@ static struct task_struct* pfair_schedule(struct task_struct * prev) | |||
577 | if (next) | 574 | if (next) |
578 | tsk_rt(next)->scheduled_on = state->cpu; | 575 | tsk_rt(next)->scheduled_on = state->cpu; |
579 | } | 576 | } |
580 | 577 | sched_state_task_picked(); | |
581 | raw_spin_unlock(&pfair_lock); | 578 | raw_spin_unlock(&pfair_lock); |
582 | 579 | ||
583 | if (next) | 580 | if (next) |
diff --git a/litmus/sched_plugin.c b/litmus/sched_plugin.c index ec04454a0cf..d912a6494d2 100644 --- a/litmus/sched_plugin.c +++ b/litmus/sched_plugin.c | |||
@@ -10,7 +10,7 @@ | |||
10 | 10 | ||
11 | #include <litmus/litmus.h> | 11 | #include <litmus/litmus.h> |
12 | #include <litmus/sched_plugin.h> | 12 | #include <litmus/sched_plugin.h> |
13 | 13 | #include <litmus/preempt.h> | |
14 | #include <litmus/jobs.h> | 14 | #include <litmus/jobs.h> |
15 | 15 | ||
16 | /* | 16 | /* |
@@ -19,36 +19,30 @@ | |||
19 | * non-preemptive section aware and does not invoke the scheduler / send | 19 | * non-preemptive section aware and does not invoke the scheduler / send |
20 | * IPIs if the to-be-preempted task is actually non-preemptive. | 20 | * IPIs if the to-be-preempted task is actually non-preemptive. |
21 | */ | 21 | */ |
22 | void preempt_if_preemptable(struct task_struct* t, int on_cpu) | 22 | void preempt_if_preemptable(struct task_struct* t, int cpu) |
23 | { | 23 | { |
24 | /* t is the real-time task executing on CPU on_cpu If t is NULL, then | 24 | /* t is the real-time task executing on CPU on_cpu If t is NULL, then |
25 | * on_cpu is currently scheduling background work. | 25 | * on_cpu is currently scheduling background work. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | int send_ipi; | 28 | int reschedule = 0; |
29 | 29 | ||
30 | if (smp_processor_id() == on_cpu) { | 30 | if (!t) |
31 | /* local CPU case */ | 31 | /* move non-real-time task out of the way */ |
32 | if (t) { | 32 | reschedule = 1; |
33 | else { | ||
34 | if (smp_processor_id() == cpu) { | ||
35 | /* local CPU case */ | ||
33 | /* check if we need to poke userspace */ | 36 | /* check if we need to poke userspace */ |
34 | if (is_user_np(t)) | 37 | if (is_user_np(t)) |
35 | /* yes, poke it */ | 38 | /* yes, poke it */ |
36 | request_exit_np(t); | 39 | request_exit_np(t); |
37 | else | 40 | else if (!is_kernel_np(t)) |
38 | /* no, see if we are allowed to preempt the | 41 | /* only if we are allowed to preempt the |
39 | * currently-executing task */ | 42 | * currently-executing task */ |
40 | if (!is_kernel_np(t)) | 43 | reschedule = 1; |
41 | set_tsk_need_resched(t); | 44 | } else { |
42 | } else | 45 | /* remote CPU case */ |
43 | /* move non-real-time task out of the way */ | ||
44 | set_tsk_need_resched(current); | ||
45 | } else { | ||
46 | /* remote CPU case */ | ||
47 | if (!t) | ||
48 | /* currently schedules non-real-time work */ | ||
49 | send_ipi = 1; | ||
50 | else { | ||
51 | /* currently schedules real-time work */ | ||
52 | if (is_user_np(t)) { | 46 | if (is_user_np(t)) { |
53 | /* need to notify user space of delayed | 47 | /* need to notify user space of delayed |
54 | * preemption */ | 48 | * preemption */ |
@@ -60,14 +54,14 @@ void preempt_if_preemptable(struct task_struct* t, int on_cpu) | |||
60 | mb(); | 54 | mb(); |
61 | } | 55 | } |
62 | /* Only send an ipi if remote task might have raced our | 56 | /* Only send an ipi if remote task might have raced our |
63 | * request, i.e., send an IPI to make sure if it exited | 57 | * request, i.e., send an IPI to make sure in case it |
64 | * its critical section. | 58 | * exited its critical section. |
65 | */ | 59 | */ |
66 | send_ipi = !is_np(t) && !is_kernel_np(t); | 60 | reschedule = !is_np(t) && !is_kernel_np(t); |
67 | } | 61 | } |
68 | if (likely(send_ipi)) | ||
69 | smp_send_reschedule(on_cpu); | ||
70 | } | 62 | } |
63 | if (likely(reschedule)) | ||
64 | litmus_reschedule(cpu); | ||
71 | } | 65 | } |
72 | 66 | ||
73 | 67 | ||
@@ -81,6 +75,7 @@ static void litmus_dummy_finish_switch(struct task_struct * prev) | |||
81 | 75 | ||
82 | static struct task_struct* litmus_dummy_schedule(struct task_struct * prev) | 76 | static struct task_struct* litmus_dummy_schedule(struct task_struct * prev) |
83 | { | 77 | { |
78 | sched_state_task_picked(); | ||
84 | return NULL; | 79 | return NULL; |
85 | } | 80 | } |
86 | 81 | ||
diff --git a/litmus/sched_psn_edf.c b/litmus/sched_psn_edf.c index aa567f2b91b..b89823d5c02 100644 --- a/litmus/sched_psn_edf.c +++ b/litmus/sched_psn_edf.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <litmus/litmus.h> | 17 | #include <litmus/litmus.h> |
18 | #include <litmus/jobs.h> | 18 | #include <litmus/jobs.h> |
19 | #include <litmus/preempt.h> | ||
19 | #include <litmus/sched_plugin.h> | 20 | #include <litmus/sched_plugin.h> |
20 | #include <litmus/edf_common.h> | 21 | #include <litmus/edf_common.h> |
21 | #include <litmus/sched_trace.h> | 22 | #include <litmus/sched_trace.h> |
@@ -108,7 +109,7 @@ static void psnedf_tick(struct task_struct *t) | |||
108 | 109 | ||
109 | if (is_realtime(t) && budget_enforced(t) && budget_exhausted(t)) { | 110 | if (is_realtime(t) && budget_enforced(t) && budget_exhausted(t)) { |
110 | if (!is_np(t)) { | 111 | if (!is_np(t)) { |
111 | set_tsk_need_resched(t); | 112 | litmus_reschedule_local(); |
112 | TRACE("psnedf_scheduler_tick: " | 113 | TRACE("psnedf_scheduler_tick: " |
113 | "%d is preemptable " | 114 | "%d is preemptable " |
114 | " => FORCE_RESCHED\n", t->pid); | 115 | " => FORCE_RESCHED\n", t->pid); |
@@ -204,6 +205,7 @@ static struct task_struct* psnedf_schedule(struct task_struct * prev) | |||
204 | } | 205 | } |
205 | 206 | ||
206 | pedf->scheduled = next; | 207 | pedf->scheduled = next; |
208 | sched_state_task_picked(); | ||
207 | raw_spin_unlock(&pedf->slock); | 209 | raw_spin_unlock(&pedf->slock); |
208 | 210 | ||
209 | return next; | 211 | return next; |