aboutsummaryrefslogtreecommitdiffstats
path: root/litmus
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2011-10-08 17:06:48 -0400
committerJonathan Herman <hermanjl@cs.unc.edu>2011-10-08 17:06:48 -0400
commit5a2b8be93c93f2c66edee2a8aff1554778959e35 (patch)
tree931b54656e800f89b5479be520b9a9ca29ed6030 /litmus
parent61ce17e3edbf33e49adb5536c9904b735e58c774 (diff)
Fixed timer issue and atomic remove issue in level A domain.
Timers had an issue where they couldn't be cancelled before they migrated. Now when you set the start_on_info to inactive, it will prevent a timer from being armed. When a task is being blocked and preempted concurrently, the blocking code needs to be able to prevent the task from being scheduled on another CPU. This did not work for CE domains. Added a per-domain remove function which, for ce domains, will prevent a task from being returned by the domain.
Diffstat (limited to 'litmus')
-rw-r--r--litmus/ce_domain.c22
-rw-r--r--litmus/event_group.c21
-rw-r--r--litmus/rt_domain.c13
-rw-r--r--litmus/sched_mc.c36
4 files changed, 57 insertions, 35 deletions
diff --git a/litmus/ce_domain.c b/litmus/ce_domain.c
index c3ddc9dd63ad..5e1f7ccc000c 100644
--- a/litmus/ce_domain.c
+++ b/litmus/ce_domain.c
@@ -30,6 +30,8 @@ void ce_requeue(domain_t *dom, struct task_struct *ts)
30 "expected_job: %3u\n", 30 "expected_job: %3u\n",
31 asleep, just_finished, expected_job); 31 asleep, just_finished, expected_job);
32 32
33 tsk_mc_data(ts)->mc_task.lvl_a_eligible = 1;
34
33 /* When coming from job completion, the task will be asleep. */ 35 /* When coming from job completion, the task will be asleep. */
34 if (asleep && just_finished < expected_job) { 36 if (asleep && just_finished < expected_job) {
35 TRACE_MC_TASK(ts, "appears behind\n"); 37 TRACE_MC_TASK(ts, "appears behind\n");
@@ -41,18 +43,27 @@ void ce_requeue(domain_t *dom, struct task_struct *ts)
41} 43}
42 44
43/* 45/*
46 *
47 */
48void ce_remove(domain_t *dom, struct task_struct *ts)
49{
50 tsk_mc_data(ts)->mc_task.lvl_a_eligible = 0;
51}
52
53/*
44 * ce_take_ready and ce_peek_ready 54 * ce_take_ready and ce_peek_ready
45 */ 55 */
46struct task_struct* ce_peek_and_take_ready(domain_t *dom) 56struct task_struct* ce_peek_and_take_ready(domain_t *dom)
47{ 57{
48 struct task_struct *ret = NULL;
49 const struct ce_dom_data *ce_data = dom->data; 58 const struct ce_dom_data *ce_data = dom->data;
50 const int exists = NULL != ce_data->should_schedule; 59 struct task_struct *ret = NULL, *sched = ce_data->should_schedule;
51 const int blocked = exists && !is_running(ce_data->should_schedule); 60 const int exists = NULL != sched;
61 const int blocked = exists && !is_running(sched);
62 const int elig = exists && tsk_mc_data(sched)->mc_task.lvl_a_eligible;
52 63
53 /* Return the task we should schedule if it is not blocked or sleeping. */ 64 /* Return the task we should schedule if it is not blocked or sleeping. */
54 if (exists && !blocked) 65 if (exists && !blocked && elig)
55 ret = ce_data->should_schedule; 66 ret = sched;
56 return ret; 67 return ret;
57} 68}
58 69
@@ -78,6 +89,7 @@ void ce_domain_init(domain_t *dom,
78 domain_init(dom, lock, requeue, peek_ready, take_ready, preempt_needed, 89 domain_init(dom, lock, requeue, peek_ready, take_ready, preempt_needed,
79 task_prio); 90 task_prio);
80 dom->data = dom_data; 91 dom->data = dom_data;
92 dom->remove = ce_remove;
81 dom_data->cpu = cpu; 93 dom_data->cpu = cpu;
82#ifdef CONFIG_MERGE_TIMERS 94#ifdef CONFIG_MERGE_TIMERS
83 init_event(&dom_data->event, CRIT_LEVEL_A, ce_timer_callback, 95 init_event(&dom_data->event, CRIT_LEVEL_A, ce_timer_callback,
diff --git a/litmus/event_group.c b/litmus/event_group.c
index daf964fbb8cc..40c2f9bf2d18 100644
--- a/litmus/event_group.c
+++ b/litmus/event_group.c
@@ -71,18 +71,19 @@ void insert_event(struct event_list *el, struct rt_event *e)
71 queued = list_entry(pos, struct rt_event, list); 71 queued = list_entry(pos, struct rt_event, list);
72 last = pos; 72 last = pos;
73 if (e->prio < queued->prio) { 73 if (e->prio < queued->prio) {
74 VTRACE("Inserting priority %d 0x%p before %d 0x%p " 74 VTRACE("Inserting priority %d event 0x%p before %d 0x%p "
75 "in 0x%p, pos 0x%p\n", e->prio, &e->list, 75 "in 0x%p, pos 0x%p\n", e->prio, e,
76 queued->prio, &queued->list, el, pos); 76 queued->prio, &queued->list, el, pos);
77 BUG_ON(!list_empty(&e->list)); 77 BUG_ON(!list_empty(&e->list));
78 list_add_tail(&e->list, pos); 78 list_add_tail(&e->list, pos);
79 return; 79 return;
80 } 80 }
81 } 81 }
82 VTRACE("Inserting priority %d 0x%p at end of 0x%p, last 0x%p\n", 82 VTRACE("Inserting priority %d event 0x%p at end of 0x%p, last 0x%p\n",
83 e->prio, &el->list, el, last); 83 e->prio, e, el, last);
84 BUG_ON(!list_empty(&e->list)); 84 BUG_ON(!list_empty(&e->list));
85 list_add(&e->list, (last) ? last : pos); 85 list_add(&e->list, (last) ? last : pos);
86 VTRACE("Singular? %d\n", list_is_singular(&el->events));
86} 87}
87 88
88/* 89/*
@@ -100,7 +101,7 @@ static struct event_list* get_event_list(struct event_group *group,
100 unsigned int slot = time2slot(fire); 101 unsigned int slot = time2slot(fire);
101 int remaining = 300; 102 int remaining = 300;
102 103
103 VTRACE("Getting list for %llu, event 0x%p\n", fire, e); 104 VTRACE("Getting list for time %llu, event 0x%p\n", fire, e);
104 105
105 /* Initialize pos for the case that the list is empty */ 106 /* Initialize pos for the case that the list is empty */
106 pos = group->event_queue[slot].next; 107 pos = group->event_queue[slot].next;
@@ -145,7 +146,7 @@ static struct event_list* get_event_list(struct event_group *group,
145static void reinit_event_list(struct rt_event *e) 146static void reinit_event_list(struct rt_event *e)
146{ 147{
147 struct event_list *el = e->event_list; 148 struct event_list *el = e->event_list;
148 VTRACE("Reinitting 0x%p for event 0x%p\n", el, e); 149 VTRACE("Reinitting list 0x%p for event 0x%p\n", el, e);
149 BUG_ON(hrtimer_try_to_cancel(&el->timer) == 1); 150 BUG_ON(hrtimer_try_to_cancel(&el->timer) == 1);
150 INIT_LIST_HEAD(&el->events); 151 INIT_LIST_HEAD(&el->events);
151 atomic_set(&el->info.state, HRTIMER_START_ON_INACTIVE); 152 atomic_set(&el->info.state, HRTIMER_START_ON_INACTIVE);
@@ -213,13 +214,14 @@ void cancel_event(struct rt_event *e)
213 /* If our event_list contains any events, it is in use */ 214 /* If our event_list contains any events, it is in use */
214 raw_spin_lock(&group->queue_lock); 215 raw_spin_lock(&group->queue_lock);
215 if (!list_empty(&e->event_list->events)) { 216 if (!list_empty(&e->event_list->events)) {
217 VTRACE("List 0x%p is not empty\n", e->event_list);
216 218
217 /* If our event_list contains events, we are the first element 219 /* If our event_list contains events, we are the first element
218 * in that list. If there is anyone after us in the list, then 220 * in that list. If there is anyone after us in the list, then
219 * swap our list with theirs to that the event_list can still 221 * swap our list with theirs to that the event_list can still
220 * trigger the queued events. 222 * trigger the queued events.
221 */ 223 */
222 if (!list_is_singular(&e->list)) { 224 if (!list_is_singular(&e->event_list->events)) {
223 swap = list_entry(e->list.next, struct rt_event, list); 225 swap = list_entry(e->list.next, struct rt_event, list);
224 VTRACE("Swapping with event 0x%p of priority %d\n", 226 VTRACE("Swapping with event 0x%p of priority %d\n",
225 swap, swap->prio); 227 swap, swap->prio);
@@ -230,8 +232,11 @@ void cancel_event(struct rt_event *e)
230 } 232 }
231 233
232 /* Disable the event_list */ 234 /* Disable the event_list */
235 atomic_set(&e->event_list->info.state, HRTIMER_START_ON_INACTIVE);
233 hrtimer_try_to_cancel(&e->event_list->timer); 236 hrtimer_try_to_cancel(&e->event_list->timer);
234 list_del_init(&e->event_list->list); 237 list_del_init(&e->event_list->list);
238 } else {
239 VTRACE("List 0x%p is empty\n", e->event_list);
235 } 240 }
236 list_del_init(&e->list); 241 list_del_init(&e->list);
237 raw_spin_unlock(&group->queue_lock); 242 raw_spin_unlock(&group->queue_lock);
@@ -248,7 +253,7 @@ struct event_list* event_list_alloc(int gfp_flags)
248 INIT_LIST_HEAD(&el->list); 253 INIT_LIST_HEAD(&el->list);
249 el->timer.function = on_timer; 254 el->timer.function = on_timer;
250 } else { 255 } else {
251 VTRACE("Failed to allocate event list!"); 256 VTRACE("Failed to allocate event list!\n");
252 printk(KERN_CRIT "Failed to allocate event list.\n"); 257 printk(KERN_CRIT "Failed to allocate event list.\n");
253 BUG(); 258 BUG();
254 } 259 }
diff --git a/litmus/rt_domain.c b/litmus/rt_domain.c
index ffb3cab9cffd..93f2a35fb29d 100644
--- a/litmus/rt_domain.c
+++ b/litmus/rt_domain.c
@@ -20,7 +20,7 @@
20#include <litmus/bheap.h> 20#include <litmus/bheap.h>
21 21
22/* Uncomment when debugging timer races... */ 22/* Uncomment when debugging timer races... */
23#if 0 23#if 1
24#define VTRACE_TASK TRACE_TASK 24#define VTRACE_TASK TRACE_TASK
25#define VTRACE TRACE 25#define VTRACE TRACE
26#else 26#else
@@ -293,8 +293,7 @@ static void setup_release(rt_domain_t *_rt)
293#else 293#else
294 arm_release_timer(rh); 294 arm_release_timer(rh);
295#endif 295#endif
296 } else 296 }
297 VTRACE_TASK(t, "0x%p is not my timer\n", &rh->timer);
298 } 297 }
299} 298}
300 299
@@ -439,6 +438,13 @@ static struct task_struct* pd_peek_ready(domain_t *dom)
439 return __next_ready((rt_domain_t*)dom->data); 438 return __next_ready((rt_domain_t*)dom->data);
440} 439}
441 440
441static void pd_remove(domain_t *dom, struct task_struct *task)
442{
443 if (is_queued(task)) {
444 remove((rt_domain_t*)dom->data, task);
445 }
446}
447
442/* pd_domain_init - create a generic domain wrapper for an rt_domain 448/* pd_domain_init - create a generic domain wrapper for an rt_domain
443 */ 449 */
444void pd_domain_init(domain_t *dom, 450void pd_domain_init(domain_t *dom,
@@ -453,5 +459,6 @@ void pd_domain_init(domain_t *dom,
453 domain_init(dom, &domain->ready_lock, 459 domain_init(dom, &domain->ready_lock,
454 pd_requeue, pd_peek_ready, pd_take_ready, 460 pd_requeue, pd_peek_ready, pd_take_ready,
455 preempt_needed, priority); 461 preempt_needed, priority);
462 dom->remove = pd_remove;
456 dom->data = domain; 463 dom->data = domain;
457} 464}
diff --git a/litmus/sched_mc.c b/litmus/sched_mc.c
index b2a9ca205be4..f360abf34035 100644
--- a/litmus/sched_mc.c
+++ b/litmus/sched_mc.c
@@ -183,7 +183,7 @@ static void update_ghost_time(struct task_struct *p)
183static inline void update_crit_position(struct crit_entry *ce) 183static inline void update_crit_position(struct crit_entry *ce)
184{ 184{
185 struct bheap *heap; 185 struct bheap *heap;
186 if (is_global(ce->domain)) { 186 if (is_global(ce->domain) && ce->usable) {
187 heap = domain_data(ce->domain)->heap; 187 heap = domain_data(ce->domain)->heap;
188 BUG_ON(!heap); 188 BUG_ON(!heap);
189 BUG_ON(!bheap_node_in_heap(ce->node)); 189 BUG_ON(!bheap_node_in_heap(ce->node));
@@ -451,9 +451,18 @@ static void check_for_preempt(struct domain *dom)
451 entry = crit_cpu(ce); 451 entry = crit_cpu(ce);
452 preempted = 0; 452 preempted = 0;
453 raw_spin_lock(&entry->lock); 453 raw_spin_lock(&entry->lock);
454 if (ce->usable && dom->preempt_needed(dom, ce->linked)){ 454
455 if (!ce->usable) {
456 TRACE_CRIT_ENTRY(ce, "Removing");
457 bheap_delete(cpu_lower_prio,
458 domain_data(dom)->heap, ce->node);
459 continue;
460 }
461 if (dom->preempt_needed(dom, ce->linked)){
455 preempted = 1; 462 preempted = 1;
456 preempt(dom, ce); 463 preempt(dom, ce);
464 } else {
465 TRACE_CRIT_ENTRY(ce, "Stopped global check\n");
457 } 466 }
458 raw_spin_unlock(&entry->lock); 467 raw_spin_unlock(&entry->lock);
459 } 468 }
@@ -486,10 +495,10 @@ static void remove_from_all(struct task_struct* task)
486 495
487 raw_spin_lock(dom->lock); 496 raw_spin_lock(dom->lock);
488 497
498 /* Remove the task from any CPU state */
489 if (task->rt_param.linked_on != NO_CPU) { 499 if (task->rt_param.linked_on != NO_CPU) {
490 entry = &per_cpu(cpus, task->rt_param.linked_on); 500 entry = &per_cpu(cpus, task->rt_param.linked_on);
491 raw_spin_lock(&entry->lock); 501 raw_spin_lock(&entry->lock);
492
493 /* Unlink only if task is still linked post lock */ 502 /* Unlink only if task is still linked post lock */
494 ce = &entry->crit_entries[tsk_mc_crit(task)]; 503 ce = &entry->crit_entries[tsk_mc_crit(task)];
495 if (task->rt_param.linked_on != NO_CPU) { 504 if (task->rt_param.linked_on != NO_CPU) {
@@ -501,23 +510,15 @@ static void remove_from_all(struct task_struct* task)
501 link_task_to_cpu(entry, NULL); 510 link_task_to_cpu(entry, NULL);
502 } 511 }
503 } 512 }
504
505 if (update) 513 if (update)
506 update_crit_levels(entry); 514 update_crit_levels(entry);
507 else 515 else
508 raw_spin_unlock(&entry->lock); 516 raw_spin_unlock(&entry->lock);
509 } 517 }
510 518
511 if (is_queued(task)) { 519 /* Ensure the task isn't returned by its domain */
512 /* This is an interesting situation: t is scheduled, 520 dom->remove(dom, task);
513 * but was just recently unlinked. It cannot be 521
514 * linked anywhere else (because then it would have
515 * been relinked to this CPU), thus it must be in some
516 * queue. We must remove it from the list in this
517 * case.
518 */
519 remove((rt_domain_t*)get_task_domain(task)->data, task);
520 }
521 BUG_ON(is_queued(task)); 522 BUG_ON(is_queued(task));
522 raw_spin_unlock(dom->lock); 523 raw_spin_unlock(dom->lock);
523} 524}
@@ -853,12 +854,9 @@ static struct task_struct* mc_schedule(struct task_struct * prev)
853 854
854 if (exists) { 855 if (exists) {
855 entry->scheduled->rt_param.scheduled_on = NO_CPU; 856 entry->scheduled->rt_param.scheduled_on = NO_CPU;
856 TRACE(TS
857 " blocks:%d out_of_time:%d sleep:%d preempt:%d "
858 "state:%d sig:%d global:%d\n", TA(prev),
859 blocks, out_of_time, sleep, preempt,
860 prev->state, signal_pending(prev), global);
861 } 857 }
858 TRACE(TS " blocks:%d out_of_time:%d sleep:%d preempt:%d\n",
859 TA(prev), blocks, out_of_time, sleep, preempt);
862 raw_spin_unlock(&entry->lock); 860 raw_spin_unlock(&entry->lock);
863 861
864 862