diff options
| author | Glenn Elliott <gelliott@cs.unc.edu> | 2013-02-11 22:48:51 -0500 |
|---|---|---|
| committer | Glenn Elliott <gelliott@cs.unc.edu> | 2013-02-11 22:48:51 -0500 |
| commit | c063e088be8e1bcbb6a76b8cd087f8dc8b6923b2 (patch) | |
| tree | 4450780888858cfbb0d042605035db689c3eedbe | |
| parent | 40d12009bd0c3515c5bfee5425bd80f58cdd7b73 (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.h | 16 | ||||
| -rw-r--r-- | include/litmus/prioq_lock.h | 1 | ||||
| -rw-r--r-- | litmus/ikglp_lock.c | 4 | ||||
| -rw-r--r-- | litmus/locking.c | 92 | ||||
| -rw-r--r-- | litmus/prioq_lock.c | 151 | ||||
| -rw-r--r-- | litmus/sched_cedf.c | 40 |
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 | |||
| 34 | int prioq_mutex_is_owner(struct litmus_lock *l, struct task_struct *t); | 34 | int prioq_mutex_is_owner(struct litmus_lock *l, struct task_struct *t); |
| 35 | struct task_struct* prioq_mutex_get_owner(struct litmus_lock *l); | 35 | struct task_struct* prioq_mutex_get_owner(struct litmus_lock *l); |
| 36 | int prioq_mutex_dgl_lock(struct litmus_lock *l, dgl_wait_state_t* dgl_wait, wait_queue_t* wq_node); | 36 | int prioq_mutex_dgl_lock(struct litmus_lock *l, dgl_wait_state_t* dgl_wait, wait_queue_t* wq_node); |
| 37 | int prioq_mutex_dgl_unlock(struct litmus_lock *l); | ||
| 37 | void prioq_mutex_enable_priority(struct litmus_lock *l, dgl_wait_state_t* dgl_wait); | 38 | void prioq_mutex_enable_priority(struct litmus_lock *l, dgl_wait_state_t* dgl_wait); |
| 38 | void prioq_mutex_dgl_quick_lock(struct litmus_lock *l, struct litmus_lock *cur_lock, | 39 | void 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 | ||
| 368 | static 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! */ |
| 382 | int __attempt_atomic_dgl_acquire(struct litmus_lock *cur_lock, dgl_wait_state_t *dgl_wait) | 370 | int __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; |
