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/ce801dccec7a
branches: trunk
changeset: 364808:ce801dccec7a
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 1d4e251ee96e -r ce801dccec7a 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 1d4e251ee96e -r ce801dccec7a 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