diff options
author | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2008-05-10 04:22:34 -0400 |
---|---|---|
committer | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2008-05-10 04:22:34 -0400 |
commit | e424c53361798a31721734816ec53d29569dbbbd (patch) | |
tree | 37d2052e76f8d422b75baef1cdcc324a1fbb4890 | |
parent | d2b711fc7a253d6a33e326156b9f0eb786f483f1 (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.c | 7 |
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 | ||