diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2013-04-09 15:02:28 -0400 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2013-04-09 16:04:07 -0400 |
commit | 202a0410c911d9f9522d76db6405b0f6001aed5b (patch) | |
tree | 9f1372be13bfe6264e0bd8214e6a4153f59813fb | |
parent | 63a043514200704c9f2f288075bf4e9b268f57bd (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.h | 9 | ||||
-rw-r--r-- | litmus/budget.c | 9 | ||||
-rw-r--r-- | litmus/ikglp_lock.c | 125 | ||||
-rw-r--r-- | litmus/sched_cedf.c | 267 |
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 | ||
78 | struct ikglp_semaphore | 87 | struct 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 | ||
80 | static inline unsigned int nominal_fq_len(struct fifo_queue *fq) | ||
81 | { | ||
82 | return (fq->count - fq->is_vunlocked); | ||
83 | } | ||
80 | 84 | ||
81 | static inline int ikglp_get_idx(struct ikglp_semaphore *sem, | 85 | static 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 | ||
196 | static void __ikglp_dump_fifoq(int i, struct fifo_queue* fq) | 201 | static 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 | |||
1398 | void ikglp_move_next_to_fq(struct ikglp_semaphore *sem, | 1407 | void 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 | ||
1901 | void ikglp_virtual_unlock(struct litmus_lock* l, struct task_struct* t) | 1926 | void 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 | |||
1970 | out: | ||
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 | ||
708 | static 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 | |||
715 | static 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 | |||
706 | static enum hrtimer_restart cedf_sobliv_on_exhausted(struct task_struct *t) | 735 | static 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 | ||
1203 | static 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 |
1322 | out_set_state: | 1402 | out_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 | ||