Skip to contentSkip to conversation

2.4, maintenance mode, and workqueues

RFC PATCH New Jeff Garzik 1 participant 1 message Oct 22, 2004

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 2.4, maintenance mode, and workqueues

One thing that would make my life a lot easier, before 2.4 goes into "deep maintenance" mode, would be the addition of workqueues (kthread.c and workqueue.c).

Doing so would go a long way towards making drivers more portable, since the kthread/wq stuff eliminates a lot of the task/signal mess that a driver really shouldn't have to care about.

The interfaces are pretty self-contained, as is shown by the attached patch (_not_ for application).

Jeff

# This is a BitKeeper generated diff -Nru style patch. #
# ChangeSet
# 2004/10/21 21:15:43-04:00 [email protected]
# Add kthread/workqueue APIs.
#

# kernel/workqueue.c
#   2004/10/21 21:15:41-04:00 [email protected] +528 -0
# 
# kernel/kthread.c
#   2004/10/21 21:15:41-04:00 [email protected] +184 -0
# 
# include/linux/workqueue.h
#   2004/10/21 21:15:41-04:00 [email protected] +89 -0
# 
# include/linux/kthread.h
#   2004/10/21 21:15:41-04:00 [email protected] +81 -0
# 
# kernel/workqueue.c
#   2004/10/21 21:15:41-04:00 [email protected] +0 -0
#   BitKeeper file /garz/repo/kthread-2.4/kernel/workqueue.c
# 
# kernel/sched.c
#   2004/10/21 21:15:41-04:00 [email protected] +11 -0
#   Add kthread/workqueue APIs.
# 
# kernel/kthread.c
#   2004/10/21 21:15:41-04:00 [email protected] +0 -0
#   BitKeeper file /garz/repo/kthread-2.4/kernel/kthread.c
# 
# kernel/ksyms.c
#   2004/10/21 21:15:41-04:00 [email protected] +1 -0
#   Add kthread/workqueue APIs.
# 
# kernel/Makefile
#   2004/10/21 21:15:41-04:00 [email protected] +3 -2
#   Add kthread/workqueue APIs.
# 
# include/linux/workqueue.h
#   2004/10/21 21:15:41-04:00 [email protected] +0 -0
#   BitKeeper file /garz/repo/kthread-2.4/include/linux/workqueue.h
# 
# include/linux/timer.h
#   2004/10/21 21:15:41-04:00 [email protected] +12 -0
#   Add kthread/workqueue APIs.
# 
# include/linux/smp.h
#   2004/10/21 21:15:41-04:00 [email protected] +11 -3
#   Add kthread/workqueue APIs.
# 
# include/linux/sched.h
#   2004/10/21 21:15:41-04:00 [email protected] +3 -1
#   Add kthread/workqueue APIs.
# 
# include/linux/kthread.h
#   2004/10/21 21:15:41-04:00 [email protected] +0 -0
#   BitKeeper file /garz/repo/kthread-2.4/include/linux/kthread.h
# 
diff -Nru a/include/linux/kthread.h b/include/linux/kthread.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/include/linux/kthread.h	2004-10-21 21:15:58 -04:00
@@ -0,0 +1,81 @@
+#ifndef _LINUX_KTHREAD_H
+#define _LINUX_KTHREAD_H
+/* Simple interface for creating and stopping kernel threads without mess. */
+#include <linux/fs.h>
+#include <linux/sched.h>
+
+/**
+ * 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 wake_up_process() to start
+ * it.  See also kthread_run(), kthread_create_on_cpu().
+ *
+ * When woken, the thread will run @threadfn() with @data as its
+ * argument. @threadfn can either call do_exit() directly if it is a
+ * standalone thread for which noone will call kthread_stop(), or
+ * return when 'kthread_should_stop()' 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().
+ *
+ * Returns a task_struct or ERR_PTR(-ENOMEM).
+ */
+struct task_struct *kthread_create(int (*threadfn)(void *data),
+				   void *data,
+				   const char namefmt[], ...);
+
+/**
+ * kthread_run: create and wake 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
+ * wake_up_process().  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))						   \
+		wake_up_process(__k);					   \
+	__k;								   \
+})
+
+/**
+ * kthread_bind: bind a just-created kthread to a cpu.
+ * @k: thread created by kthread_create().
+ * @cpu: cpu (might not be online, must be possible) for @k to run on.
+ *
+ * Description: This function is equivalent to set_cpus_allowed(),
+ * except that @cpu doesn't need to be online, and the thread must be
+ * stopped (ie. just returned from kthread_create().
+ */
+void kthread_bind(struct task_struct *k, unsigned int cpu);
+
+/**
+ * kthread_stop: stop a thread created by kthread_create().
+ * @k: thread created by kthread_create().
+ *
+ * Sets kthread_should_stop() for @k to return true, wakes it, 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 wake_up_process(): the thread
+ * will exit without calling threadfn().
+ *
+ * Returns the result of threadfn(), or -EINTR if wake_up_process()
+ * was never called. */
+int kthread_stop(struct task_struct *k);
+
+/**
+ * kthread_should_stop: should this kthread return now?
+ *
+ * When someone calls kthread_stop on your kthread, it will be woken
+ * and this will return true.  You should then return, and your return
+ * value will be passed through to kthread_stop().
+ */
+int kthread_should_stop(void);
+
+#endif /* _LINUX_KTHREAD_H */
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	2004-10-21 21:15:58 -04:00
+++ b/include/linux/sched.h	2004-10-21 21:15:58 -04:00
@@ -135,6 +135,8 @@
 extern spinlock_t runqueue_lock;
 extern spinlock_t mmlist_lock;

+typedef struct task_struct task_t;
+
extern void sched_init(void);
extern void init_idle(void);
extern void show_state(void);
@@ -143,7 +145,7 @@
extern void update_process_times(int user);
extern void update_one_process(struct task_struct *p, unsigned long user,
unsigned long system, int cpu);
-
+extern void set_user_nice(struct task_struct *p, long nice);
#define MAX_SCHEDULE_TIMEOUT LONG_MAX
extern signed long FASTCALL(schedule_timeout(signed long timeout)); asmlinkage void schedule(void);

include/linux/smp.h +11 -3
diff -Nru a/include/linux/smp.h b/include/linux/smp.h
@@ -71,7 +71,7 @@
 #define MSG_RESCHEDULE		0x0003	/* Reschedule request from master CPU*/
 #define MSG_CALL_FUNCTION       0x0004  /* Call function on all other CPUs */
 
-#else
+#else /* !SMP */
 
 /*
  *	These macros fold the SMP functionality into a single CPU system
@@ -87,5 +87,13 @@
 #define smp_call_function(func,info,retry,wait)	({ 0; })
 #define cpu_online_map				1
 
-#endif
-#endif
+#endif /* !SMP */
+
+#define get_cpu()	({ smp_processor_id(); })
+#define put_cpu()	do {} while (0)
+#define lock_cpu_hotplug()	do {} while (0)
+#define unlock_cpu_hotplug()	do {} while (0)
+#define for_each_online_cpu(cpu)	\
+	for ((cpu) = 0; (cpu) < smp_num_cpus; (cpu)++)
+
+#endif /* __LINUX_SMP_H */
include/linux/timer.h +12 -0
diff -Nru a/include/linux/timer.h b/include/linux/timer.h
@@ -20,8 +20,20 @@
 	void (*function)(unsigned long);
 };
 
+#define TIMER_INITIALIZER(_function, _expires, _data) {         \
+		.function = (_function),                        \
+		.expires = (_expires),                          \
+		.data = (_data),                                \
+		.list = { NULL, NULL },				\
+	}
+
 extern void add_timer(struct timer_list * timer);
 extern int del_timer(struct timer_list * timer);
+
+static inline void add_timer_on(struct timer_list *timer, int cpu)
+{
+	add_timer(timer);
+}
 
 #ifdef CONFIG_SMP
 extern int del_timer_sync(struct timer_list * timer);
include/linux/workqueue.h new file +89 -0

89 lines not on this page · raw message

kernel/Makefile +3 -2
diff -Nru a/kernel/Makefile b/kernel/Makefile
@@ -9,12 +9,13 @@
 
 O_TARGET := kernel.o
 
-export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.o
+export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \
+	      printk.o kthread.o workqueue.o
 
 obj-y     = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
 	    module.o exit.o itimer.o info.o time.o softirq.o resource.o \
 	    sysctl.o acct.o capability.o ptrace.o timer.o user.o \
-	    signal.o sys.o kmod.o context.o
+	    signal.o sys.o kmod.o context.o kthread.o workqueue.o
 
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += ksyms.o
kernel/ksyms.c +1 -0
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
@@ -478,6 +478,7 @@
 EXPORT_SYMBOL(xtime);
 EXPORT_SYMBOL(do_gettimeofday);
 EXPORT_SYMBOL(do_settimeofday);
+EXPORT_SYMBOL(set_user_nice);
 
 #if !defined(__ia64__)
 EXPORT_SYMBOL(loops_per_jiffy);
kernel/kthread.c new file +184 -0

184 lines not on this page · raw message

kernel/sched.c +11 -0
diff -Nru a/kernel/sched.c b/kernel/sched.c
@@ -1350,6 +1350,17 @@
 	atomic_inc(&current->files->count);
 }
 
+void set_user_nice(struct task_struct *p, long nice)
+{
+	if (nice < -20)
+		nice = -20;
+	if (nice > 19)
+		nice = 19;
+	write_lock(&tasklist_lock);
+	p->nice = nice;
+	write_unlock(&tasklist_lock);
+}
+
 extern unsigned long wait_init_idle;
 
 void __init init_idle(void)
kernel/workqueue.c new file +528 -0

528 lines not on this page · raw message