From 5442a8adfce93c1cd556e04bfc0a118adc3b683e Mon Sep 17 00:00:00 2001 From: Andrea Bastoni Date: Thu, 17 Dec 2009 21:34:09 -0500 Subject: [ported from 2008.3] Add Stack Resource Policy (SRP) support --- litmus/srp.c | 318 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 litmus/srp.c (limited to 'litmus/srp.c') diff --git a/litmus/srp.c b/litmus/srp.c new file mode 100644 index 00000000000..71639b99163 --- /dev/null +++ b/litmus/srp.c @@ -0,0 +1,318 @@ +/* ************************************************************************** */ +/* STACK RESOURCE POLICY */ +/* ************************************************************************** */ + +#include +#include +#include +#include + +#include + +#include + + +#ifdef CONFIG_SRP + +struct srp_priority { + struct list_head list; + unsigned int period; + pid_t pid; +}; + +#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); +} + +struct srp { + struct list_head ceiling; + wait_queue_head_t ceiling_blocked; +}; + + +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) +{ + int i; + + printk("Initializing SRP per-CPU ceilings..."); + for (i = 0; i < NR_CPUS; i++) { + init_waitqueue_head(&per_cpu(srp, i).ceiling_blocked); + INIT_LIST_HEAD(&per_cpu(srp, i).ceiling); + } + printk(" done!\n"); + + return 0; +} +module_init(srp_init); + + +#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; +} + +static void srp_add_prio(struct srp* srp, struct srp_priority* prio) +{ + struct list_head *pos; + if (in_list(&prio->list)) { + printk(KERN_CRIT "WARNING: SRP violation detected, prio is already in " + "ceiling list! cpu=%d, srp=%p\n", smp_processor_id(), ceiling2sem(prio)); + return; + } + list_for_each(pos, &srp->ceiling) + if (unlikely(srp_higher_prio(prio, list2prio(pos)))) { + __list_add(&prio->list, pos->prev, pos); + return; + } + + list_add_tail(&prio->list, &srp->ceiling); +} + + +static void* create_srp_semaphore(void) +{ + struct srp_semaphore* sem; + + sem = kmalloc(sizeof(*sem), GFP_KERNEL); + if (!sem) + return NULL; + + 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; +} + +static noinline int open_srp_semaphore(struct od_table_entry* entry, void* __user arg) +{ + struct srp_semaphore* sem = (struct srp_semaphore*) entry->obj->obj; + int ret = 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 (sem->cpu == UNDEF_SEM) + sem->cpu = get_partition(t); + else if (sem->cpu != get_partition(t)) + ret = -EPERM; + + if (ret == 0) { + t_prio.period = get_rt_period(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; + } + } + + return ret; +} + +static void destroy_srp_semaphore(void* sem) +{ + /* XXX invariants */ + 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 void do_srp_down(struct srp_semaphore* sem) +{ + /* 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); +} + +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->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); +} + +/* Adjust the system-wide priority ceiling if resource is claimed. */ +asmlinkage long sys_srp_down(int sem_od) +{ + int cpu; + int ret = -EINVAL; + struct srp_semaphore* sem; + + /* disabling preemptions is sufficient protection since + * SRP is strictly per CPU and we don't interfere with any + * interrupt handlers + */ + preempt_disable(); + TS_SRP_DOWN_START; + + cpu = smp_processor_id(); + sem = lookup_srp_sem(sem_od); + if (sem && sem->cpu == cpu) { + do_srp_down(sem); + ret = 0; + } + + TS_SRP_DOWN_END; + preempt_enable(); + return ret; +} + +/* Adjust the system-wide priority ceiling if resource is freed. */ +asmlinkage long sys_srp_up(int sem_od) +{ + int cpu; + int ret = -EINVAL; + struct srp_semaphore* sem; + + preempt_disable(); + TS_SRP_UP_START; + + cpu = smp_processor_id(); + sem = lookup_srp_sem(sem_od); + + if (sem && sem->cpu == cpu) { + do_srp_up(sem); + ret = 0; + } + + TS_SRP_UP_END; + preempt_enable(); + return ret; +} + +static int srp_wake_up(wait_queue_t *wait, unsigned mode, int sync, + void *key) +{ + int cpu = smp_processor_id(); + struct task_struct *tsk = wait->private; + if (cpu != get_partition(tsk)) + TRACE_TASK(tsk, "srp_wake_up on wrong cpu, partition is %d\b", + get_partition(tsk)); + else if (srp_exceeds_ceiling(tsk, &__get_cpu_var(srp))) + return default_wake_function(wait, mode, sync, key); + return 0; +} + + + +static void do_ceiling_block(struct task_struct *tsk) +{ + wait_queue_t wait = { + .private = tsk, + .func = srp_wake_up, + .task_list = {NULL, NULL} + }; + + tsk->state = TASK_UNINTERRUPTIBLE; + add_wait_queue(&__get_cpu_var(srp).ceiling_blocked, &wait); + tsk->rt_param.srp_non_recurse = 1; + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + tsk->rt_param.srp_non_recurse = 0; + remove_wait_queue(&__get_cpu_var(srp).ceiling_blocked, &wait); +} + +/* Wait for current task priority to exceed system-wide priority ceiling. + */ +void srp_ceiling_block(void) +{ + struct task_struct *tsk = current; + + /* Only applies to real-time tasks, but optimize for RT tasks. */ + if (unlikely(!is_realtime(tsk))) + return; + + /* Avoid recursive ceiling blocking. */ + if (unlikely(tsk->rt_param.srp_non_recurse)) + return; + + /* Bail out early if there aren't any SRP resources around. */ + if (likely(!atomic_read(&srp_objects_in_use))) + return; + + preempt_disable(); + if (!srp_exceeds_ceiling(tsk, &__get_cpu_var(srp))) { + TRACE_CUR("is priority ceiling blocked.\n"); + while (!srp_exceeds_ceiling(tsk, &__get_cpu_var(srp))) + do_ceiling_block(tsk); + TRACE_CUR("finally exceeds system ceiling.\n"); + } else + TRACE_CUR("is not priority ceiling blocked\n"); + preempt_enable(); +} + + +#else + +asmlinkage long sys_srp_down(int sem_od) +{ + return -ENOSYS; +} + +asmlinkage long sys_srp_up(int sem_od) +{ + return -ENOSYS; +} + +struct fdso_ops srp_sem_ops = {}; + +#endif -- cgit v1.2.2 From 34310fd7dbc3ad98d8e7cafa4f872ba71ca00860 Mon Sep 17 00:00:00 2001 From: "Bjoern B. Brandenburg" Date: Mon, 8 Nov 2010 15:02:09 -0500 Subject: Split out TRACE() from litmus.h and cleanup some includes The TRACE() functionality doesn't need all of litmus.h. Currently, it's impossible to use TRACE() in sched.h due to a circular dependency. This patch moves TRACE() and friends to litmus/sched_debug.h, which can be included in sched.h. While at it, also fix some minor include ugliness that was revealed by this change. --- litmus/srp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'litmus/srp.c') diff --git a/litmus/srp.c b/litmus/srp.c index 71639b99163..cb577598ce3 100644 --- a/litmus/srp.c +++ b/litmus/srp.c @@ -3,12 +3,12 @@ /* ************************************************************************** */ #include +#include #include + #include #include - #include - #include -- cgit v1.2.2 From fd8ae31c74975c8499983c9831bff2b136b98434 Mon Sep 17 00:00:00 2001 From: "Bjoern B. Brandenburg" Date: Fri, 28 Jan 2011 11:54:38 -0500 Subject: fdso: supply object type to constructor and destructor methods Passing the object type explicitly will enable generic lock constructors. --- litmus/srp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'litmus/srp.c') diff --git a/litmus/srp.c b/litmus/srp.c index cb577598ce3..4601b7dba81 100644 --- a/litmus/srp.c +++ b/litmus/srp.c @@ -108,7 +108,7 @@ static void srp_add_prio(struct srp* srp, struct srp_priority* prio) } -static void* create_srp_semaphore(void) +static void* create_srp_semaphore(obj_type_t type) { struct srp_semaphore* sem; @@ -152,7 +152,7 @@ static noinline int open_srp_semaphore(struct od_table_entry* entry, void* __use return ret; } -static void destroy_srp_semaphore(void* sem) +static void destroy_srp_semaphore(obj_type_t type, void* sem) { /* XXX invariants */ atomic_dec(&srp_objects_in_use); -- cgit v1.2.2 From cc602187d4466374bca031039e145aa1b89aca96 Mon Sep 17 00:00:00 2001 From: "Bjoern B. Brandenburg" Date: Fri, 28 Jan 2011 16:41:16 -0500 Subject: Litmus core: replace FMLP & SRP system calls with generic syscalls This renders the FMLP and SRP unfunctional until they are ported to the new locking API. --- litmus/srp.c | 59 ----------------------------------------------------------- 1 file changed, 59 deletions(-) (limited to 'litmus/srp.c') diff --git a/litmus/srp.c b/litmus/srp.c index 4601b7dba81..b4c171e79fd 100644 --- a/litmus/srp.c +++ b/litmus/srp.c @@ -189,55 +189,6 @@ static void do_srp_up(struct srp_semaphore* sem) wake_up_all(&__get_cpu_var(srp).ceiling_blocked); } -/* Adjust the system-wide priority ceiling if resource is claimed. */ -asmlinkage long sys_srp_down(int sem_od) -{ - int cpu; - int ret = -EINVAL; - struct srp_semaphore* sem; - - /* disabling preemptions is sufficient protection since - * SRP is strictly per CPU and we don't interfere with any - * interrupt handlers - */ - preempt_disable(); - TS_SRP_DOWN_START; - - cpu = smp_processor_id(); - sem = lookup_srp_sem(sem_od); - if (sem && sem->cpu == cpu) { - do_srp_down(sem); - ret = 0; - } - - TS_SRP_DOWN_END; - preempt_enable(); - return ret; -} - -/* Adjust the system-wide priority ceiling if resource is freed. */ -asmlinkage long sys_srp_up(int sem_od) -{ - int cpu; - int ret = -EINVAL; - struct srp_semaphore* sem; - - preempt_disable(); - TS_SRP_UP_START; - - cpu = smp_processor_id(); - sem = lookup_srp_sem(sem_od); - - if (sem && sem->cpu == cpu) { - do_srp_up(sem); - ret = 0; - } - - TS_SRP_UP_END; - preempt_enable(); - return ret; -} - static int srp_wake_up(wait_queue_t *wait, unsigned mode, int sync, void *key) { @@ -303,16 +254,6 @@ void srp_ceiling_block(void) #else -asmlinkage long sys_srp_down(int sem_od) -{ - return -ENOSYS; -} - -asmlinkage long sys_srp_up(int sem_od) -{ - return -ENOSYS; -} - struct fdso_ops srp_sem_ops = {}; #endif -- cgit v1.2.2 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. --- litmus/srp.c | 236 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 136 insertions(+), 100 deletions(-) (limited to 'litmus/srp.c') diff --git a/litmus/srp.c b/litmus/srp.c index b4c171e79fd..2ed4ec12a9d 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 From 5b8782ef8948c7aad808971f359401f1dc837c25 Mon Sep 17 00:00:00 2001 From: Bjoern Brandenburg Date: Fri, 15 Feb 2013 16:44:42 +0100 Subject: Disallow nesting of LITMUS^RT locks Nesting of locks was never supported in LITMUS^RT since the required analysis does not exist anyway. That is, as defined in the literature, the protocols implemented in LITMUS^RT have not been studied in conjunction with nested critical sections. In LITMUS^RT, attempting to nest locks could lead to silent or not-so-silent bugs. This patch makes this restriction explicit and returns EBUSY when a process attempts to nest resources. This is enforced on a protocol-by-protocol basis, which means that adding protocols with support for nesting in future versions is not affected by this change. Exception: PCP and SRP resources may be nested, but not within global critical sections. --- litmus/srp.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'litmus/srp.c') diff --git a/litmus/srp.c b/litmus/srp.c index 2ed4ec12a9d..c88dbf2f580 100644 --- a/litmus/srp.c +++ b/litmus/srp.c @@ -98,11 +98,16 @@ static void srp_add_prio(struct srp* srp, struct srp_priority* prio) static int lock_srp_semaphore(struct litmus_lock* l) { + struct task_struct* t = current; struct srp_semaphore* sem = container_of(l, struct srp_semaphore, litmus_lock); - if (!is_realtime(current)) + if (!is_realtime(t)) return -EPERM; + /* prevent acquisition of local locks in global critical sections */ + if (tsk_rt(t)->num_locks_held) + return -EBUSY; + preempt_disable(); /* Update ceiling. */ @@ -111,9 +116,11 @@ static int lock_srp_semaphore(struct litmus_lock* l) /* SRP invariant: all resources available */ BUG_ON(sem->owner != NULL); - sem->owner = current; + sem->owner = t; TRACE_CUR("acquired srp 0x%p\n", sem); + tsk_rt(t)->num_local_locks_held++; + preempt_enable(); return 0; @@ -121,12 +128,13 @@ static int lock_srp_semaphore(struct litmus_lock* l) static int unlock_srp_semaphore(struct litmus_lock* l) { + struct task_struct* t = current; struct srp_semaphore* sem = container_of(l, struct srp_semaphore, litmus_lock); int err = 0; preempt_disable(); - if (sem->owner != current) { + if (sem->owner != t) { err = -EINVAL; } else { /* Determine new system priority ceiling for this CPU. */ @@ -138,6 +146,8 @@ static int unlock_srp_semaphore(struct litmus_lock* l) /* 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); + + tsk_rt(t)->num_local_locks_held--; } preempt_enable(); -- cgit v1.2.2