aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2013-02-11 22:48:51 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2013-02-11 22:48:51 -0500
commitc063e088be8e1bcbb6a76b8cd087f8dc8b6923b2 (patch)
tree4450780888858cfbb0d042605035db689c3eedbe
parent40d12009bd0c3515c5bfee5425bd80f58cdd7b73 (diff)
BUG FIX: Support DGLs with PRIOQ_MUTEXwip-prioq-dgl
First 'working' implementation of DGLs with PRIOQ_MUTEX. (All other code prior was work-in-progress.) General approach: Because of priority queue order, PRIOQ_MUTEX DGLs must be *acquired* atomically. This means that a task cannot acquire an available PRIOQ_MUTEX if another PRIOQ_MUTEX is not available at the same time. Requests are buffered in PRIOQ_MUTEX and the resource 'idles'-- that is, the mutex owner is NULL, but there are waiting tasks for the resource. Several notes/side-effects: 1) A high-priority task that idles a resource can effectively block lower-priority tasks from acquiring that resource. This is because the low-prio task cannot skip ahead of the high-prio task in the priority queue. 2) Priority inheritance from nesting can cause the low-prioity task in #1 to jump over the high-priority task and acquire the resource. This means that any task blocked on a DGL that receives an increase in priority while blocked on the DGL must trigger a re-eval of the locks it can take. If the resources can be acquired, then the task needs to be woken up! <<<<< Lock acquisition via inheritance is entirely new and weird! >>>>> 3) A similar case for #2 exists for priorty decreases (example: this can happen when a task loses a donor) while it is blocked on a PRIOQ_MUTEX. The high-priority task described in #1 can change and become a lower- priority task. Every idle lock (mutex owner is NULL) on which the task losing priority must be revaluated--- it is possible that the (possible) new head on the priority queue can take the lock. Note: This affects BOTH singular and DGL resource requests, while the case described in #2 only affects DGL requests (because a singular request at the head of the priority queue will never idle a resource).
-rw-r--r--include/litmus/locking.h16
-rw-r--r--include/litmus/prioq_lock.h1
-rw-r--r--litmus/ikglp_lock.c4
-rw-r--r--litmus/locking.c92
-rw-r--r--litmus/prioq_lock.c151
-rw-r--r--litmus/sched_cedf.c40
6 files changed, 152 insertions, 152 deletions
diff --git a/include/litmus/locking.h b/include/litmus/locking.h
index b1024e397f67..fc437811d2b6 100644
--- a/include/litmus/locking.h
+++ b/include/litmus/locking.h
@@ -11,7 +11,6 @@ struct nested_info
11 struct litmus_lock *lock; 11 struct litmus_lock *lock;
12 struct task_struct *hp_waiter_eff_prio; 12 struct task_struct *hp_waiter_eff_prio;
13 struct task_struct **hp_waiter_ptr; 13 struct task_struct **hp_waiter_ptr;
14// struct task_struct **owner_ptr;
15 struct binheap_node hp_binheap_node; 14 struct binheap_node hp_binheap_node;
16}; 15};
17 16
@@ -134,24 +133,31 @@ struct litmus_lock_ops {
134 /* The lock is no longer being referenced (mandatory method). */ 133 /* The lock is no longer being referenced (mandatory method). */
135 lock_free_t deallocate; 134 lock_free_t deallocate;
136 135
137 136
138#ifdef CONFIG_LITMUS_NESTED_LOCKING 137#ifdef CONFIG_LITMUS_NESTED_LOCKING
139 void (*propagate_increase_inheritance)(struct litmus_lock* l, struct task_struct* t, raw_spinlock_t* to_unlock, unsigned long irqflags); 138 void (*propagate_increase_inheritance)(struct litmus_lock* l, struct task_struct* t, raw_spinlock_t* to_unlock, unsigned long irqflags);
140 void (*propagate_decrease_inheritance)(struct litmus_lock* l, struct task_struct* t, raw_spinlock_t* to_unlock, unsigned long irqflags); 139 void (*propagate_decrease_inheritance)(struct litmus_lock* l, struct task_struct* t, raw_spinlock_t* to_unlock, unsigned long irqflags);
141#endif 140#endif
142
143
144#ifdef CONFIG_LITMUS_DGL_SUPPORT 141#ifdef CONFIG_LITMUS_DGL_SUPPORT
145 raw_spinlock_t* (*get_dgl_spin_lock)(struct litmus_lock *l); 142 raw_spinlock_t* (*get_dgl_spin_lock)(struct litmus_lock *l);
146 int (*dgl_lock)(struct litmus_lock *l, dgl_wait_state_t* dgl_wait, wait_queue_t* wq_node); 143 int (*dgl_lock)(struct litmus_lock *l, dgl_wait_state_t* dgl_wait, wait_queue_t* wq_node);
147 int (*is_owner)(struct litmus_lock *l, struct task_struct *t); 144 int (*is_owner)(struct litmus_lock *l, struct task_struct *t);
148 struct task_struct* (*get_owner)(struct litmus_lock *l); 145 struct task_struct* (*get_owner)(struct litmus_lock *l);
149 void (*enable_priority)(struct litmus_lock *l, dgl_wait_state_t* dgl_wait); 146 void (*enable_priority)(struct litmus_lock *l, dgl_wait_state_t* dgl_wait);
150 147
151 int (*dgl_can_quick_lock)(struct litmus_lock *l, struct task_struct *t); 148 int (*dgl_can_quick_lock)(struct litmus_lock *l, struct task_struct *t);
152 void (*dgl_quick_lock)(struct litmus_lock *l, struct litmus_lock *cur_lock, 149 void (*dgl_quick_lock)(struct litmus_lock *l, struct litmus_lock *cur_lock,
153 struct task_struct* t, wait_queue_t *q); 150 struct task_struct* t, wait_queue_t *q);
154#endif 151#endif
152
153 /* all flags at the end */
154#ifdef CONFIG_LITMUS_NESTED_LOCKING
155 int supports_nesting:1;
156#endif
157#ifdef CONFIG_LITMUS_DGL_SUPPORT
158 int supports_dgl:1;
159 int requires_atomic_dgl:1;
160#endif
155}; 161};
156 162
157 163
diff --git a/include/litmus/prioq_lock.h b/include/litmus/prioq_lock.h
index 5c135ef0bdc6..1b0a591ef1a6 100644
--- a/include/litmus/prioq_lock.h
+++ b/include/litmus/prioq_lock.h
@@ -34,6 +34,7 @@ static inline struct prioq_mutex* prioq_mutex_from_lock(struct litmus_lock* lock
34int prioq_mutex_is_owner(struct litmus_lock *l, struct task_struct *t); 34int prioq_mutex_is_owner(struct litmus_lock *l, struct task_struct *t);
35struct task_struct* prioq_mutex_get_owner(struct litmus_lock *l); 35struct task_struct* prioq_mutex_get_owner(struct litmus_lock *l);
36int prioq_mutex_dgl_lock(struct litmus_lock *l, dgl_wait_state_t* dgl_wait, wait_queue_t* wq_node); 36int prioq_mutex_dgl_lock(struct litmus_lock *l, dgl_wait_state_t* dgl_wait, wait_queue_t* wq_node);
37int prioq_mutex_dgl_unlock(struct litmus_lock *l);
37void prioq_mutex_enable_priority(struct litmus_lock *l, dgl_wait_state_t* dgl_wait); 38void prioq_mutex_enable_priority(struct litmus_lock *l, dgl_wait_state_t* dgl_wait);
38void prioq_mutex_dgl_quick_lock(struct litmus_lock *l, struct litmus_lock *cur_lock, 39void prioq_mutex_dgl_quick_lock(struct litmus_lock *l, struct litmus_lock *cur_lock,
39 struct task_struct* t, wait_queue_t *q); 40 struct task_struct* t, wait_queue_t *q);
diff --git a/litmus/ikglp_lock.c b/litmus/ikglp_lock.c
index 3d79e41b42df..3fd760799a75 100644
--- a/litmus/ikglp_lock.c
+++ b/litmus/ikglp_lock.c
@@ -1401,7 +1401,9 @@ int ikglp_unlock(struct litmus_lock* l)
1401 struct nested_info, hp_binheap_node); 1401 struct nested_info, hp_binheap_node);
1402 ++count; 1402 ++count;
1403 } 1403 }
1404 litmus->decrease_prio(t, NULL); 1404 if (count) {
1405 litmus->decrease_prio(t, NULL);
1406 }
1405 WARN_ON(count > 2); // should not be greater than 2. only local fq inh and donation can be possible. 1407 WARN_ON(count > 2); // should not be greater than 2. only local fq inh and donation can be possible.
1406 } 1408 }
1407 raw_spin_unlock(&tsk_rt(t)->hp_blocked_tasks_lock); 1409 raw_spin_unlock(&tsk_rt(t)->hp_blocked_tasks_lock);
diff --git a/litmus/locking.c b/litmus/locking.c
index 4b8382cd77d1..eddc67a4d36a 100644
--- a/litmus/locking.c
+++ b/litmus/locking.c
@@ -365,18 +365,6 @@ static void snprintf_dgl(char* buf, size_t bsz, struct litmus_lock* dgl_locks[],
365#endif 365#endif
366 366
367 367
368static int failed_owner(struct litmus_lock *cur_lock, struct task_struct *t)
369{
370 struct task_struct *cur_owner = cur_lock->ops->get_owner(cur_lock);
371 printk(KERN_EMERG "lock %d expected owner %s/%d but got %s/%d.\n",
372 cur_lock->ident,
373 (t) ? t->comm : "null",
374 (t) ? t->pid : 0,
375 (cur_owner) ? cur_owner->comm : "null",
376 (cur_owner) ? cur_owner->pid : 0);
377 BUG();
378}
379
380/* only valid when locks are prioq locks!!! 368/* only valid when locks are prioq locks!!!
381 * THE BIG DGL LOCK MUST BE HELD! */ 369 * THE BIG DGL LOCK MUST BE HELD! */
382int __attempt_atomic_dgl_acquire(struct litmus_lock *cur_lock, dgl_wait_state_t *dgl_wait) 370int __attempt_atomic_dgl_acquire(struct litmus_lock *cur_lock, dgl_wait_state_t *dgl_wait)
@@ -395,12 +383,8 @@ int __attempt_atomic_dgl_acquire(struct litmus_lock *cur_lock, dgl_wait_state_t
395 /* take the locks */ 383 /* take the locks */
396 for(i = 0; i < dgl_wait->size; ++i) { 384 for(i = 0; i < dgl_wait->size; ++i) {
397 struct litmus_lock *l = dgl_wait->locks[i]; 385 struct litmus_lock *l = dgl_wait->locks[i];
398
399 l->ops->dgl_quick_lock(l, cur_lock, dgl_wait->task, &dgl_wait->wq_nodes[i]); 386 l->ops->dgl_quick_lock(l, cur_lock, dgl_wait->task, &dgl_wait->wq_nodes[i]);
400 387 BUG_ON(!(l->ops->is_owner(l, dgl_wait->task)));
401 if(!(l->ops->is_owner(l, dgl_wait->task)))
402 failed_owner(l, dgl_wait->task);
403 //BUG_ON(!(l->ops->is_owner(l, dgl_wait->task)));
404 } 388 }
405 389
406 return 0; /* success */ 390 return 0; /* success */
@@ -510,6 +494,7 @@ static long do_litmus_dgl_atomic_lock(dgl_wait_state_t *dgl_wait)
510 unsigned long irqflags; //, dummyflags; 494 unsigned long irqflags; //, dummyflags;
511 raw_spinlock_t *dgl_lock; 495 raw_spinlock_t *dgl_lock;
512 struct litmus_lock *l; 496 struct litmus_lock *l;
497 struct task_struct *t = current;
513 498
514#ifdef CONFIG_SCHED_DEBUG_TRACE 499#ifdef CONFIG_SCHED_DEBUG_TRACE
515 char dglstr[CONFIG_LITMUS_MAX_DGL_SIZE*5]; 500 char dglstr[CONFIG_LITMUS_MAX_DGL_SIZE*5];
@@ -519,7 +504,7 @@ static long do_litmus_dgl_atomic_lock(dgl_wait_state_t *dgl_wait)
519 504
520 dgl_lock = litmus->get_dgl_spinlock(dgl_wait->task); 505 dgl_lock = litmus->get_dgl_spinlock(dgl_wait->task);
521 506
522 BUG_ON(dgl_wait->task != current); 507 BUG_ON(dgl_wait->task != t);
523 508
524 raw_spin_lock_irqsave(dgl_lock, irqflags); 509 raw_spin_lock_irqsave(dgl_lock, irqflags);
525 510
@@ -528,7 +513,8 @@ static long do_litmus_dgl_atomic_lock(dgl_wait_state_t *dgl_wait)
528 513
529 for(i = 0; i < dgl_wait->size; ++i) { 514 for(i = 0; i < dgl_wait->size; ++i) {
530 struct litmus_lock *l = dgl_wait->locks[i]; 515 struct litmus_lock *l = dgl_wait->locks[i];
531 l->ops->dgl_lock(l, dgl_wait, &dgl_wait->wq_nodes[i]); // this should be a forced enqueue if atomic DGLs are needed. 516 // this should be a forced enqueue if atomic DGLs are needed.
517 l->ops->dgl_lock(l, dgl_wait, &dgl_wait->wq_nodes[i]);
532 } 518 }
533 519
534 if(__attempt_atomic_dgl_acquire(NULL, dgl_wait)) { 520 if(__attempt_atomic_dgl_acquire(NULL, dgl_wait)) {
@@ -536,27 +522,26 @@ static long do_litmus_dgl_atomic_lock(dgl_wait_state_t *dgl_wait)
536 * Pick a lock to push on and suspend. */ 522 * Pick a lock to push on and suspend. */
537 TRACE_CUR("Could not atomically acquire all locks.\n"); 523 TRACE_CUR("Could not atomically acquire all locks.\n");
538 524
525 /* we set the uninterruptible state here since
526 * __attempt_atomic_dgl_acquire() may actually succeed. */
527 set_task_state(t, TASK_UNINTERRUPTIBLE);
539 528
540#if defined(CONFIG_LITMUS_AFFINITY_LOCKING) && defined(CONFIG_LITMUS_NVIDIA) 529#if defined(CONFIG_LITMUS_AFFINITY_LOCKING) && defined(CONFIG_LITMUS_NVIDIA)
541 // KLUDGE: don't count this suspension as time in the critical gpu 530 // KLUDGE: don't count this suspension as time in the critical gpu
542 // critical section 531 // critical section
543 if(tsk_rt(dgl_wait->task)->held_gpus) { 532 if(tsk_rt(t)->held_gpus) {
544 tsk_rt(dgl_wait->task)->suspend_gpu_tracker_on_block = 1; 533 tsk_rt(t)->suspend_gpu_tracker_on_block = 1;