Second Coming of Kthread
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
@@ -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
@@ -60,6 +60,7 @@ extern int FASTCALL(schedule_work(structextern 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
@@ -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
@@ -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;