aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern Brandenburg <bbb@mpi-sws.org>2014-09-08 12:19:43 -0400
committerBjoern Brandenburg <bbb@mpi-sws.org>2014-09-08 12:19:43 -0400
commit642d997fc6d6500e14f3c2fa72e481800d687cd1 (patch)
tree1b7a320dfb3640ca0f0e45f40c2fa5680cd0053b
parent85533ddcfa62fdb273d2f33e5e729ad1461f771a (diff)
P-RES: ensure scheduler timer fires on _local_ CPU only
Accidentally setting up the timer on the wrong CPU when a thread resumes is problematic can lead (potentially) to deadlock and to missed scheduling events.
-rw-r--r--litmus/sched_pres.c55
1 files changed, 50 insertions, 5 deletions
diff --git a/litmus/sched_pres.c b/litmus/sched_pres.c
index 6779ffd16dae..60afde6f8d1b 100644
--- a/litmus/sched_pres.c
+++ b/litmus/sched_pres.c
@@ -65,14 +65,22 @@ static void task_arrives(struct task_struct *tsk)
65 65
66static void pres_update_timer(struct pres_cpu_state *state) 66static void pres_update_timer(struct pres_cpu_state *state)
67{ 67{
68 int local;
68 lt_t update, now; 69 lt_t update, now;
69 70
70 update = state->sup_env.next_scheduler_update; 71 update = state->sup_env.next_scheduler_update;
71 now = state->sup_env.env.current_time; 72 now = state->sup_env.env.current_time;
73
74 /* Be sure we're actually running on the right core,
75 * as pres_update_timer() is also called from pres_task_resume(),
76 * which might be called on any CPU when a thread resumes.
77 */
78 local = local_cpu_state() == state;
79
72 if (update <= now) { 80 if (update <= now) {
73 litmus_reschedule(state->cpu); 81 litmus_reschedule(state->cpu);
74 } else if (update != SUP_NO_SCHEDULER_UPDATE) { 82 } else if (likely(local && update != SUP_NO_SCHEDULER_UPDATE)) {
75 /* reprogram only if not already set correctly */ 83 /* Reprogram only if not already set correctly. */
76 if (!hrtimer_active(&state->timer) || 84 if (!hrtimer_active(&state->timer) ||
77 ktime_to_ns(hrtimer_get_expires(&state->timer)) != update) { 85 ktime_to_ns(hrtimer_get_expires(&state->timer)) != update) {
78 TRACE("canceling timer...\n"); 86 TRACE("canceling timer...\n");
@@ -81,6 +89,25 @@ static void pres_update_timer(struct pres_cpu_state *state)
81 hrtimer_start(&state->timer, ns_to_ktime(update), 89 hrtimer_start(&state->timer, ns_to_ktime(update),
82 HRTIMER_MODE_ABS_PINNED); 90 HRTIMER_MODE_ABS_PINNED);
83 } 91 }
92 } else if (unlikely(!local && update != SUP_NO_SCHEDULER_UPDATE)) {
93 /* Poke remote core only if timer needs to be set earlier than
94 * it is currently set.
95 */
96 TRACE("pres_update_timer for remote CPU %d (update=%llu, "
97 "active:%d, set:%llu)\n",
98 state->cpu,
99 update,
100 hrtimer_active(&state->timer),
101 ktime_to_ns(hrtimer_get_expires(&state->timer)));
102 if (!hrtimer_active(&state->timer) ||
103 ktime_to_ns(hrtimer_get_expires(&state->timer)) > update) {
104 TRACE("poking CPU %d so that it can update its "
105 "scheduling timer (active:%d, set:%llu)\n",
106 state->cpu,
107 hrtimer_active(&state->timer),
108 ktime_to_ns(hrtimer_get_expires(&state->timer)));
109 litmus_reschedule(state->cpu);
110 }
84 } 111 }
85} 112}
86 113
@@ -88,16 +115,27 @@ static enum hrtimer_restart on_scheduling_timer(struct hrtimer *timer)
88{ 115{
89 unsigned long flags; 116 unsigned long flags;
90 enum hrtimer_restart restart = HRTIMER_NORESTART; 117 enum hrtimer_restart restart = HRTIMER_NORESTART;
91 struct pres_cpu_state *state = local_cpu_state(); 118 struct pres_cpu_state *state;
92 lt_t update, now; 119 lt_t update, now;
93 120
121 state = container_of(timer, struct pres_cpu_state, timer);
122
123 /* The scheduling timer should only fire on the local CPU, because
124 * otherwise deadlocks via timer_cancel() are possible.
125 * Note: this does not interfere with dedicated interrupt handling, as
126 * even under dedicated interrupt handling scheduling timers for
127 * budget enforcement must occur locally on each CPU.
128 */
129 BUG_ON(state->cpu != raw_smp_processor_id());
130
94 raw_spin_lock_irqsave(&state->lock, flags); 131 raw_spin_lock_irqsave(&state->lock, flags);
95 sup_update_time(&state->sup_env, litmus_clock()); 132 sup_update_time(&state->sup_env, litmus_clock());
96 133
97 update = state->sup_env.next_scheduler_update; 134 update = state->sup_env.next_scheduler_update;
98 now = state->sup_env.env.current_time; 135 now = state->sup_env.env.current_time;
99 136
100 TRACE_CUR("on_scheduling_timer at %llu, upd:%llu\n", now, update); 137 TRACE_CUR("on_scheduling_timer at %llu, upd:%llu (for cpu=%d)\n",
138 now, update, state->cpu);
101 139
102 if (update <= now) { 140 if (update <= now) {
103 litmus_reschedule_local(); 141 litmus_reschedule_local();
@@ -173,12 +211,15 @@ static void pres_task_resume(struct task_struct *tsk)
173 struct pres_task_state* tinfo = get_pres_state(tsk); 211 struct pres_task_state* tinfo = get_pres_state(tsk);
174 struct pres_cpu_state *state = cpu_state_for(tinfo->cpu); 212 struct pres_cpu_state *state = cpu_state_for(tinfo->cpu);
175 213
176 TRACE_TASK(tsk, "wake_up at %llu\n", litmus_clock()); 214 TRACE_TASK(tsk, "thread wakes up at %llu\n", litmus_clock());
177 215
178 raw_spin_lock_irqsave(&state->lock, flags); 216 raw_spin_lock_irqsave(&state->lock, flags);
179 /* Requeue if self-suspension was already processed. */ 217 /* Requeue if self-suspension was already processed. */
180 if (state->scheduled != tsk) 218 if (state->scheduled != tsk)
181 { 219 {
220 /* Assumption: litmus_clock() is synchronized across cores,
221 * since we might not actually be executing on tinfo->cpu
222 * at the moment. */
182 sup_update_time(&state->sup_env, litmus_clock()); 223 sup_update_time(&state->sup_env, litmus_clock());
183 task_arrives(tsk); 224 task_arrives(tsk);
184 pres_update_timer(state); 225 pres_update_timer(state);
@@ -270,6 +311,8 @@ static void pres_task_new(struct task_struct *tsk, int on_runqueue,
270 } 311 }
271 312
272 if (on_runqueue || is_running) { 313 if (on_runqueue || is_running) {
314 /* Assumption: litmus_clock() is synchronized across cores
315 * [see comment in pres_task_resume()] */
273 sup_update_time(&state->sup_env, litmus_clock()); 316 sup_update_time(&state->sup_env, litmus_clock());
274 task_arrives(tsk); 317 task_arrives(tsk);
275 pres_update_timer(state); 318 pres_update_timer(state);
@@ -293,6 +336,8 @@ static void pres_task_exit(struct task_struct *tsk)
293 336
294 /* remove from queues */ 337 /* remove from queues */
295 if (is_running(tsk)) { 338 if (is_running(tsk)) {
339 /* Assumption: litmus_clock() is synchronized across cores
340 * [see comment in pres_task_resume()] */
296 sup_update_time(&state->sup_env, litmus_clock()); 341 sup_update_time(&state->sup_env, litmus_clock());
297 task_departs(tsk, 0); 342 task_departs(tsk, 0);
298 pres_update_timer(state); 343 pres_update_timer(state);