From e1b81e70c3af9d19d639bc8bdaa5a8fc13bf17a8 Mon Sep 17 00:00:00 2001 From: "Bjoern B. Brandenburg" Date: Fri, 28 Jan 2011 17:04:58 -0500 Subject: SRP: port to new generic locking API This re-enables SRP support under PSN-EDF and demonstrates how the new locking API should be used. --- include/litmus/litmus.h | 2 +- include/litmus/srp.h | 28 ++++++ litmus/fdso.c | 4 +- litmus/sched_psn_edf.c | 45 ++++++++- litmus/srp.c | 236 ++++++++++++++++++++++++++++-------------------- 5 files changed, 211 insertions(+), 104 deletions(-) create mode 100644 include/litmus/srp.h diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h index 4a774a9e7acc..8971b25f23e6 100644 --- a/include/litmus/litmus.h +++ b/include/litmus/litmus.h @@ -115,7 +115,7 @@ static inline lt_t litmus_clock(void) void preempt_if_preemptable(struct task_struct* t, int on_cpu); -#ifdef CONFIG_SRP +#ifdef CONFIG_LITMUS_LOCKING void srp_ceiling_block(void); #else #define srp_ceiling_block() /* nothing */ diff --git a/include/litmus/srp.h b/include/litmus/srp.h new file mode 100644 index 000000000000..c9a4552b2bf3 --- /dev/null +++ b/include/litmus/srp.h @@ -0,0 +1,28 @@ +#ifndef LITMUS_SRP_H +#define LITMUS_SRP_H + +struct srp_semaphore; + +struct srp_priority { + struct list_head list; + unsigned int priority; + pid_t pid; +}; +#define list2prio(l) list_entry(l, struct srp_priority, list) + +/* struct for uniprocessor SRP "semaphore" */ +struct srp_semaphore { + struct litmus_lock litmus_lock; + struct srp_priority ceiling; + struct task_struct* owner; + int cpu; /* cpu associated with this "semaphore" and resource */ +}; + +/* map a task to its SRP preemption level priority */ +typedef unsigned int (*srp_prioritization_t)(struct task_struct* t); +/* Must be updated by each plugin that uses SRP.*/ +extern srp_prioritization_t get_srp_prio; + +struct srp_semaphore* allocate_srp_semaphore(void); + +#endif diff --git a/litmus/fdso.c b/litmus/fdso.c index faede9bcbbbf..209431f3ce11 100644 --- a/litmus/fdso.c +++ b/litmus/fdso.c @@ -19,11 +19,11 @@ #include extern struct fdso_ops fmlp_sem_ops; -extern struct fdso_ops srp_sem_ops; +extern struct fdso_ops generic_lock_ops; static const struct fdso_ops* fdso_ops[] = { &fmlp_sem_ops, - &srp_sem_ops, + &generic_lock_ops, /* SRP_SEM */ }; static void* fdso_create(obj_type_t type) diff --git a/litmus/sched_psn_edf.c b/litmus/sched_psn_edf.c index 01f31e407082..c1e27960576b 100644 --- a/litmus/sched_psn_edf.c +++ b/litmus/sched_psn_edf.c @@ -435,6 +435,45 @@ static long psnedf_return_priority(struct pi_semaphore *sem) #endif +#ifdef CONFIG_LITMUS_LOCKING + +#include +#include + +static unsigned int psnedf_get_srp_prio(struct task_struct* t) +{ + /* assumes implicit deadlines */ + return get_rt_period(t); +} + +static long psnedf_activate_plugin(void) +{ + get_srp_prio = psnedf_get_srp_prio; + return 0; +} + +static long psnedf_allocate_lock(struct litmus_lock **lock, int type) +{ + int err = -ENXIO; + struct srp_semaphore* srp; + + switch (type) { + case SRP_SEM: + /* Baker's SRP */ + srp = allocate_srp_semaphore(); + if (srp) { + *lock = &srp->litmus_lock; + err = 0; + } else + err = -ENOMEM; + break; + }; + + return err; +} + +#endif + static long psnedf_admit_task(struct task_struct* tsk) { return task_cpu(tsk) == tsk->rt_param.task_params.cpu ? 0 : -EINVAL; @@ -450,7 +489,11 @@ static struct sched_plugin psn_edf_plugin __cacheline_aligned_in_smp = { .schedule = psnedf_schedule, .task_wake_up = psnedf_task_wake_up, .task_block = psnedf_task_block, - .admit_task = psnedf_admit_task + .admit_task = psnedf_admit_task, +#ifdef CONFIG_LITMUS_LOCKING + .allocate_lock = psnedf_allocate_lock, + .activate_plugin = psnedf_activate_plugin, +#endif }; diff --git a/litmus/srp.c b/litmus/srp.c index b4c171e79fd4..2ed4ec12a9d3 100644 --- a/litmus/srp.c +++ b/litmus/srp.c @@ -12,42 +12,25 @@ #include -#ifdef CONFIG_SRP +#ifdef CONFIG_LITMUS_LOCKING -struct srp_priority { - struct list_head list; - unsigned int period; - pid_t pid; -}; +#include -#define list2prio(l) list_entry(l, struct srp_priority, list) - -/* SRP task priority comparison function. Smaller periods have highest - * priority, tie-break is PID. Special case: period == 0 <=> no priority - */ -static int srp_higher_prio(struct srp_priority* first, - struct srp_priority* second) -{ - if (!first->period) - return 0; - else - return !second->period || - first->period < second->period || ( - first->period == second->period && - first->pid < second->pid); -} +srp_prioritization_t get_srp_prio; struct srp { struct list_head ceiling; wait_queue_head_t ceiling_blocked; }; +#define system_ceiling(srp) list2prio(srp->ceiling.next) +#define ceiling2sem(c) container_of(c, struct srp_semaphore, ceiling) +#define UNDEF_SEM -2 atomic_t srp_objects_in_use = ATOMIC_INIT(0); DEFINE_PER_CPU(struct srp, srp); - /* Initialize SRP semaphores at boot time. */ static int __init srp_init(void) { @@ -64,30 +47,35 @@ static int __init srp_init(void) } module_init(srp_init); +/* SRP task priority comparison function. Smaller numeric values have higher + * priority, tie-break is PID. Special case: priority == 0 <=> no priority + */ +static int srp_higher_prio(struct srp_priority* first, + struct srp_priority* second) +{ + if (!first->priority) + return 0; + else + return !second->priority || + first->priority < second->priority || ( + first->priority == second->priority && + first->pid < second->pid); +} -#define system_ceiling(srp) list2prio(srp->ceiling.next) - - -#define UNDEF_SEM -2 - - -/* struct for uniprocessor SRP "semaphore" */ -struct srp_semaphore { - struct srp_priority ceiling; - struct task_struct* owner; - int cpu; /* cpu associated with this "semaphore" and resource */ -}; - -#define ceiling2sem(c) container_of(c, struct srp_semaphore, ceiling) static int srp_exceeds_ceiling(struct task_struct* first, struct srp* srp) { - return list_empty(&srp->ceiling) || - get_rt_period(first) < system_ceiling(srp)->period || - (get_rt_period(first) == system_ceiling(srp)->period && - first->pid < system_ceiling(srp)->pid) || - ceiling2sem(system_ceiling(srp))->owner == first; + struct srp_priority prio; + + if (list_empty(&srp->ceiling)) + return 1; + else { + prio.pid = first->pid; + prio.priority = get_srp_prio(first); + return srp_higher_prio(&prio, system_ceiling(srp)) || + ceiling2sem(system_ceiling(srp))->owner == first; + } } static void srp_add_prio(struct srp* srp, struct srp_priority* prio) @@ -108,85 +96,139 @@ static void srp_add_prio(struct srp* srp, struct srp_priority* prio) } -static void* create_srp_semaphore(obj_type_t type) +static int lock_srp_semaphore(struct litmus_lock* l) { - struct srp_semaphore* sem; + struct srp_semaphore* sem = container_of(l, struct srp_semaphore, litmus_lock); - sem = kmalloc(sizeof(*sem), GFP_KERNEL); - if (!sem) - return NULL; + if (!is_realtime(current)) + return -EPERM; - INIT_LIST_HEAD(&sem->ceiling.list); - sem->ceiling.period = 0; - sem->cpu = UNDEF_SEM; - sem->owner = NULL; - atomic_inc(&srp_objects_in_use); - return sem; + preempt_disable(); + + /* Update ceiling. */ + srp_add_prio(&__get_cpu_var(srp), &sem->ceiling); + + /* SRP invariant: all resources available */ + BUG_ON(sem->owner != NULL); + + sem->owner = current; + TRACE_CUR("acquired srp 0x%p\n", sem); + + preempt_enable(); + + return 0; +} + +static int unlock_srp_semaphore(struct litmus_lock* l) +{ + struct srp_semaphore* sem = container_of(l, struct srp_semaphore, litmus_lock); + int err = 0; + + preempt_disable(); + + if (sem->owner != current) { + err = -EINVAL; + } else { + /* Determine new system priority ceiling for this CPU. */ + BUG_ON(!in_list(&sem->ceiling.list)); + + list_del(&sem->ceiling.list); + sem->owner = NULL; + + /* Wake tasks on this CPU, if they exceed current ceiling. */ + TRACE_CUR("released srp 0x%p\n", sem); + wake_up_all(&__get_cpu_var(srp).ceiling_blocked); + } + + preempt_enable(); + return err; } -static noinline int open_srp_semaphore(struct od_table_entry* entry, void* __user arg) +static int open_srp_semaphore(struct litmus_lock* l, void* __user arg) { - struct srp_semaphore* sem = (struct srp_semaphore*) entry->obj->obj; - int ret = 0; + struct srp_semaphore* sem = container_of(l, struct srp_semaphore, litmus_lock); + int err = 0; struct task_struct* t = current; struct srp_priority t_prio; - TRACE("opening SRP semaphore %p, cpu=%d\n", sem, sem->cpu); - if (!srp_active()) - return -EBUSY; + if (!is_realtime(t)) + return -EPERM; - if (sem->cpu == UNDEF_SEM) - sem->cpu = get_partition(t); - else if (sem->cpu != get_partition(t)) - ret = -EPERM; + TRACE_CUR("opening SRP semaphore %p, cpu=%d\n", sem, sem->cpu); - if (ret == 0) { - t_prio.period = get_rt_period(t); - t_prio.pid = t->pid; + preempt_disable(); + + if (sem->owner != NULL) + err = -EBUSY; + + if (err == 0) { + if (sem->cpu == UNDEF_SEM) + sem->cpu = get_partition(t); + else if (sem->cpu != get_partition(t)) + err = -EPERM; + } + + if (err == 0) { + t_prio.priority = get_srp_prio(t); + t_prio.pid = t->pid; if (srp_higher_prio(&t_prio, &sem->ceiling)) { - sem->ceiling.period = t_prio.period; - sem->ceiling.pid = t_prio.pid; + sem->ceiling.priority = t_prio.priority; + sem->ceiling.pid = t_prio.pid; } } - return ret; + preempt_enable(); + + return err; +} + +static int close_srp_semaphore(struct litmus_lock* l) +{ + struct srp_semaphore* sem = container_of(l, struct srp_semaphore, litmus_lock); + int err = 0; + + preempt_disable(); + + if (sem->owner == current) + unlock_srp_semaphore(l); + + preempt_enable(); + + return err; } -static void destroy_srp_semaphore(obj_type_t type, void* sem) +static void deallocate_srp_semaphore(struct litmus_lock* l) { - /* XXX invariants */ + struct srp_semaphore* sem = container_of(l, struct srp_semaphore, litmus_lock); atomic_dec(&srp_objects_in_use); kfree(sem); } -struct fdso_ops srp_sem_ops = { - .create = create_srp_semaphore, - .open = open_srp_semaphore, - .destroy = destroy_srp_semaphore +static struct litmus_lock_ops srp_lock_ops = { + .open = open_srp_semaphore, + .close = close_srp_semaphore, + .lock = lock_srp_semaphore, + .unlock = unlock_srp_semaphore, + .deallocate = deallocate_srp_semaphore, }; - -static void do_srp_down(struct srp_semaphore* sem) +struct srp_semaphore* allocate_srp_semaphore(void) { - /* Update ceiling. */ - srp_add_prio(&__get_cpu_var(srp), &sem->ceiling); - WARN_ON(sem->owner != NULL); - sem->owner = current; - TRACE_CUR("acquired srp 0x%p\n", sem); -} + struct srp_semaphore* sem; -static void do_srp_up(struct srp_semaphore* sem) -{ - /* Determine new system priority ceiling for this CPU. */ - WARN_ON(!in_list(&sem->ceiling.list)); - if (in_list(&sem->ceiling.list)) - list_del(&sem->ceiling.list); + sem = kmalloc(sizeof(*sem), GFP_KERNEL); + if (!sem) + return NULL; - sem->owner = NULL; + INIT_LIST_HEAD(&sem->ceiling.list); + sem->ceiling.priority = 0; + sem->cpu = UNDEF_SEM; + sem->owner = NULL; + + sem->litmus_lock.ops = &srp_lock_ops; - /* Wake tasks on this CPU, if they exceed current ceiling. */ - TRACE_CUR("released srp 0x%p\n", sem); - wake_up_all(&__get_cpu_var(srp).ceiling_blocked); + atomic_inc(&srp_objects_in_use); + return sem; } static int srp_wake_up(wait_queue_t *wait, unsigned mode, int sync, @@ -202,8 +244,6 @@ static int srp_wake_up(wait_queue_t *wait, unsigned mode, int sync, return 0; } - - static void do_ceiling_block(struct task_struct *tsk) { wait_queue_t wait = { @@ -223,6 +263,7 @@ static void do_ceiling_block(struct task_struct *tsk) } /* Wait for current task priority to exceed system-wide priority ceiling. + * FIXME: the hotpath should be inline. */ void srp_ceiling_block(void) { @@ -251,9 +292,4 @@ void srp_ceiling_block(void) preempt_enable(); } - -#else - -struct fdso_ops srp_sem_ops = {}; - #endif -- cgit v1.2.2