Skip to contentSkip to conversation

Use kthread primitives

PATCH In review Rusty Russell 1 participant 1 message Dec 31, 2003 Workqueue

lore
Share & tools
lore
#0 lore raw

PATCH 2/2 Use kthread primitives

And this is the patch actually uses the kthread primitives, simplifying and shrinking the code a little bit.

Name: Use Kthread For Core Kernel Threads
Author: Rusty Russell
Status: Tested on 2.6.0-bk3
Depends: Hotcpu/kthread.patch.gz

D: This simply changes over the migration threads, the workqueue
D: threads and the ksoftirqd threads to use kthread. D:

D: Changes:
D:  - kernel/sched.c: Split migration_thread() into
D:    migration_kthread_init() and migration_kthread() for use with
D:    kthread.  Simplifies startup greatly.
D:    - No need for migration_startup_t.
D: 
D:  - kernel/softirq.c: Split ksoftirqd() into ksoftirqd_init() and
D:    ksoftirqd(). 
D: 
D:  - kernel/workqueue.c: Split worker_thread() into worker_thread_init()
D:    and worker_thread(). 
D:    - Change waitqueue to task pointer (we need it anyway, and there's
D:      always only one).
D:    - Remove exit completion (kthread_destroy handles that for us).
D:    - Make create_workqueue_thread() return a task struct directly,
D:      since kthread_create gives us that without needing to use
D:      a structure for the thread to put it in.
kernel/sched.c +42 -55
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .27587-2.6.0-bk3-use-kthread.pre/kernel/sched.c .27587-2.6.0-bk3-use-kthread/kernel/sched.c
@@ -37,6 +37,7 @@
 #include <linux/rcupdate.h>
 #include <linux/cpu.h>
 #include <linux/percpu.h>
+#include <linux/kthread.h>
 
 #ifdef CONFIG_NUMA
 #define cpu_to_node_mask(cpu) node_to_cpumask(cpu_to_node(cpu))
@@ -2640,64 +2641,54 @@ static void move_task_away(struct task_s
 	local_irq_restore(flags);
 }
 
-typedef struct {
-	int cpu;
-	struct completion startup_done;
-	task_t *task;
-} migration_startup_t;
-
 /*
  * migration_thread - this is a highprio system thread that performs
  * thread migration by bumping thread off CPU then 'pushing' onto
  * another runqueue.
  */
-static int migration_thread(void * data)
+static int migration_kthread_init(void *data)
 {
 	/* Marking "param" __user is ok, since we do a set_fs(KERNEL_DS); */
 	struct sched_param __user param = { .sched_priority = MAX_RT_PRIO-1 };
-	migration_startup_t *startup = data;
-	int cpu = startup->cpu;
-	runqueue_t *rq;
-	int ret;
-
-	startup->task = current;
-	complete(&startup->startup_done);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule();
+	unsigned int cpu = (long)data;
 
 	BUG_ON(smp_processor_id() != cpu);
 
-	daemonize("migration/%d", cpu);
 	set_fs(KERNEL_DS);
 
-	ret = setscheduler(0, SCHED_FIFO, &param);
-
-	rq = this_rq();
-	rq->migration_thread = current;
+	setscheduler(0, SCHED_FIFO, &param);
+	return 0;
+}
 
-	for (;;) {
-		struct list_head *head;
-		migration_req_t *req;
+static int migration_kthread(void *data)
+{
+	runqueue_t *rq;
+	struct list_head *head;
+	migration_req_t *req;
 
-		if (current->flags & PF_FREEZE)
-			refrigerator(PF_IOTHREAD);
+	rq = this_rq();
 
-		spin_lock_irq(&rq->lock);
-		head = &rq->migration_queue;
-		current->state = TASK_INTERRUPTIBLE;
-		if (list_empty(head)) {
-			spin_unlock_irq(&rq->lock);
-			schedule();
-			continue;
-		}
+	spin_lock_irq(&rq->lock);
+	head = &rq->migration_queue;
+	while (!list_empty(head)) {
 		req = list_entry(head->next, migration_req_t, list);
 		list_del_init(head->next);
-		spin_unlock_irq(&rq->lock);
 
+		spin_unlock_irq(&rq->lock);
 		move_task_away(req->task,
 			       any_online_cpu(req->task->cpus_allowed));
 		complete(&req->done);
+		spin_lock_irq(&rq->lock);
+		current->state = TASK_INTERRUPTIBLE;
 	}
+	current->state = TASK_INTERRUPTIBLE;
+	spin_unlock_irq(&rq->lock);
+
+	/* FIXME: Should this be in kthread.c? --RR */
+	if (current->flags & PF_FREEZE)
+		refrigerator(PF_IOTHREAD);
+
+	return 0;
 }
 
 /*
@@ -2709,35 +2700,31 @@ static int migration_call(struct notifie
 			  void *hcpu)
 {
 	long cpu = (long) hcpu;
-	migration_startup_t startup;
+	struct task_struct *p;
 
 	switch (action) {
 	case CPU_ONLINE:
-
 		printk("Starting migration thread for cpu %li\n", cpu);
-
-		startup.cpu = cpu;
-		startup.task = NULL;
-		init_completion(&startup.startup_done);
-
-		kernel_thread(migration_thread, &startup, CLONE_KERNEL);
-		wait_for_completion(&startup.startup_done);
-		wait_task_inactive(startup.task);
-
-		startup.task->thread_info->cpu = cpu;
-		startup.task->cpus_allowed = cpumask_of_cpu(cpu);
-
-		wake_up_process(startup.task);
-
-		while (!cpu_rq(cpu)->migration_thread)
-			yield();
-
+		p = kthread_create(migration_kthread_init, migration_kthread,
+				   hcpu, "migration/%ld", cpu);
+		if (IS_ERR(p))
+			return NOTIFY_BAD;
+		/* Manually bind to CPU: thread stopped, so this is OK. */
+		p->thread_info->cpu = cpu;
+		p->cpus_allowed = cpumask_of_cpu(cpu);
+		if (IS_ERR(kthread_start(p)))
+			return NOTIFY_BAD;
+		cpu_rq(cpu)->migration_thread = p;
 		break;
 	}
 	return NOTIFY_OK;
 }
 
-static struct notifier_block migration_notifier = { &migration_call, NULL, 0 };
+/* Want this before the other threads, so they can use set_cpus_allowed. */
+static struct notifier_block __devinitdata migration_notifier = { 
+	.notifier_call = migration_call,
+	.priority = 10,
+};
 
 __init int migration_init(void)
 {
kernel/softirq.c +22 -26

79 lines not on this page · raw message

kernel/workqueue.c +53 -84

224 lines not on this page · raw message

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