aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2013-04-09 15:02:28 -0400
committerGlenn Elliott <gelliott@cs.unc.edu>2013-04-09 16:04:07 -0400
commit202a0410c911d9f9522d76db6405b0f6001aed5b (patch)
tree9f1372be13bfe6264e0bd8214e6a4153f59813fb
parent63a043514200704c9f2f288075bf4e9b268f57bd (diff)
IKGLP virtual unlock and MAJOR BUG FIX
Fixed a major bug where a scheduled task with and exhausted budget does not recheck its priority inheritance upon deadline postponement. Postponment may enable priority inheritance relations, as the priority of the lock holder decreases.
-rw-r--r--include/litmus/ikglp_lock.h9
-rw-r--r--litmus/budget.c9
-rw-r--r--litmus/ikglp_lock.c125
-rw-r--r--litmus/sched_cedf.c267
4 files changed, 287 insertions, 123 deletions
diff --git a/include/litmus/ikglp_lock.h b/include/litmus/ikglp_lock.h
index d81b755b9039..954597fc927d 100644
--- a/include/litmus/ikglp_lock.h
+++ b/include/litmus/ikglp_lock.h
@@ -73,6 +73,15 @@ struct fifo_queue
73 unsigned int count; /* number of waiters + holder */ 73 unsigned int count; /* number of waiters + holder */
74 74
75 struct nested_info nest; 75 struct nested_info nest;
76
77 /* Asserted if owner has 'virtually' unlocked the FIFO's replica.
78 * See rule B2 in Brandenburg's "Virtually Exclusive Resources"
79 * tech report MPI_SWS-2012-005.
80 *
81 * In this implementation, allows the FIFO queue to temporarily
82 * grow by one past it's maximum size.
83 */
84 unsigned int is_vunlocked:1;
76}; 85};
77 86
78struct ikglp_semaphore 87struct ikglp_semaphore
diff --git a/litmus/budget.c b/litmus/budget.c
index aa254349a85e..f7d690c77226 100644
--- a/litmus/budget.c
+++ b/litmus/budget.c
@@ -183,7 +183,8 @@ void sobliv_on_blocked(struct task_struct* t)
183 * trigger another exhaustion signal since signals are controled by 183 * trigger another exhaustion signal since signals are controled by
184 * BTF_SIG_BUDGET_SENT. */ 184 * BTF_SIG_BUDGET_SENT. */
185 int exhausted = bt_flag_test_and_clear(t, BTF_BUDGET_EXHAUSTED); 185 int exhausted = bt_flag_test_and_clear(t, BTF_BUDGET_EXHAUSTED);
186 BUG_ON(!exhausted); 186 //BUG_ON(!exhausted);
187 WARN_ON(!exhausted);
187 188
188 TRACE_TASK(t, "budget timer not armed. " 189 TRACE_TASK(t, "budget timer not armed. "
189 "Raced with exhaustion-resched? Re-arming.\n"); 190 "Raced with exhaustion-resched? Re-arming.\n");
@@ -317,12 +318,6 @@ void sobliv_revaluate_task(struct task_struct* t)
317 "on Litmus lock without " 318 "on Litmus lock without "
318 "CONFIG_LITMUS_NESTED_LOCKING enabled.\n"); 319 "CONFIG_LITMUS_NESTED_LOCKING enabled.\n");
319#endif 320#endif
320
321 /* Move a waiter onto a FIFO queue to simulate an unlock call. */
322 if (tsk_rt(t)->outermost_lock &&
323 tsk_rt(t)->outermost_lock->ops->is_omlp_family) {
324 tsk_rt(t)->outermost_lock->ops->omlp_virtual_unlock(tsk_rt(t)->outermost_lock, t);
325 }
326} 321}
327 322
328 323
diff --git a/litmus/ikglp_lock.c b/litmus/ikglp_lock.c
index 3058aa8fb2fe..d9c263eee34a 100644
--- a/litmus/ikglp_lock.c
+++ b/litmus/ikglp_lock.c
@@ -77,6 +77,10 @@ int ikglp_min_heap_donee_order(struct binheap_node *a,
77} 77}
78 78
79 79
80static inline unsigned int nominal_fq_len(struct fifo_queue *fq)
81{
82 return (fq->count - fq->is_vunlocked);
83}
80 84
81static inline int ikglp_get_idx(struct ikglp_semaphore *sem, 85static inline int ikglp_get_idx(struct ikglp_semaphore *sem,
82 struct fifo_queue *queue) 86 struct fifo_queue *queue)
@@ -122,8 +126,9 @@ static struct fifo_queue* ikglp_find_shortest(struct ikglp_semaphore *sem,
122 126
123 do { 127 do {
124 step = (step+1 != &sem->fifo_queues[sem->nr_replicas]) ? 128 step = (step+1 != &sem->fifo_queues[sem->nr_replicas]) ?
125 step+1 : &sem->fifo_queues[0]; 129 step+1 : &sem->fifo_queues[0];
126 130
131 /* consider actual lengths, not nominal lengths */
127 if(step->count < shortest->count) { 132 if(step->count < shortest->count) {
128 shortest = step; 133 shortest = step;
129 if(step->count == 0) 134 if(step->count == 0)
@@ -195,10 +200,11 @@ static void __ikglp_dump_donors(struct binheap_node *n, int depth)
195 200
196static void __ikglp_dump_fifoq(int i, struct fifo_queue* fq) 201static void __ikglp_dump_fifoq(int i, struct fifo_queue* fq)
197{ 202{
198 TRACE(" FIFO %d: Owner = %s/%d, HP Waiter = %s/%d, # Waiters = %u\n", 203 TRACE(" FIFO %d: Owner = %s/%d (Virtually Unlocked = %u), HP Waiter = %s/%d, Length = %u\n",
199 i, 204 i,
200 (fq->owner) ? fq->owner->comm : "null", 205 (fq->owner) ? fq->owner->comm : "null",
201 (fq->owner) ? fq->owner->pid : 0, 206 (fq->owner) ? fq->owner->pid : 0,
207 fq->is_vunlocked,
202 (fq->hp_waiter) ? fq->hp_waiter->comm : "null", 208 (fq->hp_waiter) ? fq->hp_waiter->comm : "null",
203 (fq->hp_waiter) ? fq->hp_waiter->pid : 0, 209 (fq->hp_waiter) ? fq->hp_waiter->pid : 0,
204 fq->count); 210 fq->count);
@@ -1395,11 +1401,16 @@ void ikglp_grant_replica_to_next(struct ikglp_semaphore *sem, struct fifo_queue
1395} 1401}
1396 1402
1397 1403
1404#define ALLOW_STEALING 1
1405#define ALWAYS_TERMINATE_DONATION 1
1406
1398void ikglp_move_next_to_fq(struct ikglp_semaphore *sem, 1407void ikglp_move_next_to_fq(struct ikglp_semaphore *sem,
1399 struct fifo_queue *fq, 1408 struct fifo_queue *fq,
1400 struct task_struct *t, 1409 struct task_struct *t,
1401 ikglp_donee_heap_node_t *donee_node, 1410 ikglp_donee_heap_node_t *donee_node,
1402 int allow_stealing) 1411 unsigned long *flags,
1412 int allow_stealing,
1413 int always_terminate_donation)
1403{ 1414{
1404 struct task_struct *donee = NULL; 1415 struct task_struct *donee = NULL;
1405 struct task_struct *new_on_fq = NULL; 1416 struct task_struct *new_on_fq = NULL;
@@ -1408,7 +1419,6 @@ void ikglp_move_next_to_fq(struct ikglp_semaphore *sem,
1408 ikglp_wait_state_t *other_donor_info = NULL; 1419 ikglp_wait_state_t *other_donor_info = NULL;
1409 struct fifo_queue *to_steal = NULL; 1420 struct fifo_queue *to_steal = NULL;
1410 int need_steal_prio_reeval = 0; 1421 int need_steal_prio_reeval = 0;
1411 unsigned long flags = 0;
1412 1422
1413 if (donee_node->donor_info) { 1423 if (donee_node->donor_info) {
1414 ikglp_wait_state_t *donor_info = donee_node->donor_info; 1424 ikglp_wait_state_t *donor_info = donee_node->donor_info;
@@ -1421,7 +1431,7 @@ void ikglp_move_next_to_fq(struct ikglp_semaphore *sem,
1421#ifdef CONFIG_LITMUS_AFFINITY_LOCKING 1431#ifdef CONFIG_LITMUS_AFFINITY_LOCKING
1422 if(sem->aff_obs) { 1432 if(sem->aff_obs) {
1423 fq_of_new_on_fq = sem->aff_obs->ops->advise_enqueue(sem->aff_obs, new_on_fq); 1433 fq_of_new_on_fq = sem->aff_obs->ops->advise_enqueue(sem->aff_obs, new_on_fq);
1424 if((fq_of_new_on_fq->count >= sem->max_fifo_len) && !sem->aff_obs->relax_max_fifo_len) { 1434 if((nominal_fq_len(fq_of_new_on_fq) >= sem->max_fifo_len) && !sem->aff_obs->relax_max_fifo_len) {
1425 WARN_ON(1); 1435 WARN_ON(1);
1426 fq_of_new_on_fq = fq; 1436 fq_of_new_on_fq = fq;
1427 } 1437 }
@@ -1438,6 +1448,11 @@ void ikglp_move_next_to_fq(struct ikglp_semaphore *sem,
1438 ikglp_get_idx(sem, fq)); 1448 ikglp_get_idx(sem, fq));
1439 1449
1440 ikglp_move_donor_to_fq(sem, fq_of_new_on_fq, donor_info); 1450 ikglp_move_donor_to_fq(sem, fq_of_new_on_fq, donor_info);
1451
1452 /* treat donor as if it had donated to a task other than 't'.
1453 * this triggers the termination of the donation relationship. */
1454 if (always_terminate_donation)
1455 other_donor_info = donor_info;
1441 } 1456 }
1442 else if(!binheap_empty(&sem->donors)) { // No donor, so move any donor to FQ 1457 else if(!binheap_empty(&sem->donors)) { // No donor, so move any donor to FQ
1443 // Select a donor 1458 // Select a donor
@@ -1459,7 +1474,7 @@ void ikglp_move_next_to_fq(struct ikglp_semaphore *sem,
1459#ifdef CONFIG_LITMUS_AFFINITY_LOCKING 1474#ifdef CONFIG_LITMUS_AFFINITY_LOCKING
1460 if(sem->aff_obs) { 1475 if(sem->aff_obs) {
1461 fq_of_new_on_fq = sem->aff_obs->ops->advise_enqueue(sem->aff_obs, new_on_fq); 1476 fq_of_new_on_fq = sem->aff_obs->ops->advise_enqueue(sem->aff_obs, new_on_fq);
1462 if((fq_of_new_on_fq->count >= sem->max_fifo_len) && !sem->aff_obs->relax_max_fifo_len) { 1477 if((nominal_fq_len(fq_of_new_on_fq) >= sem->max_fifo_len) && !sem->aff_obs->relax_max_fifo_len) {
1463 WARN_ON(1); 1478 WARN_ON(1);
1464 fq_of_new_on_fq = fq; 1479 fq_of_new_on_fq = fq;
1465 } 1480 }
@@ -1488,7 +1503,7 @@ void ikglp_move_next_to_fq(struct ikglp_semaphore *sem,
1488#ifdef CONFIG_LITMUS_AFFINITY_LOCKING 1503#ifdef CONFIG_LITMUS_AFFINITY_LOCKING
1489 if(sem->aff_obs) { 1504 if(sem->aff_obs) {
1490 fq_of_new_on_fq = sem->aff_obs->ops->advise_enqueue(sem->aff_obs, new_on_fq); 1505 fq_of_new_on_fq = sem->aff_obs->ops->advise_enqueue(sem->aff_obs, new_on_fq);
1491 if((fq_of_new_on_fq->count >= sem->max_fifo_len) && !sem->aff_obs->relax_max_fifo_len) { 1506 if((nominal_fq_len(fq_of_new_on_fq) >= sem->max_fifo_len) && !sem->aff_obs->relax_max_fifo_len) {
1492 WARN_ON(1); 1507 WARN_ON(1);
1493 fq_of_new_on_fq = fq; 1508 fq_of_new_on_fq = fq;
1494 } 1509 }
@@ -1556,7 +1571,7 @@ void ikglp_move_next_to_fq(struct ikglp_semaphore *sem,
1556 struct fifo_queue *other_fq = other_donor_info->donee_info->fq; 1571 struct fifo_queue *other_fq = other_donor_info->donee_info->fq;
1557 1572
1558 BUG_ON(!donee); 1573 BUG_ON(!donee);
1559 BUG_ON(donee == t); 1574 BUG_ON(!always_terminate_donation && donee == t);
1560 1575
1561 TRACE_TASK(t, "Terminating donation relation of donor %s/%d to donee %s/%d!\n", 1576 TRACE_TASK(t, "Terminating donation relation of donor %s/%d to donee %s/%d!\n",
1562 other_donor_info->task->comm, other_donor_info->task->pid, 1577 other_donor_info->task->comm, other_donor_info->task->pid,
@@ -1568,8 +1583,8 @@ void ikglp_move_next_to_fq(struct ikglp_semaphore *sem,
1568 donee->comm, donee->pid, 1583 donee->comm, donee->pid,
1569 ikglp_get_idx(sem, other_fq)); 1584 ikglp_get_idx(sem, other_fq));
1570 1585
1571 ikglp_remove_donation_from_owner(&other_donor_info->prio_donation.hp_binheap_node, other_fq, sem, flags); 1586 ikglp_remove_donation_from_owner(&other_donor_info->prio_donation.hp_binheap_node, other_fq, sem, *flags);
1572 lock_fine_irqsave(&sem->lock, flags); // there should be no contention!!!! 1587 lock_fine_irqsave(&sem->lock, *flags); // there should be no contention!!!!
1573 } 1588 }
1574 else { 1589 else {
1575 TRACE_TASK(t, "Donee %s/%d is blocked in of fq %d.\n", 1590 TRACE_TASK(t, "Donee %s/%d is blocked in of fq %d.\n",
@@ -1588,8 +1603,8 @@ void ikglp_move_next_to_fq(struct ikglp_semaphore *sem,
1588 (other_fq->hp_waiter) ? other_fq->hp_waiter->comm : "null", 1603 (other_fq->hp_waiter) ? other_fq->hp_waiter->comm : "null",
1589 (other_fq->hp_waiter) ? other_fq->hp_waiter->pid : 0); 1604 (other_fq->hp_waiter) ? other_fq->hp_waiter->pid : 0);
1590 1605
1591 ikglp_refresh_owners_prio_decrease(other_fq, sem, flags, 0); // unlocks sem->lock. reacquire it. 1606 ikglp_refresh_owners_prio_decrease(other_fq, sem, *flags, 0); // unlocks sem->lock. reacquire it.
1592 lock_fine_irqsave(&sem->lock, flags); // there should be no contention!!!! 1607 lock_fine_irqsave(&sem->lock, *flags); // there should be no contention!!!!
1593 } 1608 }
1594 } 1609 }
1595 } 1610 }
@@ -1598,15 +1613,15 @@ void ikglp_move_next_to_fq(struct ikglp_semaphore *sem,
1598 ikglp_get_idx(sem, to_steal)); 1613 ikglp_get_idx(sem, to_steal));
1599 1614
1600 if(need_steal_prio_reeval) { 1615 if(need_steal_prio_reeval) {
1601 ikglp_refresh_owners_prio_decrease(to_steal, sem, flags, 0); // unlocks sem->lock. reacquire it. 1616 ikglp_refresh_owners_prio_decrease(to_steal, sem, *flags, 0); // unlocks sem->lock. reacquire it.
1602 lock_fine_irqsave(&sem->lock, flags); // there should be no contention!!!! 1617 lock_fine_irqsave(&sem->lock, *flags); // there should be no contention!!!!
1603 } 1618 }
1604 } 1619 }
1605 1620
1606 // check for new HP waiter. 1621 // check for new HP waiter.
1607 if(new_on_fq) { 1622 if(new_on_fq) {
1608 ikglp_refresh_owners_prio_increase(new_on_fq, fq_of_new_on_fq, sem, flags); // unlocks sem->lock. reacquire it. 1623 ikglp_refresh_owners_prio_increase(new_on_fq, fq_of_new_on_fq, sem, *flags); // unlocks sem->lock. reacquire it.
1609 lock_fine_irqsave(&sem->lock, flags); // there should be no contention!!!! 1624 lock_fine_irqsave(&sem->lock, *flags); // there should be no contention!!!!
1610 } 1625 }
1611 1626
1612 /* we moved a request to an empty FQ. wake it up */ 1627 /* we moved a request to an empty FQ. wake it up */
@@ -1656,7 +1671,11 @@ int ikglp_unlock(struct litmus_lock* l)
1656 if(fq->count < sem->shortest_fifo_queue->count) { 1671 if(fq->count < sem->shortest_fifo_queue->count) {
1657 sem->shortest_fifo_queue = fq; 1672 sem->shortest_fifo_queue = fq;
1658 } 1673 }
1659 --(sem->nr_in_fifos); 1674
1675 if (likely(!fq->is_vunlocked))
1676 --(sem->nr_in_fifos);
1677 else
1678 TRACE_TASK(t, "virtually unlocked. handing off replica only.\n");
1660 1679
1661#ifdef CONFIG_LITMUS_AFFINITY_LOCKING 1680#ifdef CONFIG_LITMUS_AFFINITY_LOCKING
1662 if(sem->aff_obs) { 1681 if(sem->aff_obs) {
@@ -1687,9 +1706,14 @@ int ikglp_unlock(struct litmus_lock* l)
1687 } 1706 }
1688 raw_spin_unlock(&tsk_rt(t)->hp_blocked_tasks_lock); 1707 raw_spin_unlock(&tsk_rt(t)->hp_blocked_tasks_lock);
1689 1708
1690 // Move the next request into the FQ and update heaps as needed. 1709 if (likely(!fq->is_vunlocked)) {
1691 // We defer re-evaluation of priorities to later in the function. 1710 // Move the next request into the FQ and update heaps as needed.
1692 ikglp_move_next_to_fq(sem, fq, t, &fq->donee_heap_node, 1); 1711 // Skip this step we already did this during the virtual unlock.
1712 ikglp_move_next_to_fq(sem, fq, t, &fq->donee_heap_node, &flags,
1713 ALLOW_STEALING, !ALWAYS_TERMINATE_DONATION);
1714 }
1715 else
1716 fq->is_vunlocked = 0; /* reset vunlock flag */
1693 1717
1694 if (waitqueue_active(&fq->wait)) 1718 if (waitqueue_active(&fq->wait))
1695 ikglp_grant_replica_to_next(sem, fq); 1719 ikglp_grant_replica_to_next(sem, fq);
@@ -1755,7 +1779,8 @@ void ikglp_abort_request(struct ikglp_semaphore *sem, struct task_struct *t, uns
1755 1779
1756 ikglp_refresh_owners_prio_decrease(wait->donee_heap_node.fq, sem, flags, 1); // unlocks sem->lock. reacquire it. 1780 ikglp_refresh_owners_prio_decrease(wait->donee_heap_node.fq, sem, flags, 1); // unlocks sem->lock. reacquire it.
1757 lock_fine_irqsave(&sem->lock, flags); // there should be no contention!!!! 1781 lock_fine_irqsave(&sem->lock, flags); // there should be no contention!!!!
1758 ikglp_move_next_to_fq(sem, fq, t, &wait->donee_heap_node, 1); 1782 ikglp_move_next_to_fq(sem, fq, t, &wait->donee_heap_node, &flags,
1783 ALLOW_STEALING, !ALWAYS_TERMINATE_DONATION);
1759 break; 1784 break;
1760 1785
1761 1786
@@ -1900,7 +1925,51 @@ void ikglp_budget_exhausted(struct litmus_lock* l, struct task_struct* t)
1900 1925
1901void ikglp_virtual_unlock(struct litmus_lock* l, struct task_struct* t) 1926void ikglp_virtual_unlock(struct litmus_lock* l, struct task_struct* t)
1902{ 1927{
1903 TRACE_TASK(t, "TODO!\n"); 1928 /* PRE: DGL lock already held if DGLs are supported */
1929
1930 struct ikglp_semaphore *sem = ikglp_from_lock(l);
1931 struct fifo_queue *fq = ikglp_get_queue(sem, t);
1932 unsigned long flags = 0, more_flags;
1933
1934 TRACE_TASK(t, "virtual unlock!\n");
1935
1936 if (!fq)
1937 return;
1938
1939 if (fq->is_vunlocked) {
1940 TRACE_TASK(t, "Lock %d already virtually unlocked.\n", l->ident);
1941 return;
1942 }
1943
1944 raw_spin_lock_irqsave(&sem->real_lock, more_flags);
1945 lock_fine_irqsave(&sem->lock, flags);
1946
1947 if (unlikely(fq->owner != t)) {
1948 TRACE_TASK(t, "no longer holds lock %d.\n", l->ident);
1949 goto out;
1950 }
1951
1952 TRACE_TASK(t, "IKGLP before virtual unlock:\n");
1953 __ikglp_dump_state(sem);
1954
1955 /* Move a request from donor heap or PQ to fq. don't steal from
1956 * other FQs. Also, terminate donation relationship if we move
1957 * a donor to 't' to the FQ (we'll pick inheritance back up via
1958 * the FQ, if needed). */
1959 ikglp_move_next_to_fq(sem, fq, t, &fq->donee_heap_node, &flags,
1960 !ALLOW_STEALING, ALWAYS_TERMINATE_DONATION);
1961
1962 /* decrement fifo count to simulate unlock. individual fifo
1963 * length counts remain unchanged. */
1964 --(sem->nr_in_fifos);
1965 fq->is_vunlocked = 1;
1966
1967 TRACE_TASK(t, "IKGLP after virtual unlock:\n");
1968 __ikglp_dump_state(sem);
1969
1970out:
1971 unlock_fine_irqrestore(&sem->lock, flags);
1972 raw_spin_unlock_irqrestore(&sem->real_lock, more_flags);
1904} 1973}
1905 1974
1906 1975
@@ -2030,6 +2099,7 @@ struct litmus_lock* ikglp_new(unsigned int m,
2030 q->hp_waiter = NULL; 2099 q->hp_waiter = NULL;
2031 init_waitqueue_head(&q->wait); 2100 init_waitqueue_head(&q->wait);
2032 q->count = 0; 2101 q->count = 0;
2102 q->is_vunlocked = 0;
2033 2103
2034 q->global_heap_node.task = NULL; 2104 q->global_heap_node.task = NULL;
2035 INIT_BINHEAP_NODE(&q->global_heap_node.node); 2105 INIT_BINHEAP_NODE(&q->global_heap_node.node);
@@ -2316,7 +2386,8 @@ struct fifo_queue* gpu_ikglp_advise_enqueue(struct ikglp_affinity* aff, struct t
2316 2386
2317 for(i = 0; i < sem->nr_replicas; ++i) { 2387 for(i = 0; i < sem->nr_replicas; ++i) {
2318 if(&aff->q_info[i] != shortest) { 2388 if(&aff->q_info[i] != shortest) {
2319 if(aff->q_info[i].q->count < max_fifo_len) { 2389 /* is there room on this q? */
2390 if(nominal_fq_len(aff->q_info[i].q) < max_fifo_len) {
2320 int want = 0; 2391 int want = 0;
2321 2392
2322 lt_t migration = 2393 lt_t migration =
@@ -2335,7 +2406,7 @@ struct fifo_queue* gpu_ikglp_advise_enqueue(struct ikglp_affinity* aff, struct t
2335 // queues "close enough" in length to be considered equal. 2406 // queues "close enough" in length to be considered equal.
2336 2407
2337 /* NOTE: 'shortest' starts out with affinity GPU */ 2408 /* NOTE: 'shortest' starts out with affinity GPU */
2338 if(unlikely(shortest->q->count >= max_fifo_len)) { /* 'shortest' is full and i-th queue is not */ 2409 if(unlikely(nominal_fq_len(shortest->q) >= max_fifo_len)) { /* 'shortest' is full and i-th queue is not */
2339 want = 1; 2410 want = 1;
2340 } 2411 }
2341 else if(est_len < min_len) { 2412 else if(est_len < min_len) {
@@ -2363,7 +2434,7 @@ struct fifo_queue* gpu_ikglp_advise_enqueue(struct ikglp_affinity* aff, struct t
2363 min_nr_aff_users = *(aff->q_info[i].nr_aff_users); 2434 min_nr_aff_users = *(aff->q_info[i].nr_aff_users);
2364 } 2435 }
2365 2436
2366 TRACE_CUR("cs is %llu on queue %d (count = %d): est len = %llu\n", 2437 TRACE_CUR("cs is %llu on queue %d (count = %u): est len = %llu\n",
2367 get_gpu_estimate(t, 2438 get_gpu_estimate(t,
2368 gpu_migration_distance(tsk_rt(t)->last_gpu, 2439 gpu_migration_distance(tsk_rt(t)->last_gpu,
2369 replica_to_gpu(aff, i))), 2440 replica_to_gpu(aff, i))),
@@ -2378,13 +2449,13 @@ struct fifo_queue* gpu_ikglp_advise_enqueue(struct ikglp_affinity* aff, struct t
2378 } 2449 }
2379 } 2450 }
2380 2451
2381 if(shortest->q->count >= max_fifo_len) { 2452 if(nominal_fq_len(shortest->q) >= max_fifo_len) {
2382 TRACE_CUR("selected fq %d is too long, but returning it anyway.\n", 2453 TRACE_CUR("selected fq %d is too long, but returning it anyway.\n",
2383 ikglp_get_idx(sem, shortest->q)); 2454 ikglp_get_idx(sem, shortest->q));
2384 } 2455 }
2385 2456
2386 to_enqueue = shortest->q; 2457 to_enqueue = shortest->q;
2387 TRACE_CUR("enqueue on fq %d (count = %d) (non-aff wanted fq %d)\n", 2458 TRACE_CUR("enqueue on fq %d (count = %u) (non-aff wanted fq %d)\n",
2388 ikglp_get_idx(sem, to_enqueue), 2459 ikglp_get_idx(sem, to_enqueue),
2389 to_enqueue->count, 2460 to_enqueue->count,
2390 ikglp_get_idx(sem, sem->shortest_fifo_queue)); 2461 ikglp_get_idx(sem, sem->shortest_fifo_queue));
diff --git a/litmus/sched_cedf.c b/litmus/sched_cedf.c
index 7178b6cd3ba1..879f781cf1aa 100644
--- a/litmus/sched_cedf.c
+++ b/litmus/sched_cedf.c
@@ -703,6 +703,35 @@ static enum hrtimer_restart cedf_simple_on_exhausted(struct task_struct *t)
703 return HRTIMER_NORESTART; 703 return HRTIMER_NORESTART;
704} 704}
705 705
706
707#ifdef CONFIG_LITMUS_LOCKING
708static void __cedf_trigger_vunlock(struct task_struct *t)
709{
710 TRACE_TASK(t, "triggering virtual unlock of lock %d\n",
711 tsk_rt(t)->outermost_lock->ident);
712 tsk_rt(t)->outermost_lock->ops->omlp_virtual_unlock(tsk_rt(t)->outermost_lock, t);
713}
714
715static void cedf_trigger_vunlock(struct task_struct *t)
716{
717 cedf_domain_t *cluster = task_cpu_cluster(t);
718#ifdef CONFIG_LITMUS_DGL_SUPPORT
719 unsigned long flags;
720
721 /* Unfortunately, we _might_ need to grab the DGL lock, so we
722 * must grab it every time since it must be take before the
723 * cluster lock. */
724 raw_spin_lock_irqsave(&cluster->dgl_lock, flags);
725#endif
726
727 __cedf_trigger_vunlock(t);
728
729#ifdef CONFIG_LITMUS_DGL_SUPPORT
730 raw_spin_unlock_irqrestore(&cluster->dgl_lock, flags);
731#endif
732}
733#endif
734
706static enum hrtimer_restart cedf_sobliv_on_exhausted(struct task_struct *t) 735static enum hrtimer_restart cedf_sobliv_on_exhausted(struct task_struct *t)
707{ 736{
708 enum hrtimer_restart restart = HRTIMER_NORESTART; 737 enum hrtimer_restart restart = HRTIMER_NORESTART;
@@ -719,126 +748,136 @@ static enum hrtimer_restart cedf_sobliv_on_exhausted(struct task_struct *t)
719 } 748 }
720 749
721 if (budget_enforced(t) && !bt_flag_is_set(t, BTF_BUDGET_EXHAUSTED)) { 750 if (budget_enforced(t) && !bt_flag_is_set(t, BTF_BUDGET_EXHAUSTED)) {
751 int cpu = (tsk_rt(t)->linked_on != NO_CPU) ?
752 tsk_rt(t)->linked_on : tsk_rt(t)->scheduled_on;
753
754#ifdef CONFIG_LITMUS_LOCKING
755 /* if 't' running, trigger a virtual unlock of outermost held lock
756 * if supported. Case where 't' not running handled later in function.
757 */
758 if (cpu != NO_CPU &&
759 tsk_rt(t)->outermost_lock &&
760 tsk_rt(t)->outermost_lock->ops->is_omlp_family)
761 cedf_trigger_vunlock(t);
762#endif
763
722 if (is_np(t) && is_user_np(t)) { 764 if (is_np(t) && is_user_np(t)) {
723 TRACE_TASK(t, "is non-preemptable, preemption delayed.\n"); 765 TRACE_TASK(t, "is non-preemptable, preemption delayed.\n");
724 bt_flag_set(t, BTF_BUDGET_EXHAUSTED); 766 bt_flag_set(t, BTF_BUDGET_EXHAUSTED);
725 request_exit_np(t); 767 request_exit_np(t);
726 } 768 }
769 /* where do we need to call resched? */
770 else if (cpu == smp_processor_id()) {
771 TRACE_TASK(t, "is preemptable => FORCE_RESCHED\n");
772 bt_flag_set(t, BTF_BUDGET_EXHAUSTED);
773 litmus_reschedule_local();
774 set_will_schedule();
775 }
776 else if (cpu != NO_CPU) {
777 TRACE_TASK(t, "is preemptable on remote cpu (%d) => FORCE_RESCHED\n", cpu);
778 bt_flag_set(t, BTF_BUDGET_EXHAUSTED);
779 litmus_reschedule(cpu);
780 }
727 else { 781 else {
728 /* where do we need to call resched? */ 782 lt_t remaining;
729 int cpu = (tsk_rt(t)->linked_on != NO_CPU) ? 783 cedf_domain_t *cluster;
730 tsk_rt(t)->linked_on : tsk_rt(t)->scheduled_on; 784 unsigned long flags;
731 if (cpu == smp_processor_id()) {
732 TRACE_TASK(t, "is preemptable => FORCE_RESCHED\n");
733 785
734 bt_flag_set(t, BTF_BUDGET_EXHAUSTED); 786 cluster = task_cpu_cluster(t);
735 litmus_reschedule_local();
736 set_will_schedule();
737 }
738 else if (cpu != NO_CPU) {
739 TRACE_TASK(t, "is preemptable on remote cpu (%d) => FORCE_RESCHED\n", cpu);
740 787
741 bt_flag_set(t, BTF_BUDGET_EXHAUSTED); 788 // 1) refresh budget through job completion
742 litmus_reschedule(cpu); 789 // 2) if holds locks, tell the locking protocol to re-eval priority
743 } 790 // 3) -- the LP must undo any inheritance relations if appropriate
744 else {
745 lt_t remaining;
746 cedf_domain_t* cluster = task_cpu_cluster(t);
747 unsigned long flags;
748
749 BUG_ON(cpu != NO_CPU);
750
751 // 1) refresh budget through job completion
752 // 2) if holds locks, tell the locking protocol to re-eval priority
753 // 3) -- the LP must undo any inheritance relations if appropriate
754 791
755 /* force job completion */ 792 /* force job completion */
756 TRACE_TASK(t, "blocked, postponing deadline\n"); 793 TRACE_TASK(t, "blocked, postponing deadline\n");
757 794
758 /* Outermost lock of the cluster. Recursive lock calls are 795 /* Outermost lock of the cluster. Recursive lock calls are
759 * possible on this code path. This should be the _ONLY_ 796 * possible on this code path. This should be the _ONLY_
760 * scenario where recursive calls are made. */ 797 * scenario where recursive calls are made. */
761#ifdef CONFIG_LITMUS_DGL_SUPPORT 798#ifdef CONFIG_LITMUS_DGL_SUPPORT
762 /* Unfortunately, we _might_ need to grab the DGL lock, so we 799 /* Unfortunately, we _might_ need to grab the DGL lock, so we
763 * must grab it every time since it must be take before the 800 * must grab it every time since it must be take before the
764 * cluster lock. */ 801 * cluster lock. */
765 raw_spin_lock_irqsave(&cluster->dgl_lock, flags); 802 raw_spin_lock_irqsave(&cluster->dgl_lock, flags);
766 raw_readyq_lock(&cluster->cluster_lock); 803 raw_readyq_lock(&cluster->cluster_lock);
767#else 804#else
768 raw_readyq_lock_irqsave(&cluster->cluster_lock, flags); 805 raw_readyq_lock_irqsave(&cluster->cluster_lock, flags);
769#endif 806#endif
770 807
771 job_completion(t, 1); /* refreshes budget and pushes out deadline */ 808 job_completion(t, 1); /* refreshes budget and pushes out deadline */
772 809
773#ifdef CONFIG_LITMUS_LOCKING 810#ifdef CONFIG_LITMUS_LOCKING
811 {
812 int i;
813 /* any linked task that inherits from 't' needs to have their
814 * cpu-position re-evaluated. we have to do this in two passes.
815 * pass 1: remove nodes from heap s.t. heap is in known good state.
816 * pass 2: re-add nodes.
817 *
818 */
819 for (i = find_first_bit(&tsk_rt(t)->used_linkback_slots, BITS_PER_BYTE*sizeof(&tsk_rt(t)->used_linkback_slots));
820 i < BITS_PER_LONG;
821 i = find_next_bit(&tsk_rt(t)->used_linkback_slots, BITS_PER_BYTE*sizeof(&tsk_rt(t)->used_linkback_slots), i+1))
774 { 822 {
775 int i; 823 struct task_struct *to_update = tsk_rt(t)->inh_task_linkbacks[i];
776 /* any linked task that inherits from 't' needs to have their 824 BUG_ON(!to_update);
777 * cpu-position re-evaluated. we have to do this in two passes. 825 if (tsk_rt(to_update)->linked_on != NO_CPU) {
778 * pass 1: remove nodes from heap s.t. heap is in known good state. 826 cpu_entry_t *entry = &per_cpu(cedf_cpu_entries, tsk_rt(to_update)->linked_on);
779 * pass 2: re-add nodes. 827 BUG_ON(!binheap_is_in_heap(&entry->hn));
780 * 828 binheap_delete(&entry->hn, &cluster->cpu_heap);
781 */
782 for (i = find_first_bit(&tsk_rt(t)->used_linkback_slots, BITS_PER_BYTE*sizeof(&tsk_rt(t)->used_linkback_slots));
783 i < BITS_PER_LONG;
784 i = find_next_bit(&tsk_rt(t)->used_linkback_slots, BITS_PER_BYTE*sizeof(&tsk_rt(t)->used_linkback_slots), i+1))
785 {
786 struct task_struct *to_update = tsk_rt(t)->inh_task_linkbacks[i];
787 BUG_ON(!to_update);
788 if (tsk_rt(to_update)->linked_on != NO_CPU) {
789 cpu_entry_t *entry = &per_cpu(cedf_cpu_entries, tsk_rt(to_update)->linked_on);
790 BUG_ON(!binheap_is_in_heap(&entry->hn));
791 binheap_delete(&entry->hn, &cluster->cpu_heap);
792 }
793 } 829 }
794 for (i = find_first_bit(&tsk_rt(t)->used_linkback_slots, BITS_PER_BYTE*sizeof(&tsk_rt(t)->used_linkback_slots)); 830 }
795 i < BITS_PER_LONG; 831 for (i = find_first_bit(&tsk_rt(t)->used_linkback_slots, BITS_PER_BYTE*sizeof(&tsk_rt(t)->used_linkback_slots));
796 i = find_next_bit(&tsk_rt(t)->used_linkback_slots, BITS_PER_BYTE*sizeof(&tsk_rt(t)->used_linkback_slots), i+1)) 832 i < BITS_PER_LONG;
797 { 833 i = find_next_bit(&tsk_rt(t)->used_linkback_slots, BITS_PER_BYTE*sizeof(&tsk_rt(t)->used_linkback_slots), i+1))
798 struct task_struct *to_update = tsk_rt(t)->inh_task_linkbacks[i]; 834 {
799 BUG_ON(!to_update); 835 struct task_struct *to_update = tsk_rt(t)->inh_task_linkbacks[i];
800 if (tsk_rt(to_update)->linked_on != NO_CPU) { 836 BUG_ON(!to_update);
801 cpu_entry_t *entry = &per_cpu(cedf_cpu_entries, tsk_rt(to_update)->linked_on); 837 if (tsk_rt(to_update)->linked_on != NO_CPU) {
802 binheap_add(&entry->hn, &cluster->cpu_heap, cpu_entry_t, hn); 838 cpu_entry_t *entry = &per_cpu(cedf_cpu_entries, tsk_rt(to_update)->linked_on);
803 } 839 binheap_add(&entry->hn, &cluster->cpu_heap, cpu_entry_t, hn);
804 } 840 }
805 } 841 }
842 }
806 843
807 /* Check our inheritance and propagate any changes forward. */ 844 /* Check our inheritance and propagate any changes forward. */
808 sobliv_revaluate_task(t); 845 sobliv_revaluate_task(t);
846
847 if (tsk_rt(t)->outermost_lock && tsk_rt(t)->outermost_lock->ops->is_omlp_family)
848 __cedf_trigger_vunlock(t);
809#endif 849#endif
810 /* No need to recheck priority of AUX tasks. They will always 850 /* No need to recheck priority of AUX tasks. They will always
811 * inherit from 't' if they are enabled. Their prio change was 851 * inherit from 't' if they are enabled. Their prio change was
812 * captured by the cpu-heap operations above. */ 852 * captured by the cpu-heap operations above. */
813 853
814#ifdef CONFIG_LITMUS_NVIDIA 854#ifdef CONFIG_LITMUS_NVIDIA
815 /* Re-eval priority of GPU interrupt threads. */ 855 /* Re-eval priority of GPU interrupt threads. */
816 if(tsk_rt(t)->held_gpus && !tsk_rt(t)->hide_from_gpu) 856 if(tsk_rt(t)->held_gpus && !tsk_rt(t)->hide_from_gpu)
817 recheck_gpu_owner(t); 857 recheck_gpu_owner(t);
818#endif 858#endif
819 859
820#ifdef CONFIG_LITMUS_LOCKING 860#ifdef CONFIG_LITMUS_LOCKING
821 /* double-check that everything is okay */ 861 /* double-check that everything is okay */
822 check_for_preemptions(cluster); 862 check_for_preemptions(cluster);
823#endif 863#endif
824 864
825 /* should be the outermost unlock call */ 865 /* should be the outermost unlock call */
826#ifdef CONFIG_LITMUS_DGL_SUPPORT 866#ifdef CONFIG_LITMUS_DGL_SUPPORT
827 raw_readyq_unlock(&cluster->cluster_lock); 867 raw_readyq_unlock(&cluster->cluster_lock);
828 raw_spin_unlock_irqrestore(&cluster->dgl_lock, flags); 868 raw_spin_unlock_irqrestore(&cluster->dgl_lock, flags);
829#else 869#else
830 raw_readyq_unlock_irqrestore(&cluster->cluster_lock, flags); 870 raw_readyq_unlock_irqrestore(&cluster->cluster_lock, flags);
831#endif 871#endif
832 872
833 /* we need to set up the budget timer since we're within the callback. */ 873 /* we need to set up the budget timer since we're within the callback. */
834 if (bt_flag_is_set(t, BTF_IS_TOP_M)) { 874 if (bt_flag_is_set(t, BTF_IS_TOP_M)) {
835 hrtimer_forward_now(&get_budget_timer(t).timer.timer, 875 hrtimer_forward_now(&get_budget_timer(t).timer.timer,
836 ns_to_ktime(budget_remaining(t))); 876 ns_to_ktime(budget_remaining(t)));
837 remaining = hrtimer_get_expires_ns(&get_budget_timer(t).timer.timer); 877 remaining = hrtimer_get_expires_ns(&get_budget_timer(t).timer.timer);
838 878
839 TRACE_TASK(t, "rearmed timer to %ld\n", remaining); 879 TRACE_TASK(t, "rearmed timer to %ld\n", remaining);
840 restart = HRTIMER_RESTART; 880 restart = HRTIMER_RESTART;
841 }
842 } 881 }
843 } 882 }
844 } 883 }
@@ -1160,6 +1199,9 @@ static void cedf_change_prio_pai_tasklet(struct task_struct *old_prio,
1160 1199
1161#endif // PAI 1200#endif // PAI
1162 1201
1202#ifdef CONFIG_LITMUS_LOCKING
1203static int __increase_priority_inheritance(struct task_struct* t, struct task_struct* prio_inh);
1204#endif
1163 1205
1164/* Getting schedule() right is a bit tricky. schedule() may not make any 1206/* Getting schedule() right is a bit tricky. schedule() may not make any
1165 * assumptions on the state of the current task since it may be called for a 1207 * assumptions on the state of the current task since it may be called for a
@@ -1189,6 +1231,10 @@ static struct task_struct* cedf_schedule(struct task_struct * prev)
1189 int out_of_time, sleep, preempt, np, exists, blocks; 1231 int out_of_time, sleep, preempt, np, exists, blocks;
1190 struct task_struct* next = NULL; 1232 struct task_struct* next = NULL;
1191 1233
1234#ifdef CONFIG_LITMUS_NESTED_LOCKING
1235 int recheck_inheritance;
1236#endif
1237
1192#ifdef CONFIG_RELEASE_MASTER 1238#ifdef CONFIG_RELEASE_MASTER
1193 /* Bail out early if we are the release master. 1239 /* Bail out early if we are the release master.
1194 * The release master never schedules any real-time tasks. 1240 * The release master never schedules any real-time tasks.
@@ -1199,6 +1245,27 @@ static struct task_struct* cedf_schedule(struct task_struct * prev)
1199 } 1245 }
1200#endif 1246#endif
1201 1247
1248#ifdef CONFIG_LITMUS_NESTED_LOCKING
1249 /* prevent updates to inheritance relations while we work with 'prev' */
1250 /* recheck inheritance if the task holds locks, is running, and will
1251 * have its deadline pushed out by job_completion() */
1252 recheck_inheritance =
1253 (prev != NULL) &&
1254 is_realtime(prev) &&
1255 holds_locks(prev) &&
1256 !is_np(prev) &&
1257 !is_completed(prev) &&
1258 is_running(prev) &&
1259 budget_enforced(prev) &&
1260 bt_flag_is_set(prev, BTF_BUDGET_EXHAUSTED);
1261 if (recheck_inheritance) {
1262#ifdef CONFIG_LITMUS_DGL_SUPPORT
1263 raw_spin_lock(&cluster->dgl_lock);
1264#endif
1265 raw_spin_lock(&tsk_rt(prev)->hp_blocked_tasks_lock);
1266 }
1267#endif
1268
1202 raw_readyq_lock(&cluster->cluster_lock); 1269 raw_readyq_lock(&cluster->cluster_lock);
1203 clear_will_schedule(); 1270 clear_will_schedule();
1204 1271
@@ -1223,7 +1290,7 @@ static struct task_struct* cedf_schedule(struct task_struct * prev)
1223 1290
1224 if (exists) { 1291 if (exists) {
1225 TRACE_TASK(prev, 1292 TRACE_TASK(prev,
1226 "blocks:%d out_of_time:%d np:%d sleep:%d preempt:%d " 1293 "blocks:%d out_of_time:%d np:%d completed:%d preempt:%d "
1227 "state:%d sig:%d\n", 1294 "state:%d sig:%d\n",
1228 blocks, out_of_time, np, sleep, preempt, 1295 blocks, out_of_time, np, sleep, preempt,
1229 prev->state, signal_pending(prev)); 1296 prev->state, signal_pending(prev));
@@ -1284,8 +1351,22 @@ static struct task_struct* cedf_schedule(struct task_struct * prev)
1284 * this. Don't do a job completion if we block (can't have timers running 1351 * this. Don't do a job completion if we block (can't have timers running
1285 * for blocked jobs). 1352 * for blocked jobs).
1286 */ 1353 */
1287 if (!np && (out_of_time || sleep) && !blocks) 1354 if (!np && (out_of_time || sleep) && !blocks) {
1288 job_completion(entry->scheduled, !sleep); 1355 job_completion(entry->scheduled, !sleep);
1356#ifdef CONFIG_LITMUS_NESTED_LOCKING
1357 /* check if job completion enables an inheritance relation. no need to
1358 * recheck if task already inherits a priority since job_completion()
1359 * will not enable a higher-prio relation */
1360 if (unlikely(recheck_inheritance && !tsk_rt(entry->scheduled)->inh_task)) {
1361 struct task_struct *hp_blocked;
1362 TRACE_TASK(entry->scheduled, "rechecking inheritance.\n");
1363 hp_blocked = top_priority(&tsk_rt(entry->scheduled)->hp_blocked_tasks);
1364 /* hp_blocked_tasks_lock is held */
1365 if (edf_higher_prio(hp_blocked, entry->scheduled))
1366 __increase_priority_inheritance(entry->scheduled, effective_priority(hp_blocked));
1367 }
1368#endif
1369 }
1289 1370
1290 /* Link pending task if we became unlinked. 1371 /* Link pending task if we became unlinked.
1291 */ 1372 */
@@ -1317,7 +1398,6 @@ static struct task_struct* cedf_schedule(struct task_struct * prev)
1317 } 1398 }
1318 } 1399 }
1319 1400
1320
1321#ifdef CONFIG_REALTIME_AUX_TASKS 1401#ifdef CONFIG_REALTIME_AUX_TASKS
1322out_set_state: 1402out_set_state:
1323#endif 1403#endif
@@ -1325,6 +1405,15 @@ out_set_state:
1325 sched_state_task_picked(); 1405 sched_state_task_picked();
1326 raw_readyq_unlock(&cluster->cluster_lock); 1406 raw_readyq_unlock(&cluster->cluster_lock);
1327 1407
1408#ifdef CONFIG_LITMUS_NESTED_LOCKING
1409 if (recheck_inheritance) {
1410 raw_spin_unlock(&tsk_rt(prev)->hp_blocked_tasks_lock);
1411#ifdef CONFIG_LITMUS_DGL_SUPPORT
1412 raw_spin_unlock(&cluster->dgl_lock);
1413#endif
1414 }
1415#endif
1416
1328#ifdef WANT_ALL_SCHED_EVENTS 1417#ifdef WANT_ALL_SCHED_EVENTS
1329 TRACE("cluster_lock released, next=0x%p\n", next); 1418 TRACE("cluster_lock released, next=0x%p\n", next);
1330 1419