Name: Fake Schedule for Another CPU Status: Works for Me Signed-off-by: Rusty Russell (authored) This patch tries to implement scheduling for another CPU, in the case where it can't do it for itself. diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .19777-linux-2.6.8-rc2-bk1/arch/i386/kernel/Makefile .19777-linux-2.6.8-rc2-bk1.updated/arch/i386/kernel/Makefile --- .19777-linux-2.6.8-rc2-bk1/arch/i386/kernel/Makefile 2004-07-21 01:10:14.000000000 +1000 +++ .19777-linux-2.6.8-rc2-bk1.updated/arch/i386/kernel/Makefile 2004-07-24 06:22:30.000000000 +1000 @@ -7,7 +7,7 @@ extra-y := head.o init_task.o vmlinux.ld obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \ - doublefault.o + doublefault.o fake_sched.o obj-y += cpu/ obj-y += timers/ diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .19777-linux-2.6.8-rc2-bk1/arch/i386/kernel/fake_sched.c .19777-linux-2.6.8-rc2-bk1.updated/arch/i386/kernel/fake_sched.c --- .19777-linux-2.6.8-rc2-bk1/arch/i386/kernel/fake_sched.c 1970-01-01 10:00:00.000000000 +1000 +++ .19777-linux-2.6.8-rc2-bk1.updated/arch/i386/kernel/fake_sched.c 2004-07-25 02:28:08.000000000 +1000 @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include + +unsigned int fake_id; + +int smp_processor_id(void) +{ + if (fake_id && !in_irq()) + return fake_id; + return current_thread_info()->cpu; +} +EXPORT_SYMBOL(smp_processor_id); + +static int threadfn(void *data) +{ + do { + printk("XXX About to schedule...\n"); + fake_id = 1; + schedule(); + fake_id = 0; + printk("XXX Sleeping...\n"); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(10*HZ); + } while(1); +} + +static int neverrun(void *data) +{ + BUG(); + return 1; +} + +struct task_struct *fork_by_hand(void); +void push_thread_onto_cpu(struct task_struct *p); + +static int fake_sched_thread(void) +{ + struct task_struct *k, *idle; + + /* Create an idle task for the other guy. */ + idle = fork_by_hand(); + if (IS_ERR(idle)) + panic("failed fork for CPU %d", 1); + wake_up_forked_process(idle); + idle->active_mm = &init_mm; + init_idle(idle, 1); + + /* Create something to switch to. */ + k = kthread_create(neverrun, NULL, "neverrun"); + kthread_bind(k, 1); + push_thread_onto_cpu(k); + + k = kthread_run(threadfn, NULL, "fakesched"); + if (IS_ERR(k)) + return PTR_ERR(k); + return 0; +} + +__initcall(fake_sched_thread); diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .19777-linux-2.6.8-rc2-bk1/arch/i386/kernel/smpboot.c .19777-linux-2.6.8-rc2-bk1.updated/arch/i386/kernel/smpboot.c --- .19777-linux-2.6.8-rc2-bk1/arch/i386/kernel/smpboot.c 2004-07-21 01:10:15.000000000 +1000 +++ .19777-linux-2.6.8-rc2-bk1.updated/arch/i386/kernel/smpboot.c 2004-07-25 02:15:34.000000000 +1000 @@ -492,7 +492,7 @@ extern struct { unsigned short ss; } stack_start; -static struct task_struct * __init fork_by_hand(void) +struct task_struct * __init fork_by_hand(void) { struct pt_regs regs; /* @@ -1384,6 +1384,9 @@ void __init smp_cpus_done(unsigned int m * Disable executability of the SMP trampoline: */ set_kernel_exec((unsigned long)trampoline_base, trampoline_exec); + + /* Pretend we have a second CPU possible. */ + cpu_set(1, cpu_possible_map); } void __init smp_intr_init(void) diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .19777-linux-2.6.8-rc2-bk1/include/asm-i386/smp.h .19777-linux-2.6.8-rc2-bk1.updated/include/asm-i386/smp.h --- .19777-linux-2.6.8-rc2-bk1/include/asm-i386/smp.h 2004-06-17 08:49:17.000000000 +1000 +++ .19777-linux-2.6.8-rc2-bk1.updated/include/asm-i386/smp.h 2004-07-24 06:18:40.000000000 +1000 @@ -49,7 +49,7 @@ extern void zap_low_mappings (void); * from the initial startup. We map APIC_BASE very early in page_setup(), * so this is correct in the x86 case. */ -#define smp_processor_id() (current_thread_info()->cpu) +extern int smp_processor_id(void); extern cpumask_t cpu_callout_map; #define cpu_possible_map cpu_callout_map diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .19777-linux-2.6.8-rc2-bk1/include/asm-i386/system.h .19777-linux-2.6.8-rc2-bk1.updated/include/asm-i386/system.h --- .19777-linux-2.6.8-rc2-bk1/include/asm-i386/system.h 2004-07-21 01:11:12.000000000 +1000 +++ .19777-linux-2.6.8-rc2-bk1.updated/include/asm-i386/system.h 2004-07-24 06:17:19.000000000 +1000 @@ -12,8 +12,11 @@ struct task_struct; /* one of the stranger aspects of C forward declarations.. */ extern struct task_struct * FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next)); +extern unsigned int fake_id; #define switch_to(prev,next,last) do { \ unsigned long esi,edi; \ + if (fake_id) printk("Fake switch for %i\n", fake_id); \ + else \ asm volatile("pushfl\n\t" \ "pushl %%ebp\n\t" \ "movl %%esp,%0\n\t" /* save ESP */ \ diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .19777-linux-2.6.8-rc2-bk1/kernel/sched.c .19777-linux-2.6.8-rc2-bk1.updated/kernel/sched.c --- .19777-linux-2.6.8-rc2-bk1/kernel/sched.c 2004-07-21 01:11:20.000000000 +1000 +++ .19777-linux-2.6.8-rc2-bk1.updated/kernel/sched.c 2004-07-25 02:28:59.000000000 +1000 @@ -960,6 +960,15 @@ void fastcall wake_up_forked_process(tas task_rq_unlock(rq, &flags); } +void push_thread_onto_cpu(struct task_struct *p) +{ + unsigned long flags; + runqueue_t *rq = task_rq_lock(p, &flags); + + __activate_task(p, rq); + task_rq_unlock(rq, &flags); +} + /* * Potentially available exiting-child timeslices are * retrieved here - this way the parent does not get @@ -1796,6 +1805,7 @@ static inline void idle_balance(int this { struct sched_domain *sd; +#if 0 for_each_domain(this_cpu, sd) { if (sd->flags & SD_BALANCE_NEWIDLE) { if (load_balance_newidle(this_cpu, this_rq, sd)) { @@ -1804,6 +1814,7 @@ static inline void idle_balance(int this } } } +#endif } /* @@ -2206,8 +2217,8 @@ asmlinkage void __sched schedule(void) need_resched: preempt_disable(); - prev = current; rq = this_rq(); + prev = rq->curr; release_kernel_lock(prev); now = sched_clock(); @@ -3912,6 +3923,11 @@ void __init sched_init(void) runqueue_t *rq; int i, j, k; + printk("idle for %i: ->mm = %p, ->active_mm = %p\n", + smp_processor_id(), + cpu_rq(smp_processor_id())->idle->mm, + cpu_rq(smp_processor_id())->idle->active_mm); + #ifdef CONFIG_SMP /* Set up an initial dummy domain for early boot */ static struct sched_domain sched_domain_init;