Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

locking/mutex: Restructure wait loop

Doesn't really matter yet, but pull the HANDOFF and trylock out from
under the wait_lock.

The intention is to add an optimistic spin loop here, which requires
we do not hold the wait_lock, so shuffle code around in preparation.

Also clarify the purpose of taking the wait_lock in the wait loop, its
tempting to want to avoid it altogether, but the cancellation cases
need to to avoid losing wakeups.

Suggested-by: Waiman Long <waiman.long@hpe.com>
Tested-by: Jason Low <jason.low2@hpe.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Peter Zijlstra and committed by
Ingo Molnar
5bbd7e64 9d659ae1

+25 -5
+25 -5
kernel/locking/mutex.c
··· 631 631 632 632 lock_contended(&lock->dep_map, ip); 633 633 634 + set_task_state(task, state); 634 635 for (;;) { 636 + /* 637 + * Once we hold wait_lock, we're serialized against 638 + * mutex_unlock() handing the lock off to us, do a trylock 639 + * before testing the error conditions to make sure we pick up 640 + * the handoff. 641 + */ 635 642 if (__mutex_trylock(lock, first)) 636 - break; 643 + goto acquired; 637 644 638 645 /* 639 - * got a signal? (This code gets eliminated in the 640 - * TASK_UNINTERRUPTIBLE case.) 646 + * Check for signals and wound conditions while holding 647 + * wait_lock. This ensures the lock cancellation is ordered 648 + * against mutex_unlock() and wake-ups do not go missing. 641 649 */ 642 650 if (unlikely(signal_pending_state(state, task))) { 643 651 ret = -EINTR; ··· 658 650 goto err; 659 651 } 660 652 661 - __set_task_state(task, state); 662 653 spin_unlock_mutex(&lock->wait_lock, flags); 663 654 schedule_preempt_disabled(); 664 - spin_lock_mutex(&lock->wait_lock, flags); 665 655 666 656 if (!first && __mutex_waiter_is_first(lock, &waiter)) { 667 657 first = true; 668 658 __mutex_set_flag(lock, MUTEX_FLAG_HANDOFF); 669 659 } 660 + 661 + set_task_state(task, state); 662 + /* 663 + * Here we order against unlock; we must either see it change 664 + * state back to RUNNING and fall through the next schedule(), 665 + * or we must see its unlock and acquire. 666 + */ 667 + if (__mutex_trylock(lock, first)) 668 + break; 669 + 670 + spin_lock_mutex(&lock->wait_lock, flags); 670 671 } 672 + spin_lock_mutex(&lock->wait_lock, flags); 673 + acquired: 671 674 __set_task_state(task, TASK_RUNNING); 672 675 673 676 mutex_remove_waiter(lock, &waiter, task); ··· 701 682 return 0; 702 683 703 684 err: 685 + __set_task_state(task, TASK_RUNNING); 704 686 mutex_remove_waiter(lock, &waiter, task); 705 687 spin_unlock_mutex(&lock->wait_lock, flags); 706 688 debug_mutex_free_waiter(&waiter);