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