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 Linux `kthread' abst...
details: https://anonhg.NetBSD.org/src/rev/2cf6d5e113e8
branches: trunk
changeset: 1029008:2cf6d5e113e8
user: riastradh <riastradh%NetBSD.org@localhost>
date: Sun Dec 19 12:42:25 2021 +0000
description:
drm: Rework Linux `kthread' abstraction to avoid race to sleep.
Requires passing in the caller's lock and condvar to kthread_run, but
for the one user that appears not to be an onerous requirement.
diffstat:
sys/external/bsd/drm2/dist/drm/scheduler/sched_main.c | 7 +-
sys/external/bsd/drm2/include/linux/kthread.h | 9 +-
sys/external/bsd/drm2/linux/linux_kthread.c | 102 ++++++++---------
3 files changed, 57 insertions(+), 61 deletions(-)
diffs (254 lines):
diff -r b5414a7107ab -r 2cf6d5e113e8 sys/external/bsd/drm2/dist/drm/scheduler/sched_main.c
--- a/sys/external/bsd/drm2/dist/drm/scheduler/sched_main.c Sun Dec 19 12:42:14 2021 +0000
+++ b/sys/external/bsd/drm2/dist/drm/scheduler/sched_main.c Sun Dec 19 12:42:25 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sched_main.c,v 1.7 2021/12/19 12:41:44 riastradh Exp $ */
+/* $NetBSD: sched_main.c,v 1.8 2021/12/19 12:42:25 riastradh Exp $ */
/*
* Copyright 2015 Advanced Micro Devices, Inc.
@@ -47,7 +47,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sched_main.c,v 1.7 2021/12/19 12:41:44 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sched_main.c,v 1.8 2021/12/19 12:42:25 riastradh Exp $");
#include <linux/kthread.h>
#include <linux/wait.h>
@@ -857,7 +857,8 @@
atomic64_set(&sched->job_id_count, 0);
/* Each scheduler will run on a seperate kernel thread */
- sched->thread = kthread_run(drm_sched_main, sched, sched->name);
+ sched->thread = kthread_run(drm_sched_main, sched, sched->name,
+ &sched->job_list_lock, &sched->wake_up_worker);
if (IS_ERR(sched->thread)) {
ret = PTR_ERR(sched->thread);
sched->thread = NULL;
diff -r b5414a7107ab -r 2cf6d5e113e8 sys/external/bsd/drm2/include/linux/kthread.h
--- a/sys/external/bsd/drm2/include/linux/kthread.h Sun Dec 19 12:42:14 2021 +0000
+++ b/sys/external/bsd/drm2/include/linux/kthread.h Sun Dec 19 12:42:25 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: kthread.h,v 1.3 2021/12/19 12:23:07 riastradh Exp $ */
+/* $NetBSD: kthread.h,v 1.4 2021/12/19 12:42:25 riastradh Exp $ */
/*-
* Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -32,6 +32,10 @@
#ifndef _LINUX_KTHREAD_H_
#define _LINUX_KTHREAD_H_
+#include <linux/spinlock.h>
+
+#include <drm/drm_wait_netbsd.h>
+
struct task_struct;
#define __kthread_should_park linux___kthread_should_park
@@ -43,7 +47,8 @@
#define kthread_stop linux_kthread_stop
#define kthread_unpark linux_kthread_unpark
-struct task_struct *kthread_run(int (*)(void *), void *, const char *);
+struct task_struct *kthread_run(int (*)(void *), void *, const char *,
+ spinlock_t *, drm_waitqueue_t *);
int kthread_stop(struct task_struct *);
int kthread_should_stop(void);
diff -r b5414a7107ab -r 2cf6d5e113e8 sys/external/bsd/drm2/linux/linux_kthread.c
--- a/sys/external/bsd/drm2/linux/linux_kthread.c Sun Dec 19 12:42:14 2021 +0000
+++ b/sys/external/bsd/drm2/linux/linux_kthread.c Sun Dec 19 12:42:25 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: linux_kthread.c,v 1.5 2021/12/19 12:42:14 riastradh Exp $ */
+/* $NetBSD: linux_kthread.c,v 1.6 2021/12/19 12:42:25 riastradh Exp $ */
/*-
* Copyright (c) 2021 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_kthread.c,v 1.5 2021/12/19 12:42:14 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_kthread.c,v 1.6 2021/12/19 12:42:25 riastradh Exp $");
#include <sys/types.h>
@@ -42,6 +42,9 @@
#include <sys/specificdata.h>
#include <linux/kthread.h>
+#include <linux/spinlock.h>
+
+#include <drm/drm_wait_netbsd.h>
struct task_struct {
kmutex_t kt_lock;
@@ -52,6 +55,8 @@
int (*kt_func)(void *);
void *kt_cookie;
+ spinlock_t *kt_interlock;
+ drm_waitqueue_t *kt_wq;
struct lwp *kt_lwp;
};
@@ -109,7 +114,8 @@
}
static struct task_struct *
-kthread_alloc(int (*func)(void *), void *cookie)
+kthread_alloc(int (*func)(void *), void *cookie, spinlock_t *interlock,
+ drm_waitqueue_t *wq)
{
struct task_struct *T;
@@ -120,6 +126,8 @@
T->kt_func = func;
T->kt_cookie = cookie;
+ T->kt_interlock = interlock;
+ T->kt_wq = wq;
return T;
}
@@ -134,12 +142,13 @@
}
struct task_struct *
-kthread_run(int (*func)(void *), void *cookie, const char *name)
+kthread_run(int (*func)(void *), void *cookie, const char *name,
+ spinlock_t *interlock, drm_waitqueue_t *wq)
{
struct task_struct *T;
int error;
- T = kthread_alloc(func, cookie);
+ T = kthread_alloc(func, cookie, interlock, wq);
error = kthread_create(PRI_NONE, KTHREAD_MPSAFE|KTHREAD_MUSTJOIN, NULL,
linux_kthread_start, T, &T->kt_lwp, "%s", name);
if (error) {
@@ -150,59 +159,35 @@
return T;
}
-/*
- * lwp_kick(l)
- *
- * Cause l to wake up if it is asleep, no matter what condvar or
- * other wchan it's asleep on. This logic is like sleepq_timeout,
- * but without setting LW_STIMO. This is not a general-purpose
- * mechanism -- don't go around using this instead of condvars.
- */
-static void
-lwp_kick(struct lwp *l)
-{
-
- lwp_lock(l);
- if (l->l_wchan == NULL) {
- /* Not sleeping, so no need to wake up. */
- lwp_unlock(l);
- } else {
- /*
- * Sleeping, so wake it up. lwp_unsleep has the side
- * effect of unlocking l when we pass unlock=true.
- */
- lwp_unsleep(l, /*unlock*/true);
- }
-}
-
int
kthread_stop(struct task_struct *T)
{
- struct lwp *l;
int ret;
+ /* Lock order: interlock, then kthread lock. */
+ spin_lock(T->kt_interlock);
+ mutex_enter(&T->kt_lock);
+
/*
* Notify the thread that it's stopping, and wake it if it's
- * parked.
+ * parked or sleeping on its own waitqueue.
*/
- mutex_enter(&T->kt_lock);
T->kt_shouldpark = false;
T->kt_shouldstop = true;
cv_broadcast(&T->kt_cv);
- mutex_exit(&T->kt_lock);
+ DRM_SPIN_WAKEUP_ALL(T->kt_wq, T->kt_interlock);
- /*
- * Kick the lwp in case it's waiting on anything else, and then
- * wait for it to complete. It is the thread's obligation to
- * check kthread_shouldstop before sleeping again.
- */
- l = T->kt_lwp;
- KASSERT(l != curlwp);
- lwp_kick(l);
- ret = kthread_join(l);
+ /* Release the locks. */
+ mutex_exit(&T->kt_lock);
+ spin_unlock(T->kt_interlock);
+ /* Wait for the (NetBSD) kthread to exit. */
+ ret = kthread_join(T->kt_lwp);
+
+ /* Free the (Linux) kthread. */
kthread_free(T);
+ /* Return what the thread returned. */
return ret;
}
@@ -222,8 +207,9 @@
void
kthread_park(struct task_struct *T)
{
- struct lwp *l;
+ /* Lock order: interlock, then kthread lock. */
+ spin_lock(T->kt_interlock);
mutex_enter(&T->kt_lock);
/* Caller must not ask to park if they've already asked to stop. */
@@ -232,22 +218,26 @@
/* Ask the thread to park. */
T->kt_shouldpark = true;
- /* Don't wait for ourselves -- Linux allows this semantics. */
- if ((l = T->kt_lwp) == curlwp)
- goto out;
+ /*
+ * Ensure the thread is not sleeping on its condvar. After
+ * this point, we are done with the interlock, which we must
+ * not hold while we wait on the kthread condvar.
+ */
+ DRM_SPIN_WAKEUP_ALL(T->kt_wq, T->kt_interlock);
+ spin_unlock(T->kt_interlock);
/*
- * If the thread is asleep for any reason, give it a spurious
- * wakeup. The thread is responsible for checking
- * kthread_shouldpark before sleeping.
+ * Wait until the thread has issued kthread_parkme, unless we
+ * are already the thread, which Linux allows and interprets to
+ * mean don't wait.
*/
- lwp_kick(l);
+ if (T->kt_lwp != curlwp) {
+ while (!T->kt_parked)
+ cv_wait(&T->kt_cv, &T->kt_lock);
+ }
- /* Wait until the thread has issued kthread_parkme. */
- while (!T->kt_parked)
- cv_wait(&T->kt_cv, &T->kt_lock);
-
-out: mutex_exit(&T->kt_lock);
+ /* Release the kthread lock too. */
+ mutex_exit(&T->kt_lock);
}
void
Home |
Main Index |
Thread Index |
Old Index