Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/external/bsd/drm2/linux drm: Rework timeout return code ...
details: https://anonhg.NetBSD.org/src/rev/122b8b2a450a
branches: trunk
changeset: 1028953:122b8b2a450a
user: riastradh <riastradh%NetBSD.org@localhost>
date: Sun Dec 19 12:34:16 2021 +0000
description:
drm: Rework timeout return code logic.
diffstat:
sys/external/bsd/drm2/linux/linux_dma_fence.c | 144 +++++++++++++++----------
1 files changed, 86 insertions(+), 58 deletions(-)
diffs (264 lines):
diff -r 12941098fe0e -r 122b8b2a450a sys/external/bsd/drm2/linux/linux_dma_fence.c
--- a/sys/external/bsd/drm2/linux/linux_dma_fence.c Sun Dec 19 12:34:05 2021 +0000
+++ b/sys/external/bsd/drm2/linux/linux_dma_fence.c Sun Dec 19 12:34:16 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: linux_dma_fence.c,v 1.31 2021/12/19 12:34:05 riastradh Exp $ */
+/* $NetBSD: linux_dma_fence.c,v 1.32 2021/12/19 12:34:16 riastradh Exp $ */
/*-
* Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_dma_fence.c,v 1.31 2021/12/19 12:34:05 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_dma_fence.c,v 1.32 2021/12/19 12:34:16 riastradh Exp $");
#include <sys/atomic.h>
#include <sys/condvar.h>
@@ -723,8 +723,12 @@
int start, end;
long ret = 0;
+ KASSERTMSG(timeout >= 0, "timeout %ld", timeout);
+ KASSERTMSG(timeout <= MAX_SCHEDULE_TIMEOUT, "timeout %ld", timeout);
+
/* Optimistically check whether any are signalled. */
for (i = 0; i < nfences; i++) {
+ KASSERT(dma_fence_referenced_p(fences[i]));
if (dma_fence_is_signaled(fences[i])) {
if (ip)
*ip = i;
@@ -741,10 +745,8 @@
/* Allocate an array of callback records. */
cb = kcalloc(nfences, sizeof(cb[0]), GFP_KERNEL);
- if (cb == NULL) {
- ret = -ENOMEM;
- goto out0;
- }
+ if (cb == NULL)
+ return -ENOMEM;
/* Initialize a mutex and condvar for the common wait. */
mutex_init(&common.lock, MUTEX_DEFAULT, IPL_VM);
@@ -766,7 +768,7 @@
if (ip)
*ip = i;
ret = MAX(1, timeout);
- goto out1;
+ goto out;
}
}
@@ -775,7 +777,8 @@
* callbacks to notify us when it is done.
*/
mutex_enter(&common.lock);
- while (timeout > 0 && !common.done) {
+ while (!common.done) {
+ /* Wait for the time remaining. */
start = getticks();
if (intr) {
if (timeout != MAX_SCHEDULE_TIMEOUT) {
@@ -796,13 +799,42 @@
}
}
end = getticks();
+
+ /* Deduct from time remaining. If none left, time out. */
+ if (timeout != MAX_SCHEDULE_TIMEOUT) {
+ timeout -= MIN(timeout,
+ (unsigned)end - (unsigned)start);
+ if (timeout == 0)
+ ret = -EWOULDBLOCK;
+ }
+
+ /* If the wait failed, give up. */
if (ret)
break;
- timeout -= MIN(timeout, (unsigned)end - (unsigned)start);
}
mutex_exit(&common.lock);
/*
+ * Massage the return code if nonzero:
+ * - if we were interrupted, return -ERESTARTSYS;
+ * - if we timed out, return 0.
+ * No other failure is possible. On success, ret=0 but we
+ * check again below to verify anyway.
+ */
+ if (ret) {
+ KASSERTMSG((ret == -EINTR || ret == -ERESTART ||
+ ret == -EWOULDBLOCK), "ret=%ld", ret);
+ if (ret == -EINTR || ret == -ERESTART) {
+ ret = -ERESTARTSYS;
+ } else if (ret == -EWOULDBLOCK) {
+ KASSERT(timeout != MAX_SCHEDULE_TIMEOUT);
+ ret = 0; /* timed out */
+ }
+ }
+
+ KASSERT(ret != -ERESTART); /* would be confused with time left */
+
+ /*
* Test whether any of the fences has been signalled. If they
* have, return success.
*/
@@ -811,28 +843,22 @@
if (ip)
*ip = j;
ret = MAX(1, timeout);
- goto out1;
+ goto out;
}
}
/*
- * Massage the return code: if we were interrupted, return
- * ERESTARTSYS; if cv_timedwait timed out, return 0; otherwise
- * return the remaining time.
+ * If user passed MAX_SCHEDULE_TIMEOUT, we can't return 0
+ * meaning timed out because we're supposed to wait forever.
*/
- if (ret == -EINTR || ret == -ERESTART) {
- ret = -ERESTARTSYS;
- } else if (ret == -EWOULDBLOCK) {
- ret = 0; /* timed out */
- }
- KASSERTMSG(ret == -ERESTARTSYS || ret >= 0, "ret=%ld", ret);
+ KASSERT(timeout == MAX_SCHEDULE_TIMEOUT ? ret != 0 : 1);
-out1: while (i --> 0)
+out: while (i --> 0)
(void)dma_fence_remove_callback(fences[i], &cb[i].fcb);
cv_destroy(&common.cv);
mutex_destroy(&common.lock);
kfree(cb);
-out0: return ret;
+ return ret;
}
/*
@@ -911,27 +937,26 @@
/* Optimistically try to skip the lock if it's already signalled. */
if (fence->flags & (1u << DMA_FENCE_FLAG_SIGNALED_BIT))
- return (timeout ? timeout : 1);
+ return MAX(1, timeout);
/* Acquire the lock. */
spin_lock(fence->lock);
/* Ensure signalling is enabled, or stop if already completed. */
if (dma_fence_ensure_signal_enabled(fence) != 0) {
- spin_unlock(fence->lock);
- return (timeout ? timeout : 1);
+ ret = MAX(1, timeout);
+ goto out;
}
/* If merely polling, stop here. */
if (timeout == 0) {
- spin_unlock(fence->lock);
- return 0;
+ ret = 0;
+ goto out;
}
/* Find out what our deadline is so we can handle spurious wakeup. */
if (timeout < MAX_SCHEDULE_TIMEOUT) {
now = getticks();
- __insn_barrier();
starttime = now;
deadline = starttime + timeout;
}
@@ -944,10 +969,13 @@
*/
if (timeout < MAX_SCHEDULE_TIMEOUT) {
now = getticks();
- __insn_barrier();
- if (deadline <= now)
+ if (deadline <= now) {
+ ret = -EWOULDBLOCK;
break;
+ }
}
+
+ /* Wait for the time remaining. */
if (intr) {
if (timeout < MAX_SCHEDULE_TIMEOUT) {
ret = -cv_timedwait_sig(&fence->f_cv, lock,
@@ -964,43 +992,43 @@
ret = 0;
}
}
+
/* If the wait failed, give up. */
- if (ret) {
- if (ret == -ERESTART)
- ret = -ERESTARTSYS;
+ if (ret)
break;
+ }
+
+ /*
+ * Massage the return code if nonzero:
+ * - if we were interrupted, return -ERESTARTSYS;
+ * - if we timed out, return 0.
+ * No other failure is possible. On success, ret=0 but we
+ * check again below to verify anyway.
+ */
+ if (ret) {
+ KASSERTMSG((ret == -EINTR || ret == -ERESTART ||
+ ret == -EWOULDBLOCK), "ret=%ld", ret);
+ if (ret == -EINTR || ret == -ERESTART) {
+ ret = -ERESTARTSYS;
+ } else if (ret == -EWOULDBLOCK) {
+ KASSERT(timeout < MAX_SCHEDULE_TIMEOUT);
+ ret = 0; /* timed out */
}
}
- /* All done. Release the lock. */
- spin_unlock(fence->lock);
+ KASSERT(ret != -ERESTART); /* would be confused with time left */
- /* If cv_timedwait gave up, return 0 meaning timeout. */
- if (ret == -EWOULDBLOCK) {
- /* Only cv_timedwait and cv_timedwait_sig can return this. */
- KASSERT(timeout < MAX_SCHEDULE_TIMEOUT);
- return 0;
+ /* Check again in case it was signalled after a wait. */
+ if (fence->flags & (1u << DMA_FENCE_FLAG_SIGNALED_BIT)) {
+ if (timeout < MAX_SCHEDULE_TIMEOUT)
+ ret = MAX(1, deadline - now);
+ else
+ ret = MAX_SCHEDULE_TIMEOUT;
}
- /* If there was a timeout and the deadline passed, return 0. */
- if (timeout < MAX_SCHEDULE_TIMEOUT) {
- if (deadline <= now)
- return 0;
- }
-
- /* If we were interrupted, return -ERESTARTSYS. */
- if (ret == -EINTR || ret == -ERESTART)
- return -ERESTARTSYS;
-
- /* If there was any other kind of error, fail. */
- if (ret)
- return ret;
-
- /*
- * Success! Return the number of ticks left, at least 1, or 1
- * if no timeout.
- */
- return (timeout < MAX_SCHEDULE_TIMEOUT ? MIN(deadline - now, 1) : 1);
+out: /* All done. Release the lock. */
+ spin_unlock(fence->lock);
+ return ret;
}
/*
Home |
Main Index |
Thread Index |
Old Index