Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/riastradh-drm2]: src/sys First (plausible) draft of Linux workqueue impl...
details: https://anonhg.NetBSD.org/src/rev/505070d5e9b6
branches: riastradh-drm2
changeset: 788571:505070d5e9b6
user: riastradh <riastradh%NetBSD.org@localhost>
date: Mon Dec 30 04:50:12 2013 +0000
description:
First (plausible) draft of Linux workqueue implementation rework.
Untested, but this looks better than what was there before, or any of
the drafts leading up to this which got torn out of the typewriter,
crumpled up, and crudely tossed in frustration toward the wastepaper
basket by my desk alongside the empty bottles of Jack Daniels that
fueled them, or something like that.
Can't use multiple CPUs per workqueue. That requires some explicit
management of per-CPU workqueue state, since NetBSD's workqueue(9)
doesn't provide that or cancellation or flushing. Oops.
diffstat:
sys/external/bsd/drm2/drm/drm_module.c | 15 +-
sys/external/bsd/drm2/include/linux/workqueue.h | 276 +-------
sys/external/bsd/drm2/linux/linux_work.c | 714 ++++++++++++++++++++++++
sys/modules/drm2/Makefile | 3 +-
4 files changed, 778 insertions(+), 230 deletions(-)
diffs (truncated from 1114 to 300 lines):
diff -r 44a1a5d6e71d -r 505070d5e9b6 sys/external/bsd/drm2/drm/drm_module.c
--- a/sys/external/bsd/drm2/drm/drm_module.c Sun Sep 08 16:41:07 2013 +0000
+++ b/sys/external/bsd/drm2/drm/drm_module.c Mon Dec 30 04:50:12 2013 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: drm_module.c,v 1.1.2.6 2013/09/08 15:26:24 riastradh Exp $ */
+/* $NetBSD: drm_module.c,v 1.1.2.7 2013/12/30 04:50:12 riastradh Exp $ */
/*-
* Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: drm_module.c,v 1.1.2.6 2013/09/08 15:26:24 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: drm_module.c,v 1.1.2.7 2013/12/30 04:50:12 riastradh Exp $");
#include <sys/types.h>
#include <sys/device.h>
@@ -39,6 +39,7 @@
#include <linux/highmem.h>
#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include <drm/drmP.h>
@@ -75,12 +76,20 @@
" %d", error);
return error;
}
+ error = linux_workqueue_init();
+ if (error) {
+ aprint_error("drm: unable to initialize workqueues:"
+ " %d", error);
+ linux_kmap_fini();
+ return error;
+ }
#ifdef _MODULE
error = config_init_component(cfdriver_ioconf_drm,
cfattach_ioconf_drm, cfdata_ioconf_drm);
if (error) {
aprint_error("drm: unable to init component: %d\n",
error);
+ linux_workqueue_fini();
linux_kmap_fini();
return error;
}
@@ -91,6 +100,7 @@
error);
(void)config_fini_component(cfdriver_ioconf_drm,
cfattach_ioconf_drm, cfdata_ioconf_drm);
+ linux_workqueue_fini();
linux_kmap_fini();
return error;
}
@@ -108,6 +118,7 @@
/* XXX Now what? Reattach the devsw? */
return error;
#endif
+ linux_workqueue_fini();
linux_kmap_fini();
linux_mutex_destroy(&drm_global_mutex);
return 0;
diff -r 44a1a5d6e71d -r 505070d5e9b6 sys/external/bsd/drm2/include/linux/workqueue.h
--- a/sys/external/bsd/drm2/include/linux/workqueue.h Sun Sep 08 16:41:07 2013 +0000
+++ b/sys/external/bsd/drm2/include/linux/workqueue.h Mon Dec 30 04:50:12 2013 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: workqueue.h,v 1.1.2.10 2013/09/08 16:40:36 riastradh Exp $ */
+/* $NetBSD: workqueue.h,v 1.1.2.11 2013/12/30 04:50:12 riastradh Exp $ */
/*-
* Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -32,258 +32,80 @@
#ifndef _LINUX_WORKQUEUE_H_
#define _LINUX_WORKQUEUE_H_
+#include <sys/types.h>
#include <sys/callout.h>
-#include <sys/condvar.h>
-#include <sys/mutex.h>
+#include <sys/queue.h>
#include <sys/workqueue.h>
-#include <asm/bug.h>
#include <linux/kernel.h>
-/*
- * XXX This implementation is a load of bollocks -- callouts and
- * workqueues are expedient, but wrong, if for no reason other than
- * that there is no destroy operation.
- *
- * XXX The amount of code in here is absurd; it should be given a
- * proper source file.
- */
+#define INIT_DELAYED_WORK linux_INIT_DELAYED_WORK
+#define INIT_WORK linux_INIT_WORK
+#define alloc_ordered_workqueue linux_alloc_ordered_workqueue
+#define cancel_delayed_work linux_cancel_delayed_work
+#define cancel_delayed_work_sync linux_cancel_delayed_work_sync
+#define cancel_work linux_cancel_work
+#define cancel_work_sync linux_cancel_work_sync
+#define destroy_workqueue linux_destroy_workqueue
+#define flush_workqueue linux_flush_workqueue
+#define queue_delayed_work linux_queue_delayed_work
+#define queue_work linux_queue_work
+#define schedule_delayed_work linux_schedule_delayed_work
+#define schedule_work linux_schedule_work
+#define system_wq linux_system_wq
+#define to_delayed_work linux_to_delayed_work
+
+struct workqueue_struct;
struct work_struct {
- void (*w_fn)(struct work_struct *);
- struct workqueue *w_wq;
struct work w_wk;
- kmutex_t w_lock;
- kcondvar_t w_cv;
+ __cpu_simple_lock_t w_lock; /* XXX */
enum {
WORK_IDLE,
- WORK_QUEUED,
+ WORK_DELAYED,
+ WORK_PENDING,
+ WORK_INVOKED,
WORK_CANCELLED,
- WORK_INFLIGHT,
- WORK_REQUEUED,
+ WORK_DELAYED_CANCELLED,
} w_state;
+ struct workqueue_struct *w_wq;
+ void (*w_fn)(struct work_struct *);
};
-static void __unused
-linux_work_fn(struct work *wk __unused, void *arg)
-{
- struct work_struct *const work = arg;
-
- mutex_spin_enter(&work->w_lock);
- switch (work->w_state) {
- case WORK_IDLE:
- panic("work ran while idle: %p", work);
- break;
-
- case WORK_QUEUED:
- work->w_state = WORK_INFLIGHT;
- mutex_spin_exit(&work->w_lock);
- (*work->w_fn)(work);
- mutex_spin_enter(&work->w_lock);
- switch (work->w_state) {
- case WORK_IDLE:
- case WORK_QUEUED:
- panic("work hosed while in flight: %p", work);
- break;
-
- case WORK_INFLIGHT:
- case WORK_CANCELLED:
- work->w_state = WORK_IDLE;
- cv_broadcast(&work->w_cv);
- break;
-
- case WORK_REQUEUED:
- workqueue_enqueue(work->w_wq, &work->w_wk, NULL);
- work->w_state = WORK_QUEUED;
- break;
-
- default:
- panic("work %p in bad state: %d", work,
- (int)work->w_state);
- break;
- }
- break;
-
- case WORK_CANCELLED:
- work->w_state = WORK_IDLE;
- cv_broadcast(&work->w_cv);
- break;
-
- case WORK_INFLIGHT:
- panic("work already in flight: %p", work);
- break;
-
- case WORK_REQUEUED:
- panic("work requeued while not in flight: %p", work);
- break;
-
- default:
- panic("work %p in bad state: %d", work, (int)work->w_state);
- break;
- }
- mutex_spin_exit(&work->w_lock);
-}
-
-static inline void
-INIT_WORK(struct work_struct *work, void (*fn)(struct work_struct *))
-{
- int error;
-
- work->w_fn = fn;
- error = workqueue_create(&work->w_wq, "lnxworkq", &linux_work_fn,
- work, PRI_NONE, IPL_VM, WQ_MPSAFE);
- if (error)
- panic("workqueue creation failed: %d", error); /* XXX */
-
- mutex_init(&work->w_lock, MUTEX_DEFAULT, IPL_VM);
- cv_init(&work->w_cv, "linxwork");
- work->w_state = WORK_IDLE;
-}
-
-static inline void
-schedule_work(struct work_struct *work)
-{
-
- mutex_spin_enter(&work->w_lock);
- switch (work->w_state) {
- case WORK_IDLE:
- workqueue_enqueue(work->w_wq, &work->w_wk, NULL);
- work->w_state = WORK_QUEUED;
- break;
-
- case WORK_CANCELLED:
- break;
-
- case WORK_INFLIGHT:
- work->w_state = WORK_REQUEUED;
- break;
-
- case WORK_QUEUED:
- case WORK_REQUEUED:
- break;
-
- default:
- panic("work %p in bad state: %d", work, (int)work->w_state);
- break;
- }
- mutex_spin_exit(&work->w_lock);
-}
-
-/*
- * XXX This API can't possibly be right because there is no interlock.
- */
-static inline bool
-cancel_work_sync(struct work_struct *work)
-{
- bool was_pending = false;
-
- mutex_spin_enter(&work->w_lock);
-retry: switch (work->w_state) {
- case WORK_IDLE:
- break;
-
- case WORK_QUEUED:
- case WORK_INFLIGHT:
- case WORK_REQUEUED:
- work->w_state = WORK_CANCELLED;
- /* FALLTHROUGH */
- case WORK_CANCELLED:
- cv_wait(&work->w_cv, &work->w_lock);
- was_pending = true;
- goto retry;
-
- default:
- panic("work %p in bad state: %d", work, (int)work->w_state);
- }
- mutex_spin_exit(&work->w_lock);
-
- return was_pending;
-}
-
struct delayed_work {
- struct callout dw_callout;
- struct work_struct work; /* not dw_work; name must match Linux */
+ /* Not dw_work; name must match Linux. */
+ struct work_struct work;
+ struct callout dw_callout;
+ TAILQ_ENTRY(delayed_work) dw_entry;
};
-static void __unused
-linux_delayed_work_fn(void *arg)
-{
- struct delayed_work *const dw = arg;
-
- schedule_work(&dw->work);
-}
-
-static inline void
-INIT_DELAYED_WORK(struct delayed_work *dw, void (*fn)(struct work_struct *))
-{
- callout_init(&dw->dw_callout, CALLOUT_MPSAFE);
- callout_setfunc(&dw->dw_callout, linux_delayed_work_fn, dw);
- INIT_WORK(&dw->work, fn);
-}
-
static inline struct delayed_work *
to_delayed_work(struct work_struct *work)
{
return container_of(work, struct delayed_work, work);
}
Home |
Main Index |
Thread Index |
Old Index