Skip to contentSkip to conversation

create_singlethread_workqueue()

PATCH In review Rusty Russell (IBM) 2 participants 2 messages Apr 19, 2004 1 message not in the archive Workqueue

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 create_singlethread_workqueue()

I considered a more general solution, but in the end this was simplest:
I can't currently see much point in anything other than 1 thread or 1 thread per-cpu.

Name: Workqueues With Only A Single Thread, Not One Per CPU
Status: Tested on 2.6.6-rc1-bk3

Workqueues are a great primitive for running things from user context from a completely clean environment. Unfortunately, they currently insist on creating one thread per CPU, which is overkill for many situations, so the more generic keventd workqueue is used for these. Recently deadlocks using keventd were demonstrated, showing that it is not suitable for all uses.

1) Clean up CPU iterators. Always a nice touch.

2) Add __create_workqueue() and create_singlethread_workqueue(), keeping source compatibility.

3) Put workqueues in workqueue list even if !CONFIG_HOTPLUG_CPU (means we need a lock to protect that list). Now we can tell if a wq is single-threaded using list_empty(&wq->list).

4) For single-threaded workqueues, override CPU in queue_work, delayed_work_timer_fn and flush_workqueue to be 0. flush_workqueue now does redundant passes for single-threaded workqueues, but the code remains simple.

5) Make create_workqueue_thread return the thread, so we can easily kthread_bind for multi-threaded workqueues.

diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13527-linux-2.6.6-rc1-bk2/include/linux/workqueue.h .13527-linux-2.6.6-rc1-bk2.updated/include/linux/workqueue.h

include/linux/workqueue.h +5 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .26663-linux-2.6.6-rc1-bk2/include/linux/workqueue.h .26663-linux-2.6.6-rc1-bk2.updated/include/linux/workqueue.h
@@ -49,7 +50,11 @@ struct work_struct {
 		init_timer(&(_work)->timer);			\
 	} while (0)
 
-extern struct workqueue_struct *create_workqueue(const char *name);
+extern struct workqueue_struct *__create_workqueue(const char *name,
+						    int singlethread);
+#define create_workqueue(name) __create_workqueue((name), 0)
+#define create_singlethread_workqueue(name) __create_workqueue((name), 1)
+
 extern void destroy_workqueue(struct workqueue_struct *wq);
 
 extern int FASTCALL(queue_work(struct workqueue_struct *wq, struct work_struct *work));
kernel/workqueue.c +53 -31

162 lines not on this page · raw message

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw
Quoted 8 lines · Ingo Oeser

Review void fastcall flush_workqueue(struct wor

Quoted 6 lines
(quoted diff) +2 -0
+		if (is_single_threaded(wq))
+			cpu = 0;
 		cwq = wq->cpu_wq + cpu;
 
 		if (cwq->thread == current) {
@@ -266,7 +271,8 @@ void fastcall flush_workqueue(struct wor

I can't see, how this works.

I can't either. If I had more than one CPU...

OK. This has been tested on my dual SMP. Only other change is
cosmetic: single-threaded wq thread does not have "/0" appended.

Thanks!
Rusty.

Name: Workqueues With Only A Single Thread, Not One Per CPU
Status: Tested on 2.6.6-rc1-bk3

Workqueues are a great primitive for running things from user context from a completely clean environment. Unfortunately, they currently insist on creating one thread per CPU, which is overkill for many situations, so the more generic keventd workqueue is used for these. Recently deadlocks using keventd were demonstrated, showing that it is not suitable for all uses.

1) Clean up CPU iterators. Always a nice touch.

2) Add __create_workqueue() and create_singlethread_workqueue(), keeping source compatibility.

3) Put workqueues in workqueue list even if !CONFIG_HOTPLUG_CPU (means we need a lock to protect that list). Now we can tell if a wq is single-threaded using list_empty(&wq->list).

4) For single-threaded workqueues, override CPU in queue_work, delayed_work_timer_fn and flush_workqueue to be 0. flush_workqueue now does redundant passes for single-threaded workqueues, but the code remains simple.

5) Make create_workqueue_thread return the thread, so we can easily kthread_bind for multi-threaded workqueues.

include/linux/workqueue.h +5 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .21345-linux-2.6.6-rc1-bk3/include/linux/workqueue.h .21345-linux-2.6.6-rc1-bk3.updated/include/linux/workqueue.h
@@ -49,7 +49,11 @@ struct work_struct {
 		init_timer(&(_work)->timer);			\
 	} while (0)
 
-extern struct workqueue_struct *create_workqueue(const char *name);
+extern struct workqueue_struct *__create_workqueue(const char *name,
+						    int singlethread);
+#define create_workqueue(name) __create_workqueue((name), 0)
+#define create_singlethread_workqueue(name) __create_workqueue((name), 1)
+
 extern void destroy_workqueue(struct workqueue_struct *wq);
 
 extern int FASTCALL(queue_work(struct workqueue_struct *wq, struct work_struct *work));
kernel/workqueue.c +59 -33

171 lines not on this page · raw message

Signature · 1 line
Anyone who quotes me in their signature is an idiot -- Rusty Russell