diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2011-10-07 18:13:28 -0400 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2011-10-07 18:13:28 -0400 |
commit | 054b92b95cfc2249ff7c1b110fb9aee8fa43378c (patch) | |
tree | 825a392b4b3b0a536e8dfc1c770546ea073f5739 | |
parent | c0c51f136eae07e09bff56baa4954c4567d558fe (diff) |
Fixed global task deadlock
-rw-r--r-- | litmus/sched_mc.c | 49 | ||||
-rw-r--r-- | litmus/sched_mc_ce.c | 2 |
2 files changed, 33 insertions, 18 deletions
diff --git a/litmus/sched_mc.c b/litmus/sched_mc.c index 8e261426171e..90a60c568183 100644 --- a/litmus/sched_mc.c +++ b/litmus/sched_mc.c | |||
@@ -176,15 +176,30 @@ static void update_ghost_time(struct task_struct *p) | |||
176 | } | 176 | } |
177 | } | 177 | } |
178 | 178 | ||
179 | /* | ||
180 | * Update crit entry position in a global heap. Caller must hold | ||
181 | * @ce's domain lock. | ||
182 | */ | ||
183 | static inline void update_crit_position(struct crit_entry *ce) | ||
184 | { | ||
185 | struct bheap *heap; | ||
186 | if (is_global(ce->domain)) { | ||
187 | heap = domain_data(ce->domain)->heap; | ||
188 | BUG_ON(!heap); | ||
189 | BUG_ON(!bheap_node_in_heap(ce->node)); | ||
190 | bheap_delete(cpu_lower_prio, heap, ce->node); | ||
191 | bheap_insert(cpu_lower_prio, heap, ce->node); | ||
192 | } | ||
193 | } | ||
194 | |||
179 | /** | 195 | /** |
180 | * link_task_to_crit() - Logically run a task at a criticality level. | 196 | * link_task_to_crit() - Logically run a task at a criticality level. |
181 | * Caller must hold @ce's domain's lock. | 197 | * Caller must hold @ce's CPU lock. |
182 | */ | 198 | */ |
183 | static void link_task_to_crit(struct crit_entry *ce, | 199 | static void link_task_to_crit(struct crit_entry *ce, |
184 | struct task_struct *task) | 200 | struct task_struct *task) |
185 | { | 201 | { |
186 | lt_t when_to_fire; | 202 | lt_t when_to_fire; |
187 | struct bheap *heap; | ||
188 | 203 | ||
189 | TRACE_CRIT_ENTRY(ce, "Linking " TS, TA(task)); | 204 | TRACE_CRIT_ENTRY(ce, "Linking " TS, TA(task)); |
190 | BUG_ON(!ce->usable && task); | 205 | BUG_ON(!ce->usable && task); |
@@ -221,15 +236,6 @@ static void link_task_to_crit(struct crit_entry *ce, | |||
221 | arm_ghost(ce, when_to_fire); | 236 | arm_ghost(ce, when_to_fire); |
222 | } | 237 | } |
223 | } | 238 | } |
224 | |||
225 | /* Update global heap node position */ | ||
226 | if (is_global(ce->domain)) { | ||
227 | heap = domain_data(ce->domain)->heap; | ||
228 | BUG_ON(!heap); | ||
229 | BUG_ON(!bheap_node_in_heap(ce->node)); | ||
230 | bheap_delete(cpu_lower_prio, heap, ce->node); | ||
231 | bheap_insert(cpu_lower_prio, heap, ce->node); | ||
232 | } | ||
233 | } | 239 | } |
234 | 240 | ||
235 | static void check_for_preempt(struct domain*); | 241 | static void check_for_preempt(struct domain*); |
@@ -351,18 +357,18 @@ static void preempt(struct domain *dom, struct crit_entry *ce) | |||
351 | { | 357 | { |
352 | struct task_struct *task = dom->take_ready(dom); | 358 | struct task_struct *task = dom->take_ready(dom); |
353 | struct cpu_entry *entry = crit_cpu(ce); | 359 | struct cpu_entry *entry = crit_cpu(ce); |
354 | struct task_struct *old; | 360 | struct task_struct *old = ce->linked; |
355 | 361 | ||
356 | BUG_ON(!task); | 362 | BUG_ON(!task); |
357 | TRACE_CRIT_ENTRY(ce, "Preempted by " TS, TA(task)); | 363 | TRACE_CRIT_ENTRY(ce, "Preempted by " TS, TA(task)); |
358 | 364 | ||
359 | old = ce->linked; | ||
360 | |||
361 | /* Per-domain preemption */ | 365 | /* Per-domain preemption */ |
362 | if (old && can_requeue(old)) { | 366 | if (old && can_requeue(old)) { |
363 | dom->requeue(dom, old); | 367 | dom->requeue(dom, old); |
364 | } | 368 | } |
365 | link_task_to_crit(ce, task); | 369 | link_task_to_crit(ce, task); |
370 | update_crit_position(ce); | ||
371 | |||
366 | /* Preempt actual execution if this is a running task */ | 372 | /* Preempt actual execution if this is a running task */ |
367 | if (!is_ghost(task)) { | 373 | if (!is_ghost(task)) { |
368 | link_task_to_cpu(entry, task); | 374 | link_task_to_cpu(entry, task); |
@@ -412,8 +418,18 @@ static void update_crit_levels(struct cpu_entry *entry) | |||
412 | /* Re-admit tasks to the system */ | 418 | /* Re-admit tasks to the system */ |
413 | for (i = level + 1; i < NUM_CRIT_LEVELS; i++) { | 419 | for (i = level + 1; i < NUM_CRIT_LEVELS; i++) { |
414 | ce = &entry->crit_entries[i]; | 420 | ce = &entry->crit_entries[i]; |
415 | if (readmit[i]) | 421 | if (readmit[i]) { |
422 | /* Position of the crit entry changed earlier. | ||
423 | * We couldn't update it while we held the entry | ||
424 | * lock. Update it here. | ||
425 | */ | ||
426 | if (is_global(ce->domain)) { | ||
427 | raw_spin_lock(ce->domain->lock); | ||
428 | update_crit_position(ce); | ||
429 | raw_spin_unlock(ce->domain->lock); | ||
430 | } | ||
416 | low_prio_arrival(readmit[i]); | 431 | low_prio_arrival(readmit[i]); |
432 | } | ||
417 | } | 433 | } |
418 | } | 434 | } |
419 | 435 | ||
@@ -479,6 +495,7 @@ static void remove_from_all(struct task_struct* task) | |||
479 | if (task->rt_param.linked_on != NO_CPU) { | 495 | if (task->rt_param.linked_on != NO_CPU) { |
480 | BUG_ON(ce->linked != task); | 496 | BUG_ON(ce->linked != task); |
481 | link_task_to_crit(ce, NULL); | 497 | link_task_to_crit(ce, NULL); |
498 | update_crit_position(ce); | ||
482 | if (!is_ghost(task) && entry->linked == task) { | 499 | if (!is_ghost(task) && entry->linked == task) { |
483 | update = 1; | 500 | update = 1; |
484 | link_task_to_cpu(entry, NULL); | 501 | link_task_to_cpu(entry, NULL); |
@@ -577,7 +594,6 @@ static enum hrtimer_restart mc_ghost_exhausted(struct hrtimer *timer) | |||
577 | update_ghost_time(ce->linked); | 594 | update_ghost_time(ce->linked); |
578 | if (tsk_mc_data(ce->linked)->mc_job.ghost_budget == 0) { | 595 | if (tsk_mc_data(ce->linked)->mc_job.ghost_budget == 0) { |
579 | tmp = ce->linked; | 596 | tmp = ce->linked; |
580 | link_task_to_crit(ce, NULL); | ||
581 | } | 597 | } |
582 | } | 598 | } |
583 | raw_spin_unlock(&crit_cpu(ce)->lock); | 599 | raw_spin_unlock(&crit_cpu(ce)->lock); |
@@ -886,6 +902,7 @@ static struct task_struct* mc_schedule(struct task_struct * prev) | |||
886 | if (!entry->linked && ce->usable && !ce->linked && dtask) { | 902 | if (!entry->linked && ce->usable && !ce->linked && dtask) { |
887 | dom->take_ready(dom); | 903 | dom->take_ready(dom); |
888 | link_task_to_crit(ce, dtask); | 904 | link_task_to_crit(ce, dtask); |
905 | update_crit_position(ce); | ||
889 | ready_task = (is_ghost(dtask)) ? NULL : dtask; | 906 | ready_task = (is_ghost(dtask)) ? NULL : dtask; |
890 | 907 | ||
891 | /* Task found! */ | 908 | /* Task found! */ |
diff --git a/litmus/sched_mc_ce.c b/litmus/sched_mc_ce.c index ffcc25873581..5a19628b06df 100644 --- a/litmus/sched_mc_ce.c +++ b/litmus/sched_mc_ce.c | |||
@@ -421,10 +421,8 @@ void mc_ce_task_exit_common(struct task_struct *ts) | |||
421 | const int lvl_a_id = tsk_mc_data(ts)->mc_task.lvl_a_id; | 421 | const int lvl_a_id = tsk_mc_data(ts)->mc_task.lvl_a_id; |
422 | struct ce_pid_table *pid_table = get_pid_table(ce_data->cpu); | 422 | struct ce_pid_table *pid_table = get_pid_table(ce_data->cpu); |
423 | 423 | ||
424 | BUG_ON(task_cpu(ts) != get_partition(ts)); | ||
425 | BUG_ON(CRIT_LEVEL_A != tsk_mc_crit(ts)); | 424 | BUG_ON(CRIT_LEVEL_A != tsk_mc_crit(ts)); |
426 | BUG_ON(lvl_a_id >= pid_table->num_pid_entries); | 425 | BUG_ON(lvl_a_id >= pid_table->num_pid_entries); |
427 | BUG_ON(ce_data->cpu != task_cpu(ts)); | ||
428 | 426 | ||
429 | raw_spin_lock_irqsave(dom->lock, flags); | 427 | raw_spin_lock_irqsave(dom->lock, flags); |
430 | pid = pid_table->entries[lvl_a_id].pid; | 428 | pid = pid_table->entries[lvl_a_id].pid; |