From 949ce5e04b64f4ddc1a0e1a101f0f838c16f5492 Mon Sep 17 00:00:00 2001 From: Jonathan Herman Date: Tue, 14 Feb 2012 16:34:43 -0500 Subject: Further refinements --- litmus/sched_pdumb.c | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/litmus/sched_pdumb.c b/litmus/sched_pdumb.c index c4a123475160..af1076dc9be0 100644 --- a/litmus/sched_pdumb.c +++ b/litmus/sched_pdumb.c @@ -19,8 +19,11 @@ struct dumb_cpu { int blocked; raw_spinlock_t lock; }; + /* Define AND initialize one dumb_cpu per CPU. * Use of this macro is good for safety and performance reasons. + * Beware: this macro creates global variables. If two plugins pick + * the same name here, this will not compile. */ DEFINE_PER_CPU(struct dumb_cpu, pdumb_cpus); @@ -40,7 +43,7 @@ static long pdumb_activate_plugin(void) cpu = &per_cpu(pdumb_cpus, i); cpu->dumb_task = NULL; cpu->scheduled = 0; - cpu->blocked = 0; + cpu->blocked = 0; } printk(KERN_ERR "Activated a dumb plugin!\n"); @@ -55,6 +58,7 @@ static long pdumb_activate_plugin(void) static long pdumb_admit_task(struct task_struct *t) { long ret; + unsigned long flags; int cpu_num = get_partition(t); /* Per CPU variables have to be accessed wierd. @@ -62,22 +66,23 @@ static long pdumb_admit_task(struct task_struct *t) */ struct dumb_cpu *cpu = &per_cpu(pdumb_cpus, cpu_num); - raw_spin_lock(&cpu->lock); + /* We are accessing state atomically, we need a lock and to + * disable irqs. + */ + raw_spin_lock_irqsave(&cpu->lock, flags); if (cpu->dumb_task) { - printk(KERN_ERR "Already have a dumb task on %d!\n", - cpu_num); + /* Reject the task, causing a failure in userspace */ + printk(KERN_ERR "Already have a dumb task on %d!\n", cpu_num); ret = -EINVAL; } else { - printk(KERN_ERR "Taking your dumb task on %d!\n", - cpu_num); - - /* Assign our dumb task! */ + /* Assign our dumb task */ + printk(KERN_ERR "Taking your dumb task on %d!\n", cpu_num); cpu->dumb_task = t; ret = 0; } - raw_spin_unlock(&cpu->lock); + raw_spin_unlock_irqrestore(&cpu->lock, flags); return ret; } @@ -89,15 +94,16 @@ static void pdumb_task_new(struct task_struct *t, int on_rq, int running) { /* Needed to disable interrupts */ unsigned long flags; - /* The macro __get_cpu_var() returns the local cpu variable */ struct dumb_cpu *cpu = &per_cpu(pdumb_cpus, get_partition(t)); - /* We are accessing state atomically, we need a lock and to - * disable irqs. - */ raw_spin_lock_irqsave(&cpu->lock, flags); - /* The task could already be running in Linux. + /* We only admit one task per cpu, this better be it */ + BUG_ON(cpu->dumb_task != t); + + /* The task could already be running in Linux. For example, it + * could have been running, then switched into real-time + * mode. This is how all real-time tasks begin execution. * Lets just say its running here too. */ if (running) { @@ -120,6 +126,7 @@ static void pdumb_task_exit(struct task_struct *t) raw_spin_lock_irqsave(&cpu->lock, flags); cpu->dumb_task = NULL; cpu->scheduled = 0; + cpu->blocked = 0; raw_spin_unlock_irqrestore(&cpu->lock, flags); } @@ -131,6 +138,7 @@ static void pdumb_task_exit(struct task_struct *t) */ static struct task_struct* pdumb_schedule(struct task_struct *prev) { + /* The macro __get_cpu_var() returns the local cpu variable */ struct dumb_cpu *cpu = &__get_cpu_var(pdumb_cpus); struct task_struct *sched; @@ -140,6 +148,7 @@ static struct task_struct* pdumb_schedule(struct task_struct *prev) */ raw_spin_lock(&cpu->lock); + /* Switch between dumb_task and nothing arbitrarily */ if (cpu->scheduled || cpu->blocked || !cpu->dumb_task) { cpu->scheduled = 0; sched = NULL; @@ -150,9 +159,15 @@ static struct task_struct* pdumb_schedule(struct task_struct *prev) TRACE_TASK(cpu->dumb_task, "Scheduled!\n"); } + /* This must be done when the cpu state has been atomically + * chosen. This allows litmus to manage some race conditions + * with tasks blocking / preempting / releasing without any + * work on the plugin's part. + */ sched_state_task_picked(); raw_spin_unlock(&cpu->lock); + return sched; } @@ -171,7 +186,7 @@ static void pdumb_task_block(struct task_struct *t) TRACE_TASK(t, "Blocked!\n"); raw_spin_lock_irqsave(&cpu->lock, flags); - cpu->blocked = 1; + cpu->blocked = 1; cpu->scheduled = 0; raw_spin_unlock_irqrestore(&cpu->lock, flags); } @@ -188,7 +203,7 @@ static void pdumb_task_wake_up(struct task_struct *t) TRACE_TASK(t, "Awoken!\n"); raw_spin_lock_irqsave(&cpu->lock, flags); - cpu->blocked = 0; + cpu->blocked = 0; cpu->scheduled = 0; raw_spin_unlock_irqrestore(&cpu->lock, flags); } @@ -212,6 +227,7 @@ static struct sched_plugin pdumb_plugin __cacheline_aligned_in_smp = { .task_exit = pdumb_task_exit, }; + /** * Called when the system boots up. */ -- cgit v1.2.2