From: Tejun Heo <tj@kernel.org>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Walls <awalls@md.metrocast.net>,
Daniel Walker <dwalker@codeaurora.org>,
mingo@elte.hu, linux-kernel@vger.kernel.org, jeff@garzik.org,
rusty@rustcorp.com.au, cl@linux-foundation.org,
dhowells@redhat.com, arjan@linux.intel.com,
johannes@sipsolutions.net, oleg@redhat.com, axboe@kernel.dk,
mst@redhat.com, samudrala.sridhar@gmail.com
Subject: [PATCH] kthread: implement kthread_worker
Date: Sat, 19 Jun 2010 17:53:55 +0200 [thread overview]
Message-ID: <4C1CE813.8080701@kernel.org> (raw)
In-Reply-To: <4C1BACC6.5020602@kernel.org>
Implement simple work processor for kthread. This is to ease using
kthread. Single thread workqueue used to be used for things like this
but workqueue won't guarantee fixed kthread association anymore to
enable worker sharing.
This can be used in cases where specific kthread association is
necessary, for example, when it should have RT priority or be assigned
to certain cgroup.
Signed-off-by: Tejun Heo <tj@kernel.org>
---
So, basically something like this. This doesn't support all the
features of workqueue but should be enough for most cases and we can
always add missing bits as necessary. This is basically the same
logic that I wrote for vhost (vhost people cc'd) and vhost should be
able to switch easily. It's simple but efficient and makes using
kthread a lot easier.
Andrew, does this look like a reasonable compromise? If so, I'll put
it in the series, convert ivtv and integrate padata and post another
round.
Thanks.
include/linux/kthread.h | 63 +++++++++++++++++++++++++
kernel/kthread.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 181 insertions(+)
Index: work/kernel/kthread.c
===================================================================
--- work.orig/kernel/kthread.c
+++ work/kernel/kthread.c
@@ -14,6 +14,8 @@
#include <linux/file.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/freezer.h>
#include <trace/events/sched.h>
static DEFINE_SPINLOCK(kthread_create_lock);
@@ -247,3 +249,119 @@ int kthreadd(void *unused)
return 0;
}
+
+/**
+ * kthread_worker_fn - kthread function to process kthread_worker
+ * @data: pointer to initialized kthread_worker
+ *
+ * This function can be used as @threadfn to kthread_create() or
+ * kthread_run() with @data argument pointing to an initialized
+ * kthread_worker. The started kthread will process work_list until
+ * the it is stopped with kthread_stop(). A kthread can also call
+ * this function directly after extra initialization.
+ *
+ * Different kthreads can be used for the same kthread_worker as long
+ * as there's only one kthread attached to it at any given time. A
+ * kthread_worker without an attached kthread simply collects queued
+ * kthread_works.
+ */
+int kthread_worker_fn(void *worker_ptr)
+{
+ struct kthread_worker *worker = worker_ptr;
+ struct kthread_work *work;
+
+ WARN_ON(worker->task);
+ worker->task = current;
+repeat:
+ set_current_state(TASK_INTERRUPTIBLE); /* mb paired w/ kthread_stop */
+
+ if (kthread_should_stop()) {
+ __set_current_state(TASK_RUNNING);
+ spin_lock_irq(&worker->lock);
+ worker->task = NULL;
+ spin_unlock_irq(&worker->lock);
+ return 0;
+ }
+
+ work = NULL;
+ spin_lock_irq(&worker->lock);
+ if (!list_empty(&worker->work_list)) {
+ work = list_first_entry(&worker->work_list,
+ struct kthread_work, node);
+ list_del_init(&work->node);
+ }
+ spin_unlock_irq(&worker->lock);
+
+ if (work) {
+ __set_current_state(TASK_RUNNING);
+ work->func(work);
+ smp_wmb(); /* wmb worker-b0 paired with flush-b1 */
+ work->done_seq = work->queue_seq;
+ smp_mb(); /* mb worker-b1 paired with flush-b0 */
+ if (atomic_read(&work->flushing))
+ wake_up_all(&work->done);
+ } else if (!freezing(current))
+ schedule();
+
+ try_to_freeze();
+ goto repeat;
+}
+EXPORT_SYMBOL_GPL(kthread_worker_fn);
+
+/**
+ * queue_kthread_work - queue a kthread_work
+ * @worker: target kthread_worker
+ * @work: kthread_work to queue
+ *
+ * Queue @work to work processor @task for async execution. @task
+ * must have been created with kthread_worker_create(). Returns %true
+ * if @work was successfully queued, %false if it was already pending.
+ */
+bool queue_kthread_work(struct kthread_worker *worker,
+ struct kthread_work *work)
+{
+ bool ret = false;
+ unsigned long flags;
+
+ spin_lock_irqsave(&worker->lock, flags);
+ if (list_empty(&work->node)) {
+ list_add_tail(&work->node, &worker->work_list);
+ work->queue_seq++;
+ if (likely(worker->task))
+ wake_up_process(worker->task);
+ ret = true;
+ }
+ spin_unlock_irqrestore(&worker->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(queue_kthread_work);
+
+/**
+ * flush_kthread_work - flush a kthread_work
+ * @work: work to flush
+ *
+ * If @work is queued or executing, wait for it to finish execution.
+ */
+void flush_kthread_work(struct kthread_work *work)
+{
+ int seq = work->queue_seq;
+
+ atomic_inc(&work->flushing);
+
+ /*
+ * mb flush-b0 paired with worker-b1, to make sure either
+ * worker sees the above increment or we see done_seq update.
+ */
+ smp_mb__after_atomic_inc();
+
+ /* A - B <= 0 tests whether B is in front of A regardless of overflow */
+ wait_event(work->done, seq - work->done_seq <= 0);
+ atomic_dec(&work->flushing);
+
+ /*
+ * rmb flush-b1 paired with worker-b0, to make sure our caller
+ * sees every change made by work->func().
+ */
+ smp_mb__after_atomic_dec();
+}
+EXPORT_SYMBOL_GPL(flush_kthread_work);
Index: work/include/linux/kthread.h
===================================================================
--- work.orig/include/linux/kthread.h
+++ work/include/linux/kthread.h
@@ -34,4 +34,67 @@ int kthread_should_stop(void);
int kthreadd(void *unused);
extern struct task_struct *kthreadd_task;
+/*
+ * Simple work processor based on kthread.
+ *
+ * This provides easier way to make use of kthreads. A kthread_work
+ * can be queued and flushed using queue/flush_kthread_work()
+ * respectively. Queued kthread_works are processed by a kthread
+ * running kthread_worker_fn().
+ *
+ * A kthread_work can't be freed while it is executing.
+ */
+struct kthread_work;
+typedef void (*kthread_work_func_t)(struct kthread_work *work);
+
+struct kthread_worker {
+ spinlock_t lock;
+ struct list_head work_list;
+ struct task_struct *task;
+};
+
+struct kthread_work {
+ struct list_head node;
+ kthread_work_func_t func;
+ wait_queue_head_t done;
+ atomic_t flushing;
+ int queue_seq;
+ int done_seq;
+};
+
+#define KTHREAD_WORKER_INIT(worker) { \
+ .lock = SPIN_LOCK_UNLOCKED, \
+ .work_list = LIST_HEAD_INIT((worker).work_list), \
+ }
+
+#define KTHREAD_WORK_INIT(work, fn) { \
+ .node = LIST_HEAD_INIT((work).node), \
+ .func = (fn), \
+ .done = __WAIT_QUEUE_HEAD_INITIALIZER((work).done), \
+ .flushing = ATOMIC_INIT(0), \
+ }
+
+#define DEFINE_KTHREAD_WORKER(worker) \
+ struct kthread_worker worker = KTHREAD_WORKER_INIT(worker)
+
+#define DEFINE_KTHREAD_WORK(work, fn) \
+ struct kthread_work work = KTHREAD_WORK_INIT(work, fn)
+
+static inline void init_kthread_worker(struct kthread_worker *worker)
+{
+ *worker = (struct kthread_worker)KTHREAD_WORKER_INIT(*worker);
+}
+
+static inline void init_kthread_work(struct kthread_work *work,
+ kthread_work_func_t fn)
+{
+ *work = (struct kthread_work)KTHREAD_WORK_INIT(*work, fn);
+}
+
+int kthread_worker_fn(void *worker_ptr);
+
+bool queue_kthread_work(struct kthread_worker *worker,
+ struct kthread_work *work);
+void flush_kthread_work(struct kthread_work *work);
+
#endif /* _LINUX_KTHREAD_H */
next prev parent reply other threads:[~2010-06-19 15:54 UTC|newest]
Thread overview: 129+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-06-14 21:37 [PATCHSET] workqueue: concurrency managed workqueue, take#5 Tejun Heo
2010-06-14 21:37 ` [PATCH 01/30] kthread: implement kthread_data() Tejun Heo
2010-06-14 21:37 ` [PATCH 02/30] acpi: use queue_work_on() instead of binding workqueue worker to cpu0 Tejun Heo
2010-06-14 21:37 ` [PATCH 03/30] workqueue: kill RT workqueue Tejun Heo
2010-06-14 21:37 ` [PATCH 04/30] workqueue: misc/cosmetic updates Tejun Heo
2010-06-14 21:37 ` [PATCH 05/30] workqueue: merge feature parameters into flags Tejun Heo
2010-06-14 21:37 ` [PATCH 06/30] workqueue: define masks for work flags and conditionalize STATIC flags Tejun Heo
2010-06-14 21:37 ` [PATCH 07/30] workqueue: separate out process_one_work() Tejun Heo
2010-06-14 21:37 ` [PATCH 08/30] workqueue: temporarily disable workqueue tracing Tejun Heo
2010-06-15 13:29 ` Frederic Weisbecker
2010-06-15 16:37 ` Tejun Heo
2010-06-14 21:37 ` [PATCH 09/30] workqueue: kill cpu_populated_map Tejun Heo
2010-06-14 21:37 ` [PATCH 10/30] workqueue: update cwq alignement Tejun Heo
2010-06-14 21:37 ` [PATCH 11/30] workqueue: reimplement workqueue flushing using color coded works Tejun Heo
2010-06-14 21:37 ` [PATCH 12/30] workqueue: introduce worker Tejun Heo
2010-06-14 21:37 ` [PATCH 13/30] workqueue: reimplement work flushing using linked works Tejun Heo
2010-06-14 21:37 ` [PATCH 14/30] workqueue: implement per-cwq active work limit Tejun Heo
2010-06-14 21:37 ` [PATCH 15/30] workqueue: reimplement workqueue freeze using max_active Tejun Heo
2010-06-14 21:37 ` [PATCH 16/30] workqueue: introduce global cwq and unify cwq locks Tejun Heo
2010-06-14 21:37 ` [PATCH 17/30] workqueue: implement worker states Tejun Heo
2010-06-14 21:37 ` [PATCH 18/30] workqueue: reimplement CPU hotplugging support using trustee Tejun Heo
2010-06-14 21:37 ` [PATCH 19/30] workqueue: make single thread workqueue shared worker pool friendly Tejun Heo
2010-06-14 21:37 ` [PATCH 20/30] workqueue: add find_worker_executing_work() and track current_cwq Tejun Heo
2010-06-14 21:37 ` [PATCH 21/30] workqueue: carry cpu number in work data once execution starts Tejun Heo
2010-06-14 21:37 ` [PATCH 22/30] workqueue: implement WQ_NON_REENTRANT Tejun Heo
2010-06-14 21:37 ` [PATCH 23/30] workqueue: use shared worklist and pool all workers per cpu Tejun Heo
2010-06-14 21:37 ` [PATCH 24/30] workqueue: implement concurrency managed dynamic worker pool Tejun Heo
2010-06-14 21:37 ` [PATCH 25/30] workqueue: increase max_active of keventd and kill current_is_keventd() Tejun Heo
2010-06-14 21:37 ` [PATCH 26/30] workqueue: add system_wq, system_long_wq and system_nrt_wq Tejun Heo
2010-06-14 21:37 ` [PATCH 27/30] workqueue: implement DEBUGFS/workqueue Tejun Heo
2010-06-15 13:54 ` Frederic Weisbecker
2010-06-15 16:42 ` Tejun Heo
2010-06-14 21:37 ` [PATCH 28/30] workqueue: implement several utility APIs Tejun Heo
2010-06-14 21:37 ` [PATCH 29/30] libata: take advantage of cmwq and remove concurrency limitations Tejun Heo
2010-06-14 21:37 ` [PATCH 30/30] async: use workqueue for worker pool Tejun Heo
2010-06-14 21:58 ` [PATCHSET] workqueue: concurrency managed workqueue, take#5 Andrew Morton
2010-06-14 22:17 ` Tejun Heo
2010-06-14 22:31 ` Daniel Walker
2010-06-14 22:33 ` Tejun Heo
2010-06-14 22:35 ` Daniel Walker
2010-06-14 22:44 ` Tejun Heo
2010-06-14 22:49 ` Daniel Walker
2010-06-14 22:52 ` Tejun Heo
2010-06-14 22:35 ` Andrew Morton
2010-06-14 22:43 ` Tejun Heo
2010-06-14 23:06 ` Andrew Morton
2010-06-15 12:53 ` tytso
2010-06-15 16:15 ` [PATCH] SubmittingPatches: add more about patch descriptions Randy Dunlap
2010-06-15 16:33 ` Christoph Lameter
2010-06-15 18:15 ` [PATCHSET] workqueue: concurrency managed workqueue, take#5 Stefan Richter
2010-06-15 19:39 ` Tejun Heo
2010-06-15 1:20 ` Jeff Garzik
2010-06-15 18:25 ` Overview of concurrency managed workqueue Tejun Heo
2010-06-15 18:40 ` Christoph Lameter
2010-06-15 18:44 ` Tejun Heo
2010-06-15 19:43 ` Daniel Walker
2010-06-16 12:10 ` Tejun Heo
2010-06-16 13:27 ` Daniel Walker
2010-06-16 13:30 ` Tejun Heo
2010-06-16 13:41 ` Daniel Walker
2010-06-16 13:45 ` Tejun Heo
2010-06-16 14:05 ` Daniel Walker
2010-06-16 14:15 ` Tejun Heo
2010-06-16 14:34 ` Daniel Walker
2010-06-16 14:50 ` Tejun Heo
2010-06-16 15:11 ` Daniel Walker
2010-06-16 15:50 ` Tejun Heo
2010-06-16 16:30 ` Daniel Walker
2010-06-16 16:55 ` Tejun Heo
2010-06-16 18:22 ` Daniel Walker
2010-06-16 18:46 ` Tejun Heo
2010-06-16 19:20 ` Tejun Heo
2010-06-16 19:46 ` Daniel Walker
2010-06-16 19:58 ` Tejun Heo
2010-06-17 5:29 ` Florian Mickler
2010-06-17 6:21 ` Florian Mickler
2010-06-17 8:28 ` Tejun Heo
2010-06-17 18:03 ` Daniel Walker
2010-06-18 6:36 ` Florian Mickler
2010-06-18 16:38 ` Daniel Walker
2010-06-16 19:36 ` Daniel Walker
2010-06-16 19:52 ` Tejun Heo
2010-06-16 20:19 ` Daniel Walker
2010-06-16 20:24 ` Tejun Heo
2010-06-16 20:40 ` Daniel Walker
2010-06-16 21:41 ` Tejun Heo
2010-06-17 23:15 ` Andrew Morton
2010-06-18 8:03 ` Tejun Heo
2010-06-18 8:22 ` Tejun Heo
2010-06-18 17:29 ` Daniel Walker
2010-06-16 18:31 ` Stefan Richter
2010-06-16 18:41 ` Daniel Walker
2010-06-17 12:01 ` Andy Walls
2010-06-17 16:56 ` Daniel Walker
2010-06-17 23:16 ` Andrew Morton
2010-06-18 7:16 ` Tejun Heo
2010-06-18 7:31 ` Andrew Morton
2010-06-18 8:09 ` Tejun Heo
2010-06-18 17:02 ` Andrew Morton
2010-06-18 17:28 ` Tejun Heo
2010-06-19 15:53 ` Tejun Heo [this message]
2010-06-21 20:33 ` [PATCH] kthread: implement kthread_worker Randy Dunlap
2010-06-22 7:31 ` Tejun Heo
2010-06-19 8:38 ` Overview of concurrency managed workqueue Andi Kleen
2010-06-19 8:40 ` Tejun Heo
2010-06-19 8:55 ` Andi Kleen
2010-06-19 9:01 ` Tejun Heo
2010-06-19 9:08 ` Andi Kleen
2010-06-19 9:12 ` Tejun Heo
2010-06-19 9:15 ` Andi Kleen
2010-06-19 9:17 ` Tejun Heo
2010-06-19 9:27 ` Andi Kleen
2010-06-19 9:42 ` Tejun Heo
2010-06-19 12:20 ` Andi Kleen
2010-06-19 12:48 ` Tejun Heo
2010-06-17 22:28 ` Daniel Walker
2010-06-16 6:55 ` Florian Mickler
2010-06-16 12:22 ` Tejun Heo
2010-06-16 13:37 ` Johannes Berg
2010-06-16 13:39 ` Tejun Heo
2010-06-16 13:42 ` Johannes Berg
2010-06-17 23:14 ` Andrew Morton
2010-06-17 23:25 ` Joel Becker
2010-06-17 23:56 ` Andrew Morton
2010-06-18 7:15 ` Tejun Heo
2010-06-18 7:31 ` Tejun Heo
2010-06-15 18:29 ` [PATCHSET] workqueue: concurrency managed workqueue, take#5 Stefan Richter
2010-06-15 18:40 ` Tejun Heo
2010-06-15 20:29 ` Stefan Richter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4C1CE813.8080701@kernel.org \
--to=tj@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=arjan@linux.intel.com \
--cc=awalls@md.metrocast.net \
--cc=axboe@kernel.dk \
--cc=cl@linux-foundation.org \
--cc=dhowells@redhat.com \
--cc=dwalker@codeaurora.org \
--cc=jeff@garzik.org \
--cc=johannes@sipsolutions.net \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=mst@redhat.com \
--cc=oleg@redhat.com \
--cc=rusty@rustcorp.com.au \
--cc=samudrala.sridhar@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).