Author: hselasky
Date: Tue Mar 7 12:09:14 2017
New Revision: 314843
URL: https://svnweb.freebsd.org/changeset/base/314843
Log:
LinuxKPI workqueue cleanup.
This change makes the workqueue implementation behave more like in
Linux, both functionality wise and structure wise.
All workqueue code has been moved to linux_work.c
Add an atomic based statemachine to the work_struct to ensure proper
operation. Prior to this change struct_work was directly mapped to a
FreeBSD task. When a taskqueue has multiple threads the same task may
end up being executed on more than one worker thread simultaneously.
This might cause problems with code coming from Linux, which expects
serial behaviour, similar to Linux tasklets.
Move all global workqueue function names into the linux_xxx domain to
avoid symbol name clashes in the future.
Implement a few more workqueue related functions and macros.
Create two multithreaded taskqueues for the LinuxKPI during module
load, one for time-consuming callbacks and one for non-time consuming
callbacks.
MFC after:1 week
Sponsored by: Mellanox Technologies
Added:
head/sys/compat/linuxkpi/common/src/linux_work.c (contents, props changed)
Modified:
head/sys/compat/linuxkpi/common/include/linux/workqueue.h
head/sys/compat/linuxkpi/common/src/linux_compat.c
head/sys/conf/files
head/sys/modules/linuxkpi/Makefile
Modified: head/sys/compat/linuxkpi/common/include/linux/workqueue.h
==
--- head/sys/compat/linuxkpi/common/include/linux/workqueue.h Tue Mar 7
09:18:52 2017(r314842)
+++ head/sys/compat/linuxkpi/common/include/linux/workqueue.h Tue Mar 7
12:09:14 2017(r314843)
@@ -2,7 +2,7 @@
* Copyright (c) 2010 Isilon Systems, Inc.
* Copyright (c) 2010 iX Systems, Inc.
* Copyright (c) 2010 Panasas, Inc.
- * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,179 +38,189 @@
#include
+#include
+#include
#include
+#include
+
+#defineWORK_CPU_UNBOUND MAXCPU
+#defineWQ_UNBOUND (1 << 0)
+#defineWQ_HIGHPRI (1 << 1)
+
+struct work_struct;
+typedef void (*work_func_t)(struct work_struct *);
+
+struct work_exec {
+ TAILQ_ENTRY(work_exec) entry;
+ struct work_struct *target;
+};
struct workqueue_struct {
- struct taskqueue*taskqueue;
- atomic_tdraining;
+ struct taskqueue *taskqueue;
+ struct mtx exec_mtx;
+ TAILQ_HEAD(, work_exec) exec_head;
+ atomic_t draining;
};
+#defineWQ_EXEC_LOCK(wq) mtx_lock(&(wq)->exec_mtx)
+#defineWQ_EXEC_UNLOCK(wq) mtx_unlock(&(wq)->exec_mtx)
+
struct work_struct {
- struct taskwork_task;
- struct taskqueue *taskqueue;
- void(*fn)(struct work_struct *);
+ struct task work_task;
+ struct workqueue_struct *work_queue;
+ work_func_t func;
+ atomic_t state;
};
-typedef __typeof(((struct work_struct *)0)->fn) work_func_t;
+#defineDECLARE_WORK(name, fn) \
+ struct work_struct name = { .func = (fn) }
struct delayed_work {
- struct work_struct work;
- struct callout timer;
+ struct work_struct work;
+ struct {
+ struct callout callout;
+ struct mtx mtx;
+ int expires;
+ } timer;
};
-extern void linux_work_fn(void *, int);
-extern void linux_flush_fn(void *, int);
-extern void linux_delayed_work_fn(void *);
-extern struct workqueue_struct *linux_create_workqueue_common(const char *,
int);
-extern void destroy_workqueue(struct workqueue_struct *);
+#defineDECLARE_DELAYED_WORK(name, fn)
\
+ struct delayed_work name; \
+ static void name##_init(void *arg) \
+ { \
+ linux_init_delayed_work(, fn); \
+ } \
+ SYSINIT(name, SI_SUB_LOCK, SI_ORDER_SECOND, name##_init, NULL)
static inline struct delayed_work *
to_delayed_work(struct work_struct *work)
{
-
- return container_of(work, struct delayed_work, work);
+ return (container_of(work, struct delayed_work, work));
}
-#defineINIT_WORK(work, func)
\
+#defineINIT_WORK(work, fn)
\
do { \
- (work)->fn = (func);\
- (work)->taskqueue = NULL;