diff options
Diffstat (limited to 'kernel/locking')
| -rw-r--r-- | kernel/locking/rtmutex.c | 133 |
1 files changed, 88 insertions, 45 deletions
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index 50bc93b3552f..39c9f8075e14 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c | |||
| @@ -533,76 +533,119 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, | |||
| 533 | * | 533 | * |
| 534 | * Must be called with lock->wait_lock held. | 534 | * Must be called with lock->wait_lock held. |
| 535 | * | 535 | * |
| 536 | * @lock: the lock to be acquired. | 536 | * @lock: The lock to be acquired. |
| 537 | * @task: the task which wants to acquire the lock | 537 | * @task: The task which wants to acquire the lock |
| 538 | * @waiter: the waiter that is queued to the lock's wait list. (could be NULL) | 538 | * @waiter: The waiter that is queued to the lock's wait list if the |
| 539 | * callsite called task_blocked_on_lock(), otherwise NULL | ||
| 539 | */ | 540 | */ |
| 540 | static int try_to_take_rt_mutex(struct rt_mutex *lock, struct task_struct *task, | 541 | static int try_to_take_rt_mutex(struct rt_mutex *lock, struct task_struct *task, |
| 541 | struct rt_mutex_waiter *waiter) | 542 | struct rt_mutex_waiter *waiter) |
| 542 | { | 543 | { |
| 544 | unsigned long flags; | ||
| 545 | |||
| 543 | /* | 546 | /* |
| 544 | * We have to be careful here if the atomic speedups are | 547 | * Before testing whether we can acquire @lock, we set the |
| 545 | * enabled, such that, when | 548 | * RT_MUTEX_HAS_WAITERS bit in @lock->owner. This forces all |
| 546 | * - no other waiter is on the lock | 549 | * other tasks which try to modify @lock into the slow path |
| 547 | * - the lock has been released since we did the cmpxchg | 550 | * and they serialize on @lock->wait_lock. |
| 548 | * the lock can be released or taken while we are doing the | ||
| 549 | * checks and marking the lock with RT_MUTEX_HAS_WAITERS. | ||
| 550 | * | 551 | * |
| 551 | * The atomic acquire/release aware variant of | 552 | * The RT_MUTEX_HAS_WAITERS bit can have a transitional state |
| 552 | * mark_rt_mutex_waiters uses a cmpxchg loop. After setting | 553 | * as explained at the top of this file if and only if: |
| 553 | * the WAITERS bit, the atomic release / acquire can not | ||
| 554 | * happen anymore and lock->wait_lock protects us from the | ||
| 555 | * non-atomic case. | ||
| 556 | * | 554 | * |
| 557 | * Note, that this might set lock->owner = | 555 | * - There is a lock owner. The caller must fixup the |
| 558 | * RT_MUTEX_HAS_WAITERS in the case the lock is not contended | 556 | * transient state if it does a trylock or leaves the lock |
| 559 | * any more. This is fixed up when we take the ownership. | 557 | * function due to a signal or timeout. |
| 560 | * This is the transitional state explained at the top of this file. | 558 | * |
| 559 | * - @task acquires the lock and there are no other | ||
| 560 | * waiters. This is undone in rt_mutex_set_owner(@task) at | ||
| 561 | * the end of this function. | ||
| 561 | */ | 562 | */ |
| 562 | mark_rt_mutex_waiters(lock); | 563 | mark_rt_mutex_waiters(lock); |
| 563 | 564 | ||
| 565 | /* | ||
| 566 | * If @lock has an owner, give up. | ||
| 567 | */ | ||
| 564 | if (rt_mutex_owner(lock)) | 568 | if (rt_mutex_owner(lock)) |
| 565 | return 0; | 569 | return 0; |
| 566 | 570 | ||
| 567 | /* | 571 | /* |
| 568 | * It will get the lock because of one of these conditions: | 572 | * If @waiter != NULL, @task has already enqueued the waiter |
| 569 | * 1) there is no waiter | 573 | * into @lock waiter list. If @waiter == NULL then this is a |
| 570 | * 2) higher priority than waiters | 574 | * trylock attempt. |
| 571 | * 3) it is top waiter | ||
| 572 | */ | 575 | */ |
| 573 | if (rt_mutex_has_waiters(lock)) { | 576 | if (waiter) { |
| 574 | if (task->prio >= rt_mutex_top_waiter(lock)->prio) { | 577 | /* |
| 575 | if (!waiter || waiter != rt_mutex_top_waiter(lock)) | 578 | * If waiter is not the highest priority waiter of |
| 576 | return 0; | 579 | * @lock, give up. |
| 577 | } | 580 | */ |
| 578 | } | 581 | if (waiter != rt_mutex_top_waiter(lock)) |
| 579 | 582 | return 0; | |
| 580 | if (waiter || rt_mutex_has_waiters(lock)) { | ||
| 581 | unsigned long flags; | ||
| 582 | struct rt_mutex_waiter *top; | ||
| 583 | |||
| 584 | raw_spin_lock_irqsave(&task->pi_lock, flags); | ||
| 585 | 583 | ||
| 586 | /* remove the queued waiter. */ | 584 | /* |
| 587 | if (waiter) { | 585 | * We can acquire the lock. Remove the waiter from the |
| 588 | rt_mutex_dequeue(lock, waiter); | 586 | * lock waiters list. |
| 589 | task->pi_blocked_on = NULL; | 587 | */ |
| 590 | } | 588 | rt_mutex_dequeue(lock, waiter); |
| 591 | 589 | ||
| 590 | } else { | ||
| 592 | /* | 591 | /* |
| 593 | * We have to enqueue the top waiter(if it exists) into | 592 | * If the lock has waiters already we check whether @task is |
| 594 | * task->pi_waiters list. | 593 | * eligible to take over the lock. |
| 594 | * | ||
| 595 | * If there are no other waiters, @task can acquire | ||
| 596 | * the lock. @task->pi_blocked_on is NULL, so it does | ||
| 597 | * not need to be dequeued. | ||
| 595 | */ | 598 | */ |
| 596 | if (rt_mutex_has_waiters(lock)) { | 599 | if (rt_mutex_has_waiters(lock)) { |
| 597 | top = rt_mutex_top_waiter(lock); | 600 | /* |
| 598 | rt_mutex_enqueue_pi(task, top); | 601 | * If @task->prio is greater than or equal to |
| 602 | * the top waiter priority (kernel view), | ||
| 603 | * @task lost. | ||
| 604 | */ | ||
| 605 | if (task->prio >= rt_mutex_top_waiter(lock)->prio) | ||
| 606 | return 0; | ||
| 607 | |||
| 608 | /* | ||
| 609 | * The current top waiter stays enqueued. We | ||
| 610 | * don't have to change anything in the lock | ||
| 611 | * waiters order. | ||
| 612 | */ | ||
| 613 | } else { | ||
| 614 | /* | ||
| 615 | * No waiters. Take the lock without the | ||
| 616 | * pi_lock dance.@task->pi_blocked_on is NULL | ||
| 617 | * and we have no waiters to enqueue in @task | ||
| 618 | * pi waiters list. | ||
| 619 | */ | ||
| 620 | goto takeit; | ||
| 599 | } | 621 | } |
| 600 | raw_spin_unlock_irqrestore(&task->pi_lock, flags); | ||
| 601 | } | 622 | } |
| 602 | 623 | ||
| 624 | /* | ||
| 625 | * Clear @task->pi_blocked_on. Requires protection by | ||
| 626 | * @task->pi_lock. Redundant operation for the @waiter == NULL | ||
| 627 | * case, but conditionals are more expensive than a redundant | ||
| 628 | * store. | ||
| 629 | */ | ||
| 630 | raw_spin_lock_irqsave(&task->pi_lock, flags); | ||
| 631 | task->pi_blocked_on = NULL; | ||
| 632 | /* | ||
| 633 | * Finish the lock acquisition. @task is the new owner. If | ||
| 634 | * other waiters exist we have to insert the highest priority | ||
| 635 | * waiter into @task->pi_waiters list. | ||
| 636 | */ | ||
| 637 | if (rt_mutex_has_waiters(lock)) | ||
| 638 | rt_mutex_enqueue_pi(task, rt_mutex_top_waiter(lock)); | ||
| 639 | raw_spin_unlock_irqrestore(&task->pi_lock, flags); | ||
| 640 | |||
| 641 | takeit: | ||
| 603 | /* We got the lock. */ | 642 | /* We got the lock. */ |
| 604 | debug_rt_mutex_lock(lock); | 643 | debug_rt_mutex_lock(lock); |
| 605 | 644 | ||
| 645 | /* | ||
| 646 | * This either preserves the RT_MUTEX_HAS_WAITERS bit if there | ||
| 647 | * are still waiters or clears it. | ||
| 648 | */ | ||
| 606 | rt_mutex_set_owner(lock, task); | 649 | rt_mutex_set_owner(lock, task); |
| 607 | 650 | ||
| 608 | rt_mutex_deadlock_account_lock(lock, task); | 651 | rt_mutex_deadlock_account_lock(lock, task); |
