Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/external/bsd/common Draft rewrite of Linux workqueue rei...



details:   https://anonhg.NetBSD.org/src/rev/5a75f93b91d3
branches:  trunk
changeset: 835421:5a75f93b91d3
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Mon Aug 27 14:57:21 2018 +0000

description:
Draft rewrite of Linux workqueue reimplementation.

Just use an explicit thread; don't attempt to fudge it with
workqueue(9).  No doubt there are various mistakes in here, but they
should be easier to get right than the mega-kludgerific nonsense that
preceded this draft.

diffstat:

 sys/external/bsd/common/include/linux/workqueue.h |    39 +-
 sys/external/bsd/common/linux/linux_work.c        |  1217 +++++++-------------
 2 files changed, 478 insertions(+), 778 deletions(-)

diffs (truncated from 1534 to 300 lines):

diff -r ca7fcde3bbea -r 5a75f93b91d3 sys/external/bsd/common/include/linux/workqueue.h
--- a/sys/external/bsd/common/include/linux/workqueue.h Mon Aug 27 14:55:46 2018 +0000
+++ b/sys/external/bsd/common/include/linux/workqueue.h Mon Aug 27 14:57:21 2018 +0000
@@ -1,7 +1,7 @@
-/*     $NetBSD: workqueue.h,v 1.8 2018/08/27 07:46:28 riastradh Exp $  */
+/*     $NetBSD: workqueue.h,v 1.9 2018/08/27 14:57:21 riastradh Exp $  */
 
 /*-
- * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * Copyright (c) 2013, 2018 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -32,12 +32,10 @@
 #ifndef _LINUX_WORKQUEUE_H_
 #define _LINUX_WORKQUEUE_H_
 
-#include <sys/types.h>
-#include <sys/callout.h>
 #include <sys/queue.h>
-#include <sys/workqueue.h>
+#include <sys/stdbool.h>
 
-#include <linux/kernel.h>
+#include <linux/kernel.h>      /* container_of */
 
 #define        INIT_DELAYED_WORK               linux_INIT_DELAYED_WORK
 #define        INIT_WORK                       linux_INIT_WORK
@@ -64,25 +62,21 @@
 struct workqueue_struct;
 
 struct work_struct {
-       struct work             w_wk;
-       __cpu_simple_lock_t     w_lock; /* XXX */
-       enum {
-               WORK_IDLE,
-               WORK_DELAYED,
-               WORK_PENDING,
-               WORK_INVOKED,
-               WORK_CANCELLED,
-               WORK_DELAYED_CANCELLED,
-       }                       w_state;
-       struct workqueue_struct *w_wq;
-       void                    (*func)(struct work_struct *);
+       struct workqueue_struct *volatile work_queue;
+       TAILQ_ENTRY(work_struct)        work_entry;
+       void    (*func)(struct work_struct *); /* Linux API name */
 };
 
 struct delayed_work {
-       /* Not dw_work; name must match Linux.  */
-       struct work_struct              work;
+       struct work_struct              work; /* Linux API name */
        struct callout                  dw_callout;
        TAILQ_ENTRY(delayed_work)       dw_entry;
+       enum {
+               DELAYED_WORK_IDLE,
+               DELAYED_WORK_SCHEDULED,
+               DELAYED_WORK_RESCHEDULED,
+               DELAYED_WORK_CANCELLED,
+       }                               dw_state;
 };
 
 static inline struct delayed_work *
@@ -110,8 +104,9 @@
 void   INIT_WORK(struct work_struct *, void (*)(struct work_struct *));
 bool   schedule_work(struct work_struct *);
 bool   queue_work(struct workqueue_struct *, struct work_struct *);
+bool   cancel_work(struct work_struct *);
 bool   cancel_work_sync(struct work_struct *);
-void   flush_work(struct work_struct *);
+bool   flush_work(struct work_struct *);
 
 void   INIT_DELAYED_WORK(struct delayed_work *,
            void (*)(struct work_struct *));
@@ -122,7 +117,7 @@
            unsigned long ticks);
 bool   cancel_delayed_work(struct delayed_work *);
 bool   cancel_delayed_work_sync(struct delayed_work *);
-void   flush_delayed_work(struct delayed_work *);
+bool   flush_delayed_work(struct delayed_work *);
 
 struct work_struct *
        current_work(void);
diff -r ca7fcde3bbea -r 5a75f93b91d3 sys/external/bsd/common/linux/linux_work.c
--- a/sys/external/bsd/common/linux/linux_work.c        Mon Aug 27 14:55:46 2018 +0000
+++ b/sys/external/bsd/common/linux/linux_work.c        Mon Aug 27 14:57:21 2018 +0000
@@ -1,7 +1,7 @@
-/*     $NetBSD: linux_work.c,v 1.11 2018/08/27 14:48:47 riastradh Exp $        */
+/*     $NetBSD: linux_work.c,v 1.12 2018/08/27 14:57:21 riastradh Exp $        */
 
 /*-
- * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * Copyright (c) 2018 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -30,213 +30,91 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_work.c,v 1.11 2018/08/27 14:48:47 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_work.c,v 1.12 2018/08/27 14:57:21 riastradh Exp $");
 
 #include <sys/types.h>
-#include <sys/param.h>
 #include <sys/atomic.h>
 #include <sys/callout.h>
 #include <sys/condvar.h>
 #include <sys/errno.h>
-#include <sys/intr.h>
 #include <sys/kmem.h>
+#include <sys/kthread.h>
+#include <sys/lwp.h>
 #include <sys/mutex.h>
 #include <sys/queue.h>
-#include <sys/systm.h>
-#include <sys/workqueue.h>
-#include <sys/cpu.h>
-
-#include <machine/lock.h>
 
 #include <linux/workqueue.h>
 
 struct workqueue_struct {
-       struct workqueue                *wq_workqueue;
-
-       struct rb_node                  wq_node;
+       kmutex_t                        wq_lock;
+       kcondvar_t                      wq_cv;
+       TAILQ_HEAD(, delayed_work)      wq_delayed;
+       TAILQ_HEAD(, work_struct)       wq_queue;
+       struct work_struct              *wq_current_work;
+       int                             wq_flags;
        struct lwp                      *wq_lwp;
-
-       /* XXX The following should all be per-CPU.  */
-       kmutex_t                        wq_lock;
-
-       /*
-        * Condvar for when any state related to this workqueue
-        * changes.  XXX Could split this into multiple condvars for
-        * different purposes, but whatever...
-        */
-       kcondvar_t                      wq_cv;
-
-       TAILQ_HEAD(, delayed_work)      wq_delayed;
-       struct work_struct              *wq_current_work;
+       uint64_t                        wq_gen;
+       bool                            wq_requeued:1;
+       bool                            wq_dying:1;
 };
 
-static void    linux_work_lock_init(struct work_struct *);
-static void    linux_work_lock(struct work_struct *);
-static void    linux_work_unlock(struct work_struct *);
-static bool    linux_work_locked(struct work_struct *) __diagused;
-
-static void    linux_wq_barrier(struct work_struct *);
-
-static void    linux_wait_for_cancelled_work(struct work_struct *);
-static void    linux_wait_for_invoked_work(struct work_struct *);
-static void    linux_worker(struct work *, void *);
+static void __dead     linux_workqueue_thread(void *);
+static void            linux_workqueue_timeout(void *);
+static void            queue_delayed_work_anew(struct workqueue_struct *,
+                           struct delayed_work *, unsigned long);
 
-static void    linux_cancel_delayed_work_callout(struct delayed_work *, bool);
-static void    linux_wait_for_delayed_cancelled_work(struct delayed_work *);
-static void    linux_worker_intr(void *);
+static specificdata_key_t workqueue_key __read_mostly;
 
-struct workqueue_struct                *system_wq;
-struct workqueue_struct                *system_long_wq;
-struct workqueue_struct                *system_power_efficient_wq;
-
-static struct {
-       kmutex_t                lock;
-       struct rb_tree          tree;
-} workqueues __cacheline_aligned;
-
-static const rb_tree_ops_t     workqueues_rb_ops;
+struct workqueue_struct        *system_wq __read_mostly;
+struct workqueue_struct        *system_long_wq __read_mostly;
+struct workqueue_struct        *system_power_efficient_wq __read_mostly;
 
 int
 linux_workqueue_init(void)
 {
+       int error;
 
-       mutex_init(&workqueues.lock, MUTEX_DEFAULT, IPL_VM);
-       rb_tree_init(&workqueues.tree, &workqueues_rb_ops);
-
-       system_wq = alloc_ordered_workqueue("lnxsyswq", 0);
-       if (system_wq == NULL)
+       error = lwp_specific_key_create(&workqueue_key, NULL);
+       if (error)
                goto fail0;
 
+       system_wq = alloc_ordered_workqueue("lnxsyswq", 0);
+       if (system_wq == NULL) {
+               error = ENOMEM;
+               goto fail1;
+       }
+
        system_long_wq = alloc_ordered_workqueue("lnxlngwq", 0);
-       if (system_long_wq == NULL)
-               goto fail1;
+       if (system_long_wq == NULL) {
+               error = ENOMEM;
+               goto fail2;
+       }
 
        system_power_efficient_wq = alloc_ordered_workqueue("lnxpwrwq", 0);
-       if (system_long_wq == NULL)
-               goto fail2;
+       if (system_long_wq == NULL) {
+               error = ENOMEM;
+               goto fail3;
+       }
 
        return 0;
 
-fail3: __unused
+fail4: __unused
        destroy_workqueue(system_power_efficient_wq);
-fail2: destroy_workqueue(system_long_wq);
-fail1: destroy_workqueue(system_wq);
-fail0: mutex_destroy(&workqueues.lock);
-       return ENOMEM;
+fail3: destroy_workqueue(system_long_wq);
+fail2: destroy_workqueue(system_wq);
+fail1: lwp_specific_key_delete(workqueue_key);
+fail0: KASSERT(error);
+       return error;
 }
 
 void
 linux_workqueue_fini(void)
 {
 
+       destroy_workqueue(system_power_efficient_wq);
        destroy_workqueue(system_long_wq);
-       system_long_wq = NULL;
        destroy_workqueue(system_wq);
-       system_wq = NULL;
-       KASSERT(RB_TREE_MIN(&workqueues.tree) == NULL);
-       mutex_destroy(&workqueues.lock);
-}
-
-/*
- * Table of workqueue LWPs for validation -- assumes there is only one
- * thread per workqueue.
- *
- * XXX Mega-kludgerific!
- */
-
-static int
-compare_nodes(void *cookie, const void *va, const void *vb)
-{
-       const struct workqueue_struct *wa = va;
-       const struct workqueue_struct *wb = vb;
-
-       if ((uintptr_t)wa->wq_lwp < (uintptr_t)wb->wq_lwp)
-               return -1;
-       if ((uintptr_t)wa->wq_lwp > (uintptr_t)wb->wq_lwp)
-               return +1;
-       return 0;
-}
-
-static int
-compare_key(void *cookie, const void *vn, const void *vk)
-{
-       const struct workqueue_struct *w = vn;
-       const struct lwp *lwp = vk;
-
-       if ((uintptr_t)w->wq_lwp < (uintptr_t)lwp)
-               return -1;
-       if ((uintptr_t)w->wq_lwp > (uintptr_t)lwp)
-               return +1;
-       return 0;
-}
-
-static const rb_tree_ops_t workqueues_rb_ops = {
-       .rbto_compare_nodes = compare_nodes,
-       .rbto_compare_key = compare_key,
-       .rbto_node_offset = offsetof(struct workqueue_struct, wq_node),
-};
-
-struct wq_whoami_work {
-       kmutex_t                www_lock;
-       kcondvar_t              www_cv;
-       struct workqueue_struct *www_wq;
-       struct work_struct      www_work;
-};
-
-static void
-workqueue_whoami_work(struct work_struct *work)



Home | Main Index | Thread Index | Old Index