aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-09-17 19:31:04 -0400
committerGlenn Elliott <gelliott@cs.unc.edu>2012-09-17 19:34:45 -0400
commitd9b5000b74bbc468624f877495443b33f9511922 (patch)
treec0efc70114f208916f0b0b32f85d8c80ab25b89e
parentb247fd41c493e7bd3cd33cb1c4b7c46420d16364 (diff)
Fixed three bugs with aux threads and nested locks
Fixes two bugs with nested locks: 1) List of aux threads could become corrupted. -- moved modifications to be within scheduler lock. 2) Fixed bad EDF comparison ordering that could lead to schedule thrashing in an infinite loop. 3) Prevent aux threads from inheriting a priority from a task that is blocked on a real-time litmus lock. (since the aux threads can't possibly hold these locks, we don't have to worry about inheritance.)
-rw-r--r--include/litmus/locking.h3
-rw-r--r--include/litmus/rt_param.h1
-rw-r--r--litmus/aux_tasks.c58
-rw-r--r--litmus/edf_common.c10
-rw-r--r--litmus/ikglp_lock.c2
-rw-r--r--litmus/kfmlp_lock.c2
-rw-r--r--litmus/locking.c29
-rw-r--r--litmus/rsm_lock.c2
-rw-r--r--litmus/sched_cedf.c17
-rw-r--r--litmus/sched_gsn_edf.c19
10 files changed, 98 insertions, 45 deletions
diff --git a/include/litmus/locking.h b/include/litmus/locking.h
index 296bbf6f7af0..4a5f198a0407 100644
--- a/include/litmus/locking.h
+++ b/include/litmus/locking.h
@@ -156,5 +156,8 @@ struct litmus_lock_ops {
156#endif 156#endif
157 157
158 158
159void suspend_for_lock(void);
160
161
159#endif 162#endif
160 163
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h
index 8b9e14c461dc..44f85a366574 100644
--- a/include/litmus/rt_param.h
+++ b/include/litmus/rt_param.h
@@ -288,6 +288,7 @@ struct rt_param {
288#ifdef CONFIG_REALTIME_AUX_TASKS 288#ifdef CONFIG_REALTIME_AUX_TASKS
289 unsigned int is_aux_task:1; 289 unsigned int is_aux_task:1;
290 unsigned int has_aux_tasks:1; 290 unsigned int has_aux_tasks:1;
291 unsigned int hide_from_aux_tasks:1;
291 292
292 struct list_head aux_task_node; 293 struct list_head aux_task_node;
293 struct binheap_node aux_task_owner_node; 294 struct binheap_node aux_task_owner_node;
diff --git a/litmus/aux_tasks.c b/litmus/aux_tasks.c
index b0617accdf7f..efda7dc0bd76 100644
--- a/litmus/aux_tasks.c
+++ b/litmus/aux_tasks.c
@@ -55,7 +55,7 @@ int exit_aux_task(struct task_struct *t)
55 tsk_rt(t)->is_aux_task = 0; 55 tsk_rt(t)->is_aux_task = 0;
56 56
57 if (tsk_rt(t)->inh_task) { 57 if (tsk_rt(t)->inh_task) {
58 litmus->decrease_prio(t, NULL); 58 litmus->__decrease_prio(t, NULL);
59 } 59 }
60 60
61 return retval; 61 return retval;
@@ -114,31 +114,37 @@ int aux_task_owner_increase_priority(struct task_struct *t)
114 int retval = 0; 114 int retval = 0;
115 struct task_struct *leader; 115 struct task_struct *leader;
116 struct task_struct *hp = NULL; 116 struct task_struct *hp = NULL;
117 struct task_struct *hp_eff = NULL;
117 118
118 BUG_ON(!tsk_rt(t)->has_aux_tasks);
119 BUG_ON(!is_realtime(t)); 119 BUG_ON(!is_realtime(t));
120 BUG_ON(!binheap_is_in_heap(&tsk_rt(t)->aux_task_owner_node)); 120 BUG_ON(!tsk_rt(t)->has_aux_tasks);
121 121
122 leader = t->group_leader; 122 leader = t->group_leader;
123 123
124 if (!binheap_is_in_heap(&tsk_rt(t)->aux_task_owner_node)) {
125 WARN_ON(!is_running(t));
126 TRACE_CUR("aux tasks may not inherit from %s/%d in group %s/%d\n",
127 t->comm, t->pid, leader->comm, leader->pid);
128 goto out;
129 }
130
124 TRACE_CUR("task %s/%d in group %s/%d increasing priority.\n", t->comm, t->pid, leader->comm, leader->pid); 131 TRACE_CUR("task %s/%d in group %s/%d increasing priority.\n", t->comm, t->pid, leader->comm, leader->pid);
125 132
126 hp = container_of(binheap_top_entry(&tsk_aux(leader)->aux_task_owners, struct rt_param, aux_task_owner_node), 133 hp = container_of(binheap_top_entry(&tsk_aux(leader)->aux_task_owners, struct rt_param, aux_task_owner_node),
127 struct task_struct, rt_param); 134 struct task_struct, rt_param);
135 hp_eff = effective_priority(hp);
128 136
129 if (hp == t) { 137 if (hp != t) { /* our position in the heap may have changed. hp is already at the root. */
130 goto out; // already hp, nothing to do. 138 binheap_decrease(&tsk_rt(t)->aux_task_owner_node, &tsk_aux(leader)->aux_task_owners);
131 } 139 }
132 140
133 binheap_decrease(&tsk_rt(t)->aux_task_owner_node, &tsk_aux(leader)->aux_task_owners);
134
135 hp = container_of(binheap_top_entry(&tsk_aux(leader)->aux_task_owners, struct rt_param, aux_task_owner_node), 141 hp = container_of(binheap_top_entry(&tsk_aux(leader)->aux_task_owners, struct rt_param, aux_task_owner_node),
136 struct task_struct, rt_param); 142 struct task_struct, rt_param);
137 143
138 if (hp == t) { 144 if (effective_priority(hp) != hp_eff) { /* the eff. prio. of hp has changed */
145 hp_eff = effective_priority(hp);
139 TRACE_CUR("%s/%d is new hp in group %s/%d.\n", t->comm, t->pid, leader->comm, leader->pid); 146 TRACE_CUR("%s/%d is new hp in group %s/%d.\n", t->comm, t->pid, leader->comm, leader->pid);
140 retval = aux_tasks_increase_priority(leader, 147 retval = aux_tasks_increase_priority(leader, hp_eff);
141 (tsk_rt(hp)->inh_task) ? tsk_rt(hp)->inh_task : hp);
142 } 148 }
143 149
144out: 150out:
@@ -150,30 +156,41 @@ int aux_task_owner_decrease_priority(struct task_struct *t)
150 int retval = 0; 156 int retval = 0;
151 struct task_struct *leader; 157 struct task_struct *leader;
152 struct task_struct *hp = NULL; 158 struct task_struct *hp = NULL;
153 struct task_struct *new_hp = NULL; 159 struct task_struct *hp_eff = NULL;
154 160
155 BUG_ON(!tsk_rt(t)->has_aux_tasks);
156 BUG_ON(!is_realtime(t)); 161 BUG_ON(!is_realtime(t));
157 BUG_ON(!binheap_is_in_heap(&tsk_rt(t)->aux_task_owner_node)); 162 BUG_ON(!tsk_rt(t)->has_aux_tasks);
158 163
159 leader = t->group_leader; 164 leader = t->group_leader;
160 165
166 if (!binheap_is_in_heap(&tsk_rt(t)->aux_task_owner_node)) {
167 WARN_ON(!is_running(t));
168 TRACE_CUR("aux tasks may not inherit from %s/%d in group %s/%d\n",
169 t->comm, t->pid, leader->comm, leader->pid);
170 goto out;
171 }
172
161 TRACE_CUR("task %s/%d in group %s/%d decresing priority.\n", t->comm, t->pid, leader->comm, leader->pid); 173 TRACE_CUR("task %s/%d in group %s/%d decresing priority.\n", t->comm, t->pid, leader->comm, leader->pid);
162 174
163 hp = container_of(binheap_top_entry(&tsk_aux(leader)->aux_task_owners, struct rt_param, aux_task_owner_node), 175 hp = container_of(binheap_top_entry(&tsk_aux(leader)->aux_task_owners, struct rt_param, aux_task_owner_node),
164 struct task_struct, rt_param); 176 struct task_struct, rt_param);
177 hp_eff = effective_priority(hp);
165 binheap_delete(&tsk_rt(t)->aux_task_owner_node, &tsk_aux(leader)->aux_task_owners); 178 binheap_delete(&tsk_rt(t)->aux_task_owner_node, &tsk_aux(leader)->aux_task_owners);
166 binheap_add(&tsk_rt(t)->aux_task_owner_node, &tsk_aux(leader)->aux_task_owners, 179 binheap_add(&tsk_rt(t)->aux_task_owner_node, &tsk_aux(leader)->aux_task_owners,
167 struct rt_param, aux_task_owner_node); 180 struct rt_param, aux_task_owner_node);
168 new_hp = container_of(binheap_top_entry(&tsk_aux(leader)->aux_task_owners, struct rt_param, aux_task_owner_node),
169 struct task_struct, rt_param);
170 181
171 if (hp == t && new_hp != t) { 182 if (hp == t) { /* t was originally the hp */
172 TRACE_CUR("%s/%d is no longer hp in group %s/%d.\n", t->comm, t->pid, leader->comm, leader->pid); 183 struct task_struct *new_hp =
173 retval = aux_tasks_decrease_priority(leader, 184 container_of(binheap_top_entry(&tsk_aux(leader)->aux_task_owners, struct rt_param, aux_task_owner_node),
174 (tsk_rt(new_hp)->inh_task) ? tsk_rt(new_hp)->inh_task : new_hp); 185 struct task_struct, rt_param);
186 if (effective_priority(new_hp) != hp_eff) { /* eff prio. of hp has changed */
187 hp_eff = effective_priority(new_hp);
188 TRACE_CUR("%s/%d is no longer hp in group %s/%d.\n", t->comm, t->pid, leader->comm, leader->pid);
189 retval = aux_tasks_decrease_priority(leader, hp_eff);
190 }
175 } 191 }
176 192
193out:
177 return retval; 194 return retval;
178} 195}
179 196
@@ -302,8 +319,7 @@ static long __do_enable_aux_tasks(void)
302 tsk_rt(t)->task_params.period); 319 tsk_rt(t)->task_params.period);
303 320
304 /* inspect heap_node to see if it is an rt task */ 321 /* inspect heap_node to see if it is an rt task */
305 if (tsk_rt(t)->task_params.period == 0) { //|| 322 if (tsk_rt(t)->task_params.period == 0) {
306 // tsk_rt(t)->task_params.period == MAGIC_AUX_TASK_PERIOD) {
307 if (!tsk_rt(t)->is_aux_task) { 323 if (!tsk_rt(t)->is_aux_task) {
308 TRACE_CUR("AUX task in %s/%d: %s/%d:\n", leader->comm, leader->pid, t->comm, t->pid); 324 TRACE_CUR("AUX task in %s/%d: %s/%d:\n", leader->comm, leader->pid, t->comm, t->pid);
309 /* hasn't been aux_tasks_increase_priorityted into rt. make it a aux. */ 325 /* hasn't been aux_tasks_increase_priorityted into rt. make it a aux. */
diff --git a/litmus/edf_common.c b/litmus/edf_common.c
index 7e0d3a5d0c4d..f4881452373d 100644
--- a/litmus/edf_common.c
+++ b/litmus/edf_common.c
@@ -237,6 +237,7 @@ int edf_higher_prio(struct task_struct* first, struct task_struct* second)
237 second_task->rt_param.is_proxy_thread) { 237 second_task->rt_param.is_proxy_thread) {
238 return 1; 238 return 1;
239 } 239 }
240 else if (first_task->rt_param.is_proxy_thread == second_task->rt_param.is_proxy_thread) {
240#endif 241#endif
241 242
242#ifdef CONFIG_REALTIME_AUX_TASKS 243#ifdef CONFIG_REALTIME_AUX_TASKS
@@ -244,6 +245,7 @@ int edf_higher_prio(struct task_struct* first, struct task_struct* second)
244 if (tsk_rt(first)->is_aux_task < tsk_rt(second)->is_aux_task) { 245 if (tsk_rt(first)->is_aux_task < tsk_rt(second)->is_aux_task) {
245 return 1; 246 return 1;
246 } 247 }
248 else if (tsk_rt(first)->is_aux_task == tsk_rt(second)->is_aux_task) {
247#endif 249#endif
248 250
249 /* Something could be wrong if you get this far. */ 251 /* Something could be wrong if you get this far. */
@@ -281,6 +283,14 @@ int edf_higher_prio(struct task_struct* first, struct task_struct* second)
281 return 1; 283 return 1;
282 } 284 }
283 } 285 }
286
287#ifdef CONFIG_REALTIME_AUX_TASKS
288 }
289#endif
290#ifdef CONFIG_LITMUS_SOFTIRQD
291 }
292#endif
293
284 } 294 }
285 } 295 }
286 } 296 }
diff --git a/litmus/ikglp_lock.c b/litmus/ikglp_lock.c
index 83b708ab85cb..bd7bfc0f48ac 100644
--- a/litmus/ikglp_lock.c
+++ b/litmus/ikglp_lock.c
@@ -963,7 +963,7 @@ int ikglp_lock(struct litmus_lock* l)
963 963
964 TS_LOCK_SUSPEND; 964 TS_LOCK_SUSPEND;
965 965
966 schedule(); 966 suspend_for_lock();
967 967
968 TS_LOCK_RESUME; 968 TS_LOCK_RESUME;
969 969
diff --git a/litmus/kfmlp_lock.c b/litmus/kfmlp_lock.c
index bff857ed8d4e..ab472330095d 100644
--- a/litmus/kfmlp_lock.c
+++ b/litmus/kfmlp_lock.c
@@ -267,7 +267,7 @@ int kfmlp_lock(struct litmus_lock* l)
267 * when we wake up; we are guaranteed to have the lock since 267 * when we wake up; we are guaranteed to have the lock since
268 * there is only one wake up per release (or steal). 268 * there is only one wake up per release (or steal).
269 */ 269 */
270 schedule(); 270 suspend_for_lock();
271 271
272 272
273 if(my_queue->owner == t) { 273 if(my_queue->owner == t) {
diff --git a/litmus/locking.c b/litmus/locking.c
index 12a23eb715cc..16c936ba8139 100644
--- a/litmus/locking.c
+++ b/litmus/locking.c
@@ -540,6 +540,35 @@ out:
540 return passed; 540 return passed;
541} 541}
542 542
543
544void suspend_for_lock(void)
545{
546#ifdef CONFIG_REALTIME_AUX_TASKS
547 unsigned int restore = 0;
548 struct task_struct *t = current;
549 unsigned int hide;
550
551 if (tsk_rt(t)->has_aux_tasks) {
552 /* hide from aux tasks so they can't inherit our priority when we block
553 * for a litmus lock. inheritance is already going to a litmus lock
554 * holder. */
555 hide = tsk_rt(t)->hide_from_aux_tasks;
556 restore = 1;
557 tsk_rt(t)->hide_from_aux_tasks = 1;
558 }
559#endif
560
561 schedule();
562
563#ifdef CONFIG_REALTIME_AUX_TASKS
564 if (restore) {
565 /* restore our state */
566 tsk_rt(t)->hide_from_aux_tasks = hide;
567 }
568#endif
569}
570
571
543#else // CONFIG_LITMUS_LOCKING 572#else // CONFIG_LITMUS_LOCKING
544 573
545struct fdso_ops generic_lock_ops = {}; 574struct fdso_ops generic_lock_ops = {};
diff --git a/litmus/rsm_lock.c b/litmus/rsm_lock.c
index 75ed87c5ed48..3dfd8ae9d221 100644
--- a/litmus/rsm_lock.c
+++ b/litmus/rsm_lock.c
@@ -289,7 +289,7 @@ int rsm_mutex_lock(struct litmus_lock* l)
289 * there is only one wake up per release. 289 * there is only one wake up per release.
290 */ 290 */
291 291
292 schedule(); 292 suspend_for_lock();
293 293
294 TS_LOCK_RESUME; 294 TS_LOCK_RESUME;
295 295
diff --git a/litmus/sched_cedf.c b/litmus/sched_cedf.c
index f5c9807090a1..6746d4d6033e 100644
--- a/litmus/sched_cedf.c
+++ b/litmus/sched_cedf.c
@@ -1032,7 +1032,7 @@ static void cedf_task_wake_up(struct task_struct *task)
1032#endif 1032#endif
1033 1033
1034#ifdef CONFIG_REALTIME_AUX_TASKS 1034#ifdef CONFIG_REALTIME_AUX_TASKS
1035 if (tsk_rt(task)->has_aux_tasks) { 1035 if (tsk_rt(task)->has_aux_tasks && !tsk_rt(task)->hide_from_aux_tasks) {
1036 TRACE_CUR("%s/%d is ready so aux tasks may not inherit.\n", task->comm, task->pid); 1036 TRACE_CUR("%s/%d is ready so aux tasks may not inherit.\n", task->comm, task->pid);
1037 disable_aux_task_owner(task); 1037 disable_aux_task_owner(task);
1038 } 1038 }
@@ -1057,7 +1057,7 @@ static void cedf_task_block(struct task_struct *t)
1057 unlink(t); 1057 unlink(t);
1058 1058
1059#ifdef CONFIG_REALTIME_AUX_TASKS 1059#ifdef CONFIG_REALTIME_AUX_TASKS
1060 if (tsk_rt(t)->has_aux_tasks) { 1060 if (tsk_rt(t)->has_aux_tasks && !tsk_rt(t)->hide_from_aux_tasks) {
1061 1061
1062 TRACE_CUR("%s/%d is blocked so aux tasks may inherit.\n", t->comm, t->pid); 1062 TRACE_CUR("%s/%d is blocked so aux tasks may inherit.\n", t->comm, t->pid);
1063 enable_aux_task_owner(t); 1063 enable_aux_task_owner(t);
@@ -1079,19 +1079,16 @@ static void cedf_task_exit(struct task_struct * t)
1079 cedf_change_prio_pai_tasklet(t, NULL); 1079 cedf_change_prio_pai_tasklet(t, NULL);
1080#endif 1080#endif
1081 1081
1082#ifdef CONFIG_REALTIME_AUX_TASKS
1083 if (tsk_rt(t)->is_aux_task) {
1084 exit_aux_task(t); /* cannot be called with gsnedf_lock held */
1085 }
1086#endif
1087
1088 /* unlink if necessary */ 1082 /* unlink if necessary */
1089 raw_spin_lock_irqsave(&cluster->cluster_lock, flags); 1083 raw_spin_lock_irqsave(&cluster->cluster_lock, flags);
1090 1084
1091#ifdef CONFIG_REALTIME_AUX_TASKS 1085#ifdef CONFIG_REALTIME_AUX_TASKS
1092 /* make sure we clean up on our way out */ 1086 /* make sure we clean up on our way out */
1093 if(tsk_rt(t)->has_aux_tasks) { 1087 if (unlikely(tsk_rt(t)->is_aux_task)) {
1094 disable_aux_task_owner(t); /* must be called witl gsnedf_lock held */ 1088 exit_aux_task(t);
1089 }
1090 else if(tsk_rt(t)->has_aux_tasks) {
1091 disable_aux_task_owner(t);
1095 } 1092 }
1096#endif 1093#endif
1097 1094
diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c
index ed9b4697a5a2..04b189e54b03 100644
--- a/litmus/sched_gsn_edf.c
+++ b/litmus/sched_gsn_edf.c
@@ -1050,7 +1050,7 @@ static void gsnedf_task_wake_up(struct task_struct *task)
1050#endif 1050#endif
1051 1051
1052#ifdef CONFIG_REALTIME_AUX_TASKS 1052#ifdef CONFIG_REALTIME_AUX_TASKS
1053 if (tsk_rt(task)->has_aux_tasks) { 1053 if (tsk_rt(task)->has_aux_tasks && !tsk_rt(task)->hide_from_aux_tasks) {
1054 TRACE_CUR("%s/%d is ready so aux tasks may not inherit.\n", task->comm, task->pid); 1054 TRACE_CUR("%s/%d is ready so aux tasks may not inherit.\n", task->comm, task->pid);
1055 disable_aux_task_owner(task); 1055 disable_aux_task_owner(task);
1056 } 1056 }
@@ -1072,7 +1072,7 @@ static void gsnedf_task_block(struct task_struct *t)
1072 unlink(t); 1072 unlink(t);
1073 1073
1074#ifdef CONFIG_REALTIME_AUX_TASKS 1074#ifdef CONFIG_REALTIME_AUX_TASKS
1075 if (tsk_rt(t)->has_aux_tasks) { 1075 if (tsk_rt(t)->has_aux_tasks && !tsk_rt(t)->hide_from_aux_tasks) {
1076 1076
1077 TRACE_CUR("%s/%d is blocked so aux tasks may inherit.\n", t->comm, t->pid); 1077 TRACE_CUR("%s/%d is blocked so aux tasks may inherit.\n", t->comm, t->pid);
1078 enable_aux_task_owner(t); 1078 enable_aux_task_owner(t);
@@ -1093,19 +1093,16 @@ static void gsnedf_task_exit(struct task_struct * t)
1093 gsnedf_change_prio_pai_tasklet(t, NULL); 1093 gsnedf_change_prio_pai_tasklet(t, NULL);
1094#endif 1094#endif
1095 1095
1096#ifdef CONFIG_REALTIME_AUX_TASKS
1097 if (tsk_rt(t)->is_aux_task) {
1098 exit_aux_task(t); /* cannot be called with gsnedf_lock held */
1099 }
1100#endif
1101
1102 /* unlink if necessary */ 1096 /* unlink if necessary */
1103 raw_spin_lock_irqsave(&gsnedf_lock, flags); 1097 raw_spin_lock_irqsave(&gsnedf_lock, flags);
1104 1098
1105#ifdef CONFIG_REALTIME_AUX_TASKS 1099#ifdef CONFIG_REALTIME_AUX_TASKS
1106 /* make sure we clean up on our way out */ 1100 /* make sure we clean up on our way out */
1107 if(tsk_rt(t)->has_aux_tasks) { 1101 if (unlikely(tsk_rt(t)->is_aux_task)) {
1108 disable_aux_task_owner(t); /* must be called witl gsnedf_lock held */ 1102 exit_aux_task(t);
1103 }
1104 else if(tsk_rt(t)->has_aux_tasks) {
1105 disable_aux_task_owner(t);
1109 } 1106 }
1110#endif 1107#endif
1111 1108
@@ -1664,7 +1661,7 @@ int gsnedf_fmlp_lock(struct litmus_lock* l)
1664 * there is only one wake up per release. 1661 * there is only one wake up per release.
1665 */ 1662 */
1666 1663
1667 schedule(); 1664 suspend_for_lock();
1668 1665
1669 TS_LOCK_RESUME; 1666 TS_LOCK_RESUME;
1670 1667