summaryrefslogtreecommitdiff
path: root/sys/kern/kern_umtx.c
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2015-01-31 12:27:40 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2015-01-31 12:27:40 +0000
commit6690381ef14fbc2167446b57941e0d824e7e4cca (patch)
tree80faa7ffd2d70487fb7a8024a56066ebeb74c55b /sys/kern/kern_umtx.c
parent311d39f2ee3dc301317d175b7d3b0dfd8b7e91ae (diff)
downloadsrc-test2-6690381ef14fbc2167446b57941e0d824e7e4cca.tar.gz
src-test2-6690381ef14fbc2167446b57941e0d824e7e4cca.zip
Notes
Diffstat (limited to 'sys/kern/kern_umtx.c')
-rw-r--r--sys/kern/kern_umtx.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c
index 5b42c6fd118a..317e05bfb57a 100644
--- a/sys/kern/kern_umtx.c
+++ b/sys/kern/kern_umtx.c
@@ -1302,6 +1302,47 @@ umtx_pi_adjust_thread(struct umtx_pi *pi, struct thread *td)
return (1);
}
+static struct umtx_pi *
+umtx_pi_next(struct umtx_pi *pi)
+{
+ struct umtx_q *uq_owner;
+
+ if (pi->pi_owner == NULL)
+ return (NULL);
+ uq_owner = pi->pi_owner->td_umtxq;
+ if (uq_owner == NULL)
+ return (NULL);
+ return (uq_owner->uq_pi_blocked);
+}
+
+/*
+ * Floyd's Cycle-Finding Algorithm.
+ */
+static bool
+umtx_pi_check_loop(struct umtx_pi *pi)
+{
+ struct umtx_pi *pi1; /* fast iterator */
+
+ mtx_assert(&umtx_lock, MA_OWNED);
+ if (pi == NULL)
+ return (false);
+ pi1 = pi;
+ for (;;) {
+ pi = umtx_pi_next(pi);
+ if (pi == NULL)
+ break;
+ pi1 = umtx_pi_next(pi1);
+ if (pi1 == NULL)
+ break;
+ pi1 = umtx_pi_next(pi1);
+ if (pi1 == NULL)
+ break;
+ if (pi == pi1)
+ return (true);
+ }
+ return (false);
+}
+
/*
* Propagate priority when a thread is blocked on POSIX
* PI mutex.
@@ -1319,6 +1360,8 @@ umtx_propagate_priority(struct thread *td)
pi = uq->uq_pi_blocked;
if (pi == NULL)
return;
+ if (umtx_pi_check_loop(pi))
+ return;
for (;;) {
td = pi->pi_owner;
@@ -1362,6 +1405,8 @@ umtx_repropagate_priority(struct umtx_pi *pi)
mtx_assert(&umtx_lock, MA_OWNED);
+ if (umtx_pi_check_loop(pi))
+ return;
while (pi != NULL && pi->pi_owner != NULL) {
pri = PRI_MAX;
uq_owner = pi->pi_owner->td_umtxq;
@@ -1694,6 +1739,11 @@ do_lock_pi(struct thread *td, struct umutex *m, uint32_t flags,
continue;
}
+ if ((owner & ~UMUTEX_CONTESTED) == id) {
+ error = EDEADLK;
+ break;
+ }
+
if (try != 0) {
error = EBUSY;
break;