Skip to contentSkip to conversation

Second Coming of Kthread

PATCH New Rusty Russell 1 participant 1 message Jan 6, 2004 Workqueue

lore
Share & tools
lore
#0 lore raw

PATCH 1/2 Second Coming of Kthread

My previous approach, with initfn and corefn, was too complex. Having reimplemented it using signals, and debated a length with Davide, I present this completely rewritten, much simpler version.

The user now uses it exactly like kernel_thread(), and exits when signalled. This requires the previous workqueue SIGCHLD fix.

Feedback welcome!
Rusty.
--
Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

Name: Simplified Kthread
Author: Rusty Russell
Status: Tested on 2.6.1-rc1-bk6
Depends: Hotcpu-New-Kthread/workqueue_children.patch.gz

D: The hotplug CPU code introduces two major problems:
D:

D: 1) Threads which previously never stopped (migration thread,
D:    ksoftirqd, keventd) have to be stopped cleanly as CPUs go offline.
D: 2) Threads which previously never had to be created now have
D:    to be created when a CPU goes online.

D:
D: Unfortunately, stopping a thread is fairly baroque, involving memory
D: barriers, a completion and spinning until the task is actually dead
D: (for example, complete_and_exit() must be used if inside a module). D:

D: There are also three problems in starting a thread:
D: 1) Doing it from a random process context risks environment contamination:
D:    better to do it from keventd to guarantee a clean environment, a-la
D:    call_usermodehelper.
D: 2) Getting the task struct without races is a hard: see kernel/sched.c
D:    migration_call(), kernel/workqueue.c create_workqueue_thread().
D: 3) There are races in starting a thread for a CPU which is not yet
D:    online: migration thread does a complex dance at the moment for
D:    a similar reason (there may be no migration thread to migrate us).

D:
D: Place all this logic in some primitives to make life easier:
D: kthread_create(), kthread_start() and kthread_stop(). These
D: primitives require no extra data-structures in the caller: they operate
D: on normal "struct task_struct"s.
D:

D: Other changes:
D:   - Expose keventd_up(), as keventd and migration threads will use
D:     kthread to launch, and kthread normally uses workqueues and must
D:     recognize this case.
include/linux/kthread.h +67 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12121-linux-2.6.1-rc1-bk6/include/linux/kthread.h .12121-linux-2.6.1-rc1-bk6.updated/include/linux/kthread.h
@@ -0,0 +1,67 @@
+#ifndef _LINUX_KTHREAD_H
+#define _LINUX_KTHREAD_H
+/* Simple interface for creating and stopping kernel threads without mess. */
+#include <linux/err.h>
+struct task_struct;
+
+/**
+ * kthread_create: create a kthread.
+ * @threadfn: the function to run until signal_pending(current).
+ * @data: data ptr for @threadfn.
+ * @namefmt: printf-style name for the thread.
+ *
+ * Description: This helper function creates and names a kernel
+ * thread.  The thread will be stopped: use kthread_start() to start
+ * it.  See also kthread_run().
+ * 
+ * Returns a task_struct or ERR_PTR(-ENOMEM).
+ */
+struct task_struct *kthread_create(int (*threadfn)(void *data),
+				   void *data,
+				   const char namefmt[], ...);
+
+/**
+ * kthread_start: start a thread created by kthread_create().
+ * @k: the task returned by kthread_create().
+ *
+ * Description: This makes the thread @k run the threadfn() specified
+ * in kthread_create().  The threadfn() can either call do_exit()
+ * directly if it is a standalone thread for which noone will call
+ * kthread_stop(), or return when 'signal_pending(current)' is true
+ * (which means kthread_stop() has been called).  The return value
+ * should be zero or a negative error number: it will be passed to
+ * kthread_stop().
+ */
+void kthread_start(struct task_struct *k);
+
+/**
+ * kthread_run: create and start a thread.
+ * @threadfn: the function to run until signal_pending(current).
+ * @data: data ptr for @threadfn.
+ * @namefmt: printf-style name for the thread.
+ *
+ * Description: Convenient wrapper for kthread_create() followed by
+ * kthread_start().  Returns the kthread, or ERR_PTR(-ENOMEM). */
+#define kthread_run(threadfn, data, namefmt, ...)			   \
+({									   \
+	struct task_struct *__k						   \
+		= kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
+	if (!IS_ERR(__k))						   \
+		kthread_start(__k);					   \
+	__k;								   \
+})
+
+/**
+ * kthread_stop: stop a thread created by kthread_create().
+ * @k: thread created by kthread_create.
+ *
+ * Sends a signal to @k, and waits for it to exit.  Your threadfn()
+ * must not call do_exit() itself if you use this function!  This can
+ * also be called after kthread_create() instead of calling
+ * kthread_start(): the thread will exit without calling threadfn.
+ *
+ * Returns the result of threadfn(), or -EINTR if kthread_start() was never
+ * called. */
+int kthread_stop(struct task_struct *k);
+
+#endif /* _LINUX_KTHREAD_H */
include/linux/workqueue.h +1 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12121-linux-2.6.1-rc1-bk6/include/linux/workqueue.h .12121-linux-2.6.1-rc1-bk6.updated/include/linux/workqueue.h
@@ -60,6 +60,7 @@ extern int FASTCALL(schedule_work(struct
 extern int FASTCALL(schedule_delayed_work(struct work_struct *work, unsigned long delay));
 extern void flush_scheduled_work(void);
 extern int current_is_keventd(void);
+extern int keventd_up(void);
 
 extern void init_workqueues(void);
 
kernel/Makefile +2 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12121-linux-2.6.1-rc1-bk6/kernel/Makefile .12121-linux-2.6.1-rc1-bk6.updated/kernel/Makefile
@@ -6,7 +6,8 @@ obj-y     = sched.o fork.o exec_domain.o
 	    exit.o itimer.o time.o softirq.o resource.o \
 	    sysctl.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o workqueue.o pid.o \
-	    rcupdate.o intermodule.o extable.o params.o posix-timers.o
+	    rcupdate.o intermodule.o extable.o params.o posix-timers.o \
+	    kthread.o
 
 obj-$(CONFIG_FUTEX) += futex.o
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
kernel/kthread.c +171 -0

171 lines not on this page · raw message

kernel/workqueue.c +5 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12121-linux-2.6.1-rc1-bk6/kernel/workqueue.c .12121-linux-2.6.1-rc1-bk6.updated/kernel/workqueue.c
@@ -347,6 +347,11 @@ void flush_scheduled_work(void)
 	flush_workqueue(keventd_wq);
 }
 
+int keventd_up(void)
+{
+	return keventd_wq != NULL;
+}
+
 int current_is_keventd(void)
 {
 	struct cpu_workqueue_struct *cwq;