Skip to contentSkip to conversation

set_cpus_allowed() for 2.4

PATCH In review Robert Love 5 participants 10 messages Oct 1, 2002 – Dec 2, 2002 Scheduler

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 set_cpus_allowed() for 2.4

The following patch implements set_cpus_allowed() for stock 2.4 without the O(1) scheduler.

The calling semantics and behavior remain the same as 2.5's method.

This is to provide a backward-compatible interface, specifically for those interested in back-porting the new workqueue code to 2.4 - set_cpus_allowed() seems to be the only nit preventing a straight drop-in.

Patch is against 2.4.20-pre8 and untested but does compile.

Robert Love

include/linux/sched.h +6 -0
diff -urN linux-2.4.20-pre8/include/linux/sched.h linux/include/linux/sched.h
@@ -163,6 +164,12 @@
 extern int start_context_thread(void);
 extern int current_is_keventd(void);
 
+#if CONFIG_SMP
+extern void set_cpus_allowed(struct task_struct *p, unsigned long new_mask);
+#else
+# define set_cpus_allowed(p, new_mask) do { } while (0)
+#endif
+
 /*
  * The default fd array needs to be at least BITS_PER_LONG,
  * as this is the granularity returned by copy_fdset().
kernel/ksyms.c +3 -0
diff -urN linux-2.4.20-pre8/kernel/ksyms.c linux/kernel/ksyms.c
@@ -451,6 +451,9 @@
 EXPORT_SYMBOL(interruptible_sleep_on_timeout);
 EXPORT_SYMBOL(schedule);
 EXPORT_SYMBOL(schedule_timeout);
+#if CONFIG_SMP
+EXPORT_SYMBOL(set_cpus_allowed);
+#endif
 EXPORT_SYMBOL(yield);
 EXPORT_SYMBOL(__cond_resched);
 EXPORT_SYMBOL(jiffies);
kernel/sched.c +40 -0
diff -urN linux-2.4.20-pre8/kernel/sched.c linux/kernel/sched.c
@@ -850,6 +850,46 @@
 
 void scheduling_functions_end_here(void) { }
 
+#if CONFIG_SMP
+
+/**
+ * set_cpus_allowed() - change a given task's processor affinity
+ * @p: task to bind
+ * @new_mask: bitmask of allowed processors
+ *
+ * Upon return, the task is running on a legal processor.  Note the caller
+ * must have a valid reference to the task: it must not exit() prematurely.
+ * This call can sleep; do not hold locks on call.
+ */
+void set_cpus_allowed(struct task_struct *p, unsigned long new_mask)
+{
+	new_mask &= cpu_online_map;
+	BUG_ON(!new_mask);
+
+	p->cpus_allowed = new_mask;
+
+	/*
+	 * If the task is on a no-longer-allowed processor, we need to move
+	 * it.  If the task is not current, then set need_resched and send
+	 * its processor an IPI to reschedule.
+	 */
+	if (!(p->cpus_runnable & p->cpus_allowed)) {
+		if (p != current) {
+			p->need_resched = 1;
+			smp_send_reschedule(p->processor);
+		}
+		/*
+		 * Wait until we are on a legal processor.  If the task is
+		 * current, then we should be on a legal processor the next
+		 * time we reschedule.  Otherwise, we need to wait for the IPI.
+		 */
+		while (!(p->cpus_runnable & p->cpus_allowed))
+			schedule();
+	}
+}
+
+#endif /* CONFIG_SMP */
+
 #ifndef __alpha__
 
 /*
kernel/softirq.c +2 -3
diff -urN linux-2.4.20-pre8/kernel/softirq.c linux/kernel/softirq.c
@@ -368,9 +368,8 @@
 	sigfillset(&current->blocked);
 
 	/* Migrate to the right CPU */
-	current->cpus_allowed = 1UL << cpu;
-	while (smp_processor_id() != cpu)
-		schedule();
+	set_cpus_allowed(current, 1UL << cpu);
+	BUG_ON(smp_processor_id() != cpu);
 
 	sprintf(current->comm, "ksoftirqd_CPU%d", bind_cpu);
 
#1 lore raw
Quoted 11 lines · Robert Love

The following patch implements set_cpus_allowed() for stock 2.4 without the O(1) scheduler.

The calling semantics and behavior remain the same as 2.5's method.

This is to provide a backward-compatible interface, specifically for those interested in back-porting the new workqueue code to 2.4 - set_cpus_allowed() seems to be the only nit preventing a straight drop-in.

Patch is against 2.4.20-pre8 and untested but does compile.

Patch looks good to me, and I'd really like to have it in XFS :) BTW, now that you have the core functionality I wonder why you don't also add the cpu affinity syscalls..

#2 lore raw
Quoted 1 line · Christoph Hellwig

Patch looks good to me, and I'd really like to have it in XFS :)

Good :)

Quoted 2 lines

BTW, now that you have the core functionality I wonder why you don't also add the cpu affinity syscalls..

I already wrote them for 2.4, although I guess I should redo them for the new set_cpus_allowed()... I have been waiting to send them to Marcelo to ensure the 2.5 interfaces were solid and did not change. As we approach the feature freeze, I guess we are getting there.

Robert Love

#3 lore raw
In reply to Robert Love

Hi Marcelo,

now that all vendors ship a backport of Ingo's O(1) scheduler external projects like XFS have to track those projects in addition to the mainline kernel.

Having the common new APIs available in mainline would be a very good think for thos projects. We already have a proper yield() in 2.4.20, but the set_cpus_allowed() API used e.g. for kernelthreads bound to CPUs is still missing.

Any chance you could apply Robert Love's patch to add it for 2.4.20-rc2? Note that it does not change any existing code but just adds that interface.

include/linux/sched.h +6 -0
diff -urN linux-2.4.20-pre8/include/linux/sched.h linux/include/linux/sched.h
@@ -163,6 +164,12 @@
 extern int start_context_thread(void);
 extern int current_is_keventd(void);
 
+#if CONFIG_SMP
+extern void set_cpus_allowed(struct task_struct *p, unsigned long new_mask);
+#else
+# define set_cpus_allowed(p, new_mask) do { } while (0)
+#endif
+
 /*
  * The default fd array needs to be at least BITS_PER_LONG,
  * as this is the granularity returned by copy_fdset().
kernel/ksyms.c +3 -0
diff -urN linux-2.4.20-pre8/kernel/ksyms.c linux/kernel/ksyms.c
@@ -451,6 +451,9 @@
 EXPORT_SYMBOL(interruptible_sleep_on_timeout);
 EXPORT_SYMBOL(schedule);
 EXPORT_SYMBOL(schedule_timeout);
+#if CONFIG_SMP
+EXPORT_SYMBOL(set_cpus_allowed);
+#endif
 EXPORT_SYMBOL(yield);
 EXPORT_SYMBOL(__cond_resched);
 EXPORT_SYMBOL(jiffies);
kernel/sched.c +40 -0
diff -urN linux-2.4.20-pre8/kernel/sched.c linux/kernel/sched.c
@@ -850,6 +850,46 @@
 
 void scheduling_functions_end_here(void) { }
 
+#if CONFIG_SMP
+
+/**
+ * set_cpus_allowed() - change a given task's processor affinity
+ * @p: task to bind
+ * @new_mask: bitmask of allowed processors
+ *
+ * Upon return, the task is running on a legal processor.  Note the caller
+ * must have a valid reference to the task: it must not exit() prematurely.
+ * This call can sleep; do not hold locks on call.
+ */
+void set_cpus_allowed(struct task_struct *p, unsigned long new_mask)
+{
+	new_mask &= cpu_online_map;
+	BUG_ON(!new_mask);
+
+	p->cpus_allowed = new_mask;
+
+	/*
+	 * If the task is on a no-longer-allowed processor, we need to move
+	 * it.  If the task is not current, then set need_resched and send
+	 * its processor an IPI to reschedule.
+	 */
+	if (!(p->cpus_runnable & p->cpus_allowed)) {
+		if (p != current) {
+			p->need_resched = 1;
+			smp_send_reschedule(p->processor);
+		}
+		/*
+		 * Wait until we are on a legal processor.  If the task is
+		 * current, then we should be on a legal processor the next
+		 * time we reschedule.  Otherwise, we need to wait for the IPI.
+		 */
+		while (!(p->cpus_runnable & p->cpus_allowed))
+			schedule();
+	}
+}
+
+#endif /* CONFIG_SMP */
+
 #ifndef __alpha__
 
 /*
#4 lore raw
Quoted 3 lines · Christoph Hellwig

...
now that all vendors ship a backport of Ingo's O(1) scheduler external projects
...

Your "all vendors" doesn't include Debian?

cu
Adrian

Signature · 4 lines
       "Is there not promise of rain?" Ling Tan asked suddenly out
        of the darkness. There had been need of rain for many days.
       "Only a promise," Lao Er said.
                                       Pearl S. Buck - Dragon Seed
#5 lore raw
Quoted 6 lines · Adrian Bunk
Quoted 3 lines · Christoph Hellwig

...
now that all vendors ship a backport of Ingo's O(1) scheduler external projects
...

Your "all vendors" doesn't include Debian?

No. Replace all vendors with all commercial vendors or all recently releaseased distribution :)

#6 lore raw
In reply to Christoph Hellwig
Quoted 16 lines · Christoph Hellwig
kernel/sched.c +16 -0
+void set_cpus_allowed(struct task_struct *p, unsigned long new_mask)
+{
+	new_mask &= cpu_online_map;
+	BUG_ON(!new_mask);
+
+	p->cpus_allowed = new_mask;
+
+	/*
+	 * If the task is on a no-longer-allowed processor, we need to move
+	 * it.  If the task is not current, then set need_resched and send
+	 * its processor an IPI to reschedule.
+	 */
+	if (!(p->cpus_runnable & p->cpus_allowed)) {
+		if (p != current) {
+			p->need_resched = 1;
+			smp_send_reschedule(p->processor);

kernel/sched.c line 889

Quoted 10 lines
kernel/sched.c +10 -0
+		}
+		/*
+		 * Wait until we are on a legal processor.  If the task is
+		 * current, then we should be on a legal processor the next
+		 * time we reschedule.  Otherwise, we need to wait for the IPI.
+		 */
+		while (!(p->cpus_runnable & p->cpus_allowed))
+			schedule();
+	}
+}

Is this implementation of set_cpus_allowed() Ok for all 2.4 kernels, even if they (like RH8.0's) use a non-vanilla scheduler?

I'm asking because I need to put a set_cpus_allowed() implementation in my performance counters driver's compat layer. If it makes any difference, I'll only use set_cpus_allowed(p, new_mask) when p == current or p is stopped and under ptrace() control by current.

/Mikael

#7 lore raw
Quoted 2 lines · Mikael Pettersson

Is this implementation of set_cpus_allowed() Ok for all 2.4 kernels, even if they (like RH8.0's) use a non-vanilla scheduler?

No, it's for the stock scheduler. But RH8.0 already has set_cpus_allowed().

#8 lore raw
Quoted 5 lines · Christoph Hellwig
Quoted 2 lines · Mikael Pettersson

Is this implementation of set_cpus_allowed() Ok for all 2.4 kernels, even if they (like RH8.0's) use a non-vanilla scheduler?

No, it's for the stock scheduler. But RH8.0 already has set_cpus_allowed().

I knew RH8.0 has set_cpus_allowed(), but I wanted to avoid having to check for being compiled in a RH-hacked kernel. LINUX_VERSION_CODE doesn't distinguish between standard and "with tons of vendor-specific changes" :-(

I'll use your code then on stock 2.4 kernels, and work out some kludge for the RH case.

Thanks,

/Mikael

#9 lore raw
Quoted 6 lines · Mikael Pettersson

I knew RH8.0 has set_cpus_allowed(), but I wanted to avoid having to check for being compiled in a RH-hacked kernel. LINUX_VERSION_CODE doesn't distinguish between standard and "with tons of vendor-specific changes" :-(

I'll use your code then on stock 2.4 kernels, and work out some kludge for the RH case.

The code only works on the stock scheduler. It is the same interface and has the same behavior as the O(1) scheduler version, but the code is very very different.

If this patch is merged, you can safely use set_cpus_allowed() in either kernel (which is the intention). But you cannot use this routine's code on either scheduler.

Robert Love