From: "Nicolai Hähnle" <nhaehnle@gmail.com>
To: linux-kernel@vger.kernel.org
Cc: "Nicolai Hähnle" <Nicolai.Haehnle@amd.com>,
"Peter Zijlstra" <peterz@infradead.org>,
"Ingo Molnar" <mingo@redhat.com>,
"Maarten Lankhorst" <dev@mblankhorst.nl>,
"Daniel Vetter" <daniel@ffwll.ch>,
"Chris Wilson" <chris@chris-wilson.co.uk>,
dri-devel@lists.freedesktop.org
Subject: [PATCH 05/11] locking/ww_mutex: Add waiters in stamp order
Date: Mon, 28 Nov 2016 13:20:06 +0100 [thread overview]
Message-ID: <1480335612-12069-6-git-send-email-nhaehnle@gmail.com> (raw)
In-Reply-To: <1480335612-12069-1-git-send-email-nhaehnle@gmail.com>
From: Nicolai Hähnle <Nicolai.Haehnle@amd.com>
Add regular waiters in stamp order. Keep adding waiters that have no
context in FIFO order and take care not to starve them.
While adding our task as a waiter, back off if we detect that there is a
waiter with a lower stamp in front of us.
Make sure to call lock_contended even when we back off early.
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Maarten Lankhorst <dev@mblankhorst.nl>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: dri-devel@lists.freedesktop.org
Signed-off-by: Nicolai Hähnle <Nicolai.Haehnle@amd.com>
---
include/linux/mutex.h | 3 ++
kernel/locking/mutex.c | 76 +++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 72 insertions(+), 7 deletions(-)
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index b97870f..118a3b6 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -20,6 +20,8 @@
#include <linux/osq_lock.h>
#include <linux/debug_locks.h>
+struct ww_acquire_ctx;
+
/*
* Simple, straightforward mutexes with strict semantics:
*
@@ -75,6 +77,7 @@ static inline struct task_struct *__mutex_owner(struct mutex *lock)
struct mutex_waiter {
struct list_head list;
struct task_struct *task;
+ struct ww_acquire_ctx *ww_ctx;
#ifdef CONFIG_DEBUG_MUTEXES
void *magic;
#endif
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index 585627f..01dcae7 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -628,6 +628,40 @@ __ww_mutex_lock_check_stamp(struct mutex *lock, struct ww_acquire_ctx *ctx)
return 0;
}
+static inline int __sched
+__ww_mutex_add_waiter(struct mutex_waiter *waiter,
+ struct mutex *lock,
+ struct ww_acquire_ctx *ww_ctx)
+{
+ if (ww_ctx) {
+ struct mutex_waiter *cur;
+
+ /*
+ * Add the waiter before the first waiter with a higher stamp.
+ * Waiters without a context are skipped to avoid starving
+ * them.
+ */
+ list_for_each_entry(cur, &lock->wait_list, list) {
+ if (!cur->ww_ctx)
+ continue;
+
+ if (__ww_mutex_stamp_after(ww_ctx, cur->ww_ctx)) {
+ /* Back off immediately if necessary. */
+ if (ww_ctx->acquired > 0)
+ return -EDEADLK;
+
+ continue;
+ }
+
+ list_add_tail(&waiter->list, &cur->list);
+ return 0;
+ }
+ }
+
+ list_add_tail(&waiter->list, &lock->wait_list);
+ return 0;
+}
+
/*
* Lock a mutex (possibly interruptible), slowpath:
*/
@@ -677,15 +711,25 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
debug_mutex_lock_common(lock, &waiter);
debug_mutex_add_waiter(lock, &waiter, task);
- /* add waiting tasks to the end of the waitqueue (FIFO): */
- list_add_tail(&waiter.list, &lock->wait_list);
+ lock_contended(&lock->dep_map, ip);
+
+ if (!use_ww_ctx) {
+ /* add waiting tasks to the end of the waitqueue (FIFO): */
+ list_add_tail(&waiter.list, &lock->wait_list);
+ } else {
+ /* Add in stamp order, waking up waiters that must back off. */
+ ret = __ww_mutex_add_waiter(&waiter, lock, ww_ctx);
+ if (ret)
+ goto err_early_backoff;
+
+ waiter.ww_ctx = ww_ctx;
+ }
+
waiter.task = task;
if (__mutex_waiter_is_first(lock, &waiter))
__mutex_set_flag(lock, MUTEX_FLAG_WAITERS);
- lock_contended(&lock->dep_map, ip);
-
set_task_state(task, state);
for (;;) {
/*
@@ -693,8 +737,12 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
* mutex_unlock() handing the lock off to us, do a trylock
* before testing the error conditions to make sure we pick up
* the handoff.
+ *
+ * For w/w locks, we always need to do this even if we're not
+ * currently the first waiter, because we may have been the
+ * first waiter during the unlock.
*/
- if (__mutex_trylock(lock, first))
+ if (__mutex_trylock(lock, use_ww_ctx || first))
goto acquired;
/*
@@ -716,7 +764,20 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
spin_unlock_mutex(&lock->wait_lock, flags);
schedule_preempt_disabled();
- if (!first && __mutex_waiter_is_first(lock, &waiter)) {
+ if (use_ww_ctx && ww_ctx) {
+ /*
+ * Always re-check whether we're in first position. We
+ * don't want to spin if another task with a lower
+ * stamp has taken our position.
+ *
+ * We also may have to set the handoff flag again, if
+ * our position at the head was temporarily taken away.
+ */
+ first = __mutex_waiter_is_first(lock, &waiter);
+
+ if (first)
+ __mutex_set_flag(lock, MUTEX_FLAG_HANDOFF);
+ } else if (!first && __mutex_waiter_is_first(lock, &waiter)) {
first = true;
__mutex_set_flag(lock, MUTEX_FLAG_HANDOFF);
}
@@ -728,7 +789,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
* or we must see its unlock and acquire.
*/
if ((first && mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, true)) ||
- __mutex_trylock(lock, first))
+ __mutex_trylock(lock, use_ww_ctx || first))
break;
spin_lock_mutex(&lock->wait_lock, flags);
@@ -761,6 +822,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
err:
__set_task_state(task, TASK_RUNNING);
mutex_remove_waiter(lock, &waiter, task);
+err_early_backoff:
spin_unlock_mutex(&lock->wait_lock, flags);
debug_mutex_free_waiter(&waiter);
mutex_release(&lock->dep_map, 1, ip);
--
2.7.4
next prev parent reply other threads:[~2016-11-28 12:20 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-11-28 12:20 [PATCH 00/11] locking/ww_mutex: Keep sorted wait list to avoid stampedes Nicolai Hähnle
2016-11-28 12:20 ` [PATCH 01/11] drm/vgem: Use ww_mutex_(un)lock even with a NULL context Nicolai Hähnle
2016-11-28 12:42 ` Maarten Lankhorst
2016-11-28 12:50 ` Peter Zijlstra
2016-11-28 12:58 ` Christian König
2016-11-28 12:20 ` [PATCH 02/11] locking/ww_mutex: Re-check ww->ctx in the inner optimistic spin loop Nicolai Hähnle
2016-11-28 12:20 ` [PATCH 03/11] locking/ww_mutex: Extract stamp comparison to __ww_mutex_stamp_after Nicolai Hähnle
2016-11-28 12:20 ` [PATCH 04/11] locking/ww_mutex: Set use_ww_ctx even when locking without a context Nicolai Hähnle
2016-11-28 12:20 ` Nicolai Hähnle [this message]
2016-11-30 14:10 ` [PATCH 05/11] locking/ww_mutex: Add waiters in stamp order Chris Wilson
2016-11-28 12:20 ` [PATCH 06/11] locking/ww_mutex: Notify waiters that have to back off while adding tasks to wait list Nicolai Hähnle
2016-11-28 12:20 ` [PATCH 07/11] locking/ww_mutex: Wake at most one waiter for back off when acquiring the lock Nicolai Hähnle
2016-11-28 12:20 ` [PATCH 08/11] locking/ww_mutex: Yield to other waiters from optimistic spin Nicolai Hähnle
2016-11-28 12:20 ` [PATCH 09/11] locking/mutex: Initialize mutex_waiter::ww_ctx with poison when debugging Nicolai Hähnle
2016-11-28 12:20 ` [PATCH 10/11] Documentation/locking/ww_mutex: Update the design document Nicolai Hähnle
2016-11-28 12:20 ` [PATCH 11/11] [rfc] locking/ww_mutex: Always spin optimistically for the first waiter Nicolai Hähnle
2016-11-30 0:35 ` [PATCH 1/4] locking: Begin kselftests for ww_mutex Chris Wilson
2016-11-30 0:35 ` [PATCH 2/4] locking: Add kselftests for ww_mutex AA deadlock detection Chris Wilson
2016-11-30 0:35 ` [PATCH 3/4] locking: Add kselftests for ww_mutex ABBA " Chris Wilson
2016-11-30 0:35 ` [PATCH 4/4] locking: Add kselftests for ww_mutex stress Chris Wilson
2016-11-30 12:29 ` Maarten Lankhorst
2016-11-30 12:52 ` Chris Wilson
2016-11-30 8:00 ` [PATCH 1/4] locking: Begin kselftests for ww_mutex Nicolai Hähnle
2016-11-30 19:08 ` kbuild test robot
2016-11-30 9:40 ` [PATCH 00/11] locking/ww_mutex: Keep sorted wait list to avoid stampedes Chris Wilson
2016-11-30 11:52 ` Nicolai Hähnle
2016-11-30 12:20 ` Chris Wilson
2016-11-30 13:40 ` Nicolai Hähnle
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1480335612-12069-6-git-send-email-nhaehnle@gmail.com \
--to=nhaehnle@gmail.com \
--cc=Nicolai.Haehnle@amd.com \
--cc=chris@chris-wilson.co.uk \
--cc=daniel@ffwll.ch \
--cc=dev@mblankhorst.nl \
--cc=dri-devel@lists.freedesktop.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®