aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern B. Brandenburg <bbb@cs.unc.edu>2008-05-10 04:22:34 -0400
committerBjoern B. Brandenburg <bbb@cs.unc.edu>2008-05-10 04:22:34 -0400
commite424c53361798a31721734816ec53d29569dbbbd (patch)
tree37d2052e76f8d422b75baef1cdcc324a1fbb4890
parentd2b711fc7a253d6a33e326156b9f0eb786f483f1 (diff)
LITMUS: don't let rt_domain deadlock in global plugins
On the T2000, GSN-EDF would eventually deadlock. This was caused by a deadlock involving the release and ready locks of its rt_domain. Usually, the dependency in GSN-EDF is: function held -> required ========================================= enqueue: ready -> release gsnedf_job_release: -> ready arm_release_timer: -> release So far so good. The problem arose when hrtimer detected that the timer being armed had already expired (must have been just a few nanoseconds) and decided to call the callback directly WHILE HOLDING THE RELEASE LOCK. Which led to the following result: function held -> required CPU ==================================================== enqueue: ready -> release 5 gsnedf_job_release: release -> ready 6 We avoid this problem now by dropping the release lock in arm_release_timer() before calling the job release callback.
-rw-r--r--litmus/rt_domain.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/litmus/rt_domain.c b/litmus/rt_domain.c
index 5df3100dfb..a90cb64f0f 100644
--- a/litmus/rt_domain.c
+++ b/litmus/rt_domain.c
@@ -66,18 +66,19 @@ static void arm_release_timers(unsigned long _rt)
66{ 66{
67 rt_domain_t *rt = (rt_domain_t*) _rt; 67 rt_domain_t *rt = (rt_domain_t*) _rt;
68 unsigned long flags; 68 unsigned long flags;
69 struct list_head alt;
69 struct list_head *pos, *safe; 70 struct list_head *pos, *safe;
70 struct task_struct* t; 71 struct task_struct* t;
71 72
72 spin_lock_irqsave(&rt->release_lock, flags); 73 spin_lock_irqsave(&rt->release_lock, flags);
74 list_replace_init(&rt->release_queue, &alt);
75 spin_unlock_irqrestore(&rt->release_lock, flags);
73 76
74 list_for_each_safe(pos, safe, &rt->release_queue) { 77 list_for_each_safe(pos, safe, &alt) {
75 t = list_entry(pos, struct task_struct, rt_list); 78 t = list_entry(pos, struct task_struct, rt_list);
76 list_del(pos); 79 list_del(pos);
77 setup_job_release_timer(t); 80 setup_job_release_timer(t);
78 } 81 }
79
80 spin_unlock_irqrestore(&rt->release_lock, flags);
81} 82}
82 83
83 84