History

locking/mutex: Enable optimistic spinning of woken waiter

This patch makes the waiter that sets the HANDOFF flag start spinning instead of sleeping until the handoff is complete or the owner sleeps. Otherwise, the handoff will cause the optimistic spinners to abort spinning as the handed-off owner may not be running.

Waiman Long committed 10 years ago

Commit b341afb1 parent a40ca561 file · +54 −23Browse files

Showing the changes to kernel/locking (1 of 1 file). Show all

Unified · Split

kernel/locking/mutex.c+54−23
@@ -416,24 +416,39 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock) · 415 unmodified lines
416 *416 *
417 * Returns true when the lock was taken, otherwise false, indicating417 * Returns true when the lock was taken, otherwise false, indicating
418 * that we need to jump to the slowpath and sleep.418 * that we need to jump to the slowpath and sleep.
419 *
420 * The waiter flag is set to true if the spinner is a waiter in the wait
421 * queue. The waiter-spinner will spin on the lock directly and concurrently
422 * with the spinner at the head of the OSQ, if present, until the owner is
423 * changed to itself.
419 */424 */
420static bool mutex_optimistic_spin(struct mutex *lock,425static bool mutex_optimistic_spin(struct mutex *lock,
421 struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx)426 struct ww_acquire_ctx *ww_ctx,
427 const bool use_ww_ctx, const bool waiter)
422{428{
423 struct task_struct *task = current;429 struct task_struct *task = current;
424 430
425 if (!mutex_can_spin_on_owner(lock))431 if (!waiter) {
426 goto done;432 /*
433 * The purpose of the mutex_can_spin_on_owner() function is
434 * to eliminate the overhead of osq_lock() and osq_unlock()
435 * in case spinning isn't possible. As a waiter-spinner
436 * is not going to take OSQ lock anyway, there is no need
437 * to call mutex_can_spin_on_owner().
438 */
439 if (!mutex_can_spin_on_owner(lock))
440 goto fail;
427 441
428 /*442 /*
429 * In order to avoid a stampede of mutex spinners trying to443 * In order to avoid a stampede of mutex spinners trying to
430 * acquire the mutex all at once, the spinners need to take a444 * acquire the mutex all at once, the spinners need to take a
431 * MCS (queued) lock first before spinning on the owner field.445 * MCS (queued) lock first before spinning on the owner field.
432 */446 */
433 if (!osq_lock(&lock->osq))447 if (!osq_lock(&lock->osq))
434 goto done;448 goto fail;
449 }
435 450
436 while (true) {451 for (;;) {
437 struct task_struct *owner;452 struct task_struct *owner;
438 453
439 if (use_ww_ctx && ww_ctx->acquired > 0) {454 if (use_ww_ctx && ww_ctx->acquired > 0) {
@@ -449,7 +464,7 @@ static bool mutex_optimistic_spin(struct mutex *lock, · 9 unmodified lines
449 * performed the optimistic spinning cannot be done.464 * performed the optimistic spinning cannot be done.
450 */465 */
451 if (READ_ONCE(ww->ctx))466 if (READ_ONCE(ww->ctx))
452 break;467 goto fail_unlock;
453 }468 }
454 469
455 /*470 /*
@@ -457,15 +472,20 @@ static bool mutex_optimistic_spin(struct mutex *lock, · 1 unmodified line
457 * release the lock or go to sleep.472 * release the lock or go to sleep.
458 */473 */
459 owner = __mutex_owner(lock);474 owner = __mutex_owner(lock);
460 if (owner && !mutex_spin_on_owner(lock, owner))475 if (owner) {
461 break;476 if (waiter && owner == task) {
477 smp_mb(); /* ACQUIRE */
478 break;
479 }
462 480
463 /* Try to acquire the mutex if it is unlocked. */481 if (!mutex_spin_on_owner(lock, owner))
464 if (__mutex_trylock(lock, false)) {482 goto fail_unlock;
465 osq_unlock(&lock->osq);
466 return true;
467 }483 }
468 484
485 /* Try to acquire the mutex if it is unlocked. */
486 if (__mutex_trylock(lock, waiter))
487 break;
488
469 /*489 /*
470 * The cpu_relax() call is a compiler barrier which forces490 * The cpu_relax() call is a compiler barrier which forces
471 * everything in this loop to be re-loaded. We don't need491 * everything in this loop to be re-loaded. We don't need
@@ -475,8 +495,17 @@ static bool mutex_optimistic_spin(struct mutex *lock, · 3 unmodified lines
475 cpu_relax_lowlatency();495 cpu_relax_lowlatency();
476 }496 }
477 497
478 osq_unlock(&lock->osq);498 if (!waiter)
479done:499 osq_unlock(&lock->osq);
500
501 return true;
502
503
504fail_unlock:
505 if (!waiter)
506 osq_unlock(&lock->osq);
507
508fail:
480 /*509 /*
481 * If we fell out of the spin path because of need_resched(),510 * If we fell out of the spin path because of need_resched(),
482 * reschedule now, before we try-lock the mutex. This avoids getting511 * reschedule now, before we try-lock the mutex. This avoids getting
@@ -495,7 +524,8 @@ done: · 12 unmodified lines
495}524}
496#else525#else
497static bool mutex_optimistic_spin(struct mutex *lock,526static bool mutex_optimistic_spin(struct mutex *lock,
498 struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx)527 struct ww_acquire_ctx *ww_ctx,
528 const bool use_ww_ctx, const bool waiter)
499{529{
500 return false;530 return false;
501}531}
@@ -600,7 +630,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, · 98 unmodified lines
600 mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip);630 mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip);
601 631
602 if (__mutex_trylock(lock, false) ||632 if (__mutex_trylock(lock, false) ||
603 mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx)) {633 mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, false)) {
604 /* got the lock, yay! */634 /* got the lock, yay! */
605 lock_acquired(&lock->dep_map, ip);635 lock_acquired(&lock->dep_map, ip);
606 if (use_ww_ctx)636 if (use_ww_ctx)
@@ -669,7 +699,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, · 62 unmodified lines
669 * state back to RUNNING and fall through the next schedule(),699 * state back to RUNNING and fall through the next schedule(),
670 * or we must see its unlock and acquire.700 * or we must see its unlock and acquire.
671 */701 */
672 if (__mutex_trylock(lock, first))702 if ((first && mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, true)) ||
703 __mutex_trylock(lock, first))
673 break;704 break;
674 705
675 spin_lock_mutex(&lock->wait_lock, flags);706 spin_lock_mutex(&lock->wait_lock, flags);