| Subject: rt-local-irq-lock.patch |
| From: Thomas Gleixner <tglx@linutronix.de> |
| Date: Mon, 20 Jun 2011 09:03:47 +0200 |
| |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| --- |
| include/linux/locallock.h | 230 ++++++++++++++++++++++++++++++++++++++++++++++ |
| 1 file changed, 230 insertions(+) |
| |
| Index: linux-stable/include/linux/locallock.h |
| =================================================================== |
| --- /dev/null |
| +++ linux-stable/include/linux/locallock.h |
| @@ -0,0 +1,230 @@ |
| +#ifndef _LINUX_LOCALLOCK_H |
| +#define _LINUX_LOCALLOCK_H |
| + |
| +#include <linux/spinlock.h> |
| + |
| +#ifdef CONFIG_PREEMPT_RT_BASE |
| + |
| +#ifdef CONFIG_DEBUG_SPINLOCK |
| +# define LL_WARN(cond) WARN_ON(cond) |
| +#else |
| +# define LL_WARN(cond) do { } while (0) |
| +#endif |
| + |
| +/* |
| + * per cpu lock based substitute for local_irq_*() |
| + */ |
| +struct local_irq_lock { |
| + spinlock_t lock; |
| + struct task_struct *owner; |
| + int nestcnt; |
| + unsigned long flags; |
| +}; |
| + |
| +#define DEFINE_LOCAL_IRQ_LOCK(lvar) \ |
| + DEFINE_PER_CPU(struct local_irq_lock, lvar) = { \ |
| + .lock = __SPIN_LOCK_UNLOCKED((lvar).lock) } |
| + |
| +#define local_irq_lock_init(lvar) \ |
| + do { \ |
| + int __cpu; \ |
| + for_each_possible_cpu(__cpu) \ |
| + spin_lock_init(&per_cpu(lvar, __cpu).lock); \ |
| + } while (0) |
| + |
| +static inline void __local_lock(struct local_irq_lock *lv) |
| +{ |
| + if (lv->owner != current) { |
| + spin_lock(&lv->lock); |
| + LL_WARN(lv->owner); |
| + LL_WARN(lv->nestcnt); |
| + lv->owner = current; |
| + } |
| + lv->nestcnt++; |
| +} |
| + |
| +#define local_lock(lvar) \ |
| + do { __local_lock(&get_local_var(lvar)); } while (0) |
| + |
| +static inline int __local_trylock(struct local_irq_lock *lv) |
| +{ |
| + if (lv->owner != current && spin_trylock(&lv->lock)) { |
| + LL_WARN(lv->owner); |
| + LL_WARN(lv->nestcnt); |
| + lv->owner = current; |
| + lv->nestcnt = 1; |
| + return 1; |
| + } |
| + return 0; |
| +} |
| + |
| +#define local_trylock(lvar) \ |
| + ({ \ |
| + int __locked; \ |
| + __locked = __local_trylock(&get_local_var(lvar)); \ |
| + if (!__locked) \ |
| + put_local_var(lvar); \ |
| + __locked; \ |
| + }) |
| + |
| +static inline void __local_unlock(struct local_irq_lock *lv) |
| +{ |
| + LL_WARN(lv->nestcnt == 0); |
| + LL_WARN(lv->owner != current); |
| + if (--lv->nestcnt) |
| + return; |
| + |
| + lv->owner = NULL; |
| + spin_unlock(&lv->lock); |
| +} |
| + |
| +#define local_unlock(lvar) \ |
| + do { \ |
| + __local_unlock(&__get_cpu_var(lvar)); \ |
| + put_local_var(lvar); \ |
| + } while (0) |
| + |
| +static inline void __local_lock_irq(struct local_irq_lock *lv) |
| +{ |
| + spin_lock_irqsave(&lv->lock, lv->flags); |
| + LL_WARN(lv->owner); |
| + LL_WARN(lv->nestcnt); |
| + lv->owner = current; |
| + lv->nestcnt = 1; |
| +} |
| + |
| +#define local_lock_irq(lvar) \ |
| + do { __local_lock_irq(&get_local_var(lvar)); } while (0) |
| + |
| +static inline void __local_unlock_irq(struct local_irq_lock *lv) |
| +{ |
| + LL_WARN(!lv->nestcnt); |
| + LL_WARN(lv->owner != current); |
| + lv->owner = NULL; |
| + lv->nestcnt = 0; |
| + spin_unlock_irq(&lv->lock); |
| +} |
| + |
| +#define local_unlock_irq(lvar) \ |
| + do { \ |
| + __local_unlock_irq(&__get_cpu_var(lvar)); \ |
| + put_local_var(lvar); \ |
| + } while (0) |
| + |
| +static inline int __local_lock_irqsave(struct local_irq_lock *lv) |
| +{ |
| + if (lv->owner != current) { |
| + __local_lock_irq(lv); |
| + return 0; |
| + } else { |
| + lv->nestcnt++; |
| + return 1; |
| + } |
| +} |
| + |
| +#define local_lock_irqsave(lvar, _flags) \ |
| + do { \ |
| + if (__local_lock_irqsave(&get_local_var(lvar))) \ |
| + put_local_var(lvar); \ |
| + _flags = __get_cpu_var(lvar).flags; \ |
| + } while (0) |
| + |
| +static inline int __local_unlock_irqrestore(struct local_irq_lock *lv, |
| + unsigned long flags) |
| +{ |
| + LL_WARN(!lv->nestcnt); |
| + LL_WARN(lv->owner != current); |
| + if (--lv->nestcnt) |
| + return 0; |
| + |
| + lv->owner = NULL; |
| + spin_unlock_irqrestore(&lv->lock, lv->flags); |
| + return 1; |
| +} |
| + |
| +#define local_unlock_irqrestore(lvar, flags) \ |
| + do { \ |
| + if (__local_unlock_irqrestore(&__get_cpu_var(lvar), flags)) \ |
| + put_local_var(lvar); \ |
| + } while (0) |
| + |
| +#define local_spin_trylock_irq(lvar, lock) \ |
| + ({ \ |
| + int __locked; \ |
| + local_lock_irq(lvar); \ |
| + __locked = spin_trylock(lock); \ |
| + if (!__locked) \ |
| + local_unlock_irq(lvar); \ |
| + __locked; \ |
| + }) |
| + |
| +#define local_spin_lock_irq(lvar, lock) \ |
| + do { \ |
| + local_lock_irq(lvar); \ |
| + spin_lock(lock); \ |
| + } while (0) |
| + |
| +#define local_spin_unlock_irq(lvar, lock) \ |
| + do { \ |
| + spin_unlock(lock); \ |
| + local_unlock_irq(lvar); \ |
| + } while (0) |
| + |
| +#define local_spin_lock_irqsave(lvar, lock, flags) \ |
| + do { \ |
| + local_lock_irqsave(lvar, flags); \ |
| + spin_lock(lock); \ |
| + } while (0) |
| + |
| +#define local_spin_unlock_irqrestore(lvar, lock, flags) \ |
| + do { \ |
| + spin_unlock(lock); \ |
| + local_unlock_irqrestore(lvar, flags); \ |
| + } while (0) |
| + |
| +#define get_locked_var(lvar, var) \ |
| + (*({ \ |
| + local_lock(lvar); \ |
| + &__get_cpu_var(var); \ |
| + })) |
| + |
| +#define put_locked_var(lvar, var) local_unlock(lvar) |
| + |
| +#define local_lock_cpu(lvar) \ |
| + ({ \ |
| + local_lock(lvar); \ |
| + smp_processor_id(); \ |
| + }) |
| + |
| +#define local_unlock_cpu(lvar) local_unlock(lvar) |
| + |
| +#else /* PREEMPT_RT_BASE */ |
| + |
| +#define DEFINE_LOCAL_IRQ_LOCK(lvar) __typeof__(const int) lvar |
| + |
| +static inline void local_irq_lock_init(int lvar) { } |
| + |
| +#define local_lock(lvar) preempt_disable() |
| +#define local_unlock(lvar) preempt_enable() |
| +#define local_lock_irq(lvar) local_irq_disable() |
| +#define local_unlock_irq(lvar) local_irq_enable() |
| +#define local_lock_irqsave(lvar, flags) local_irq_save(flags) |
| +#define local_unlock_irqrestore(lvar, flags) local_irq_restore(flags) |
| + |
| +#define local_spin_trylock_irq(lvar, lock) spin_trylock_irq(lock) |
| +#define local_spin_lock_irq(lvar, lock) spin_lock_irq(lock) |
| +#define local_spin_unlock_irq(lvar, lock) spin_unlock_irq(lock) |
| +#define local_spin_lock_irqsave(lvar, lock, flags) \ |
| + spin_lock_irqsave(lock, flags) |
| +#define local_spin_unlock_irqrestore(lvar, lock, flags) \ |
| + spin_unlock_irqrestore(lock, flags) |
| + |
| +#define get_locked_var(lvar, var) get_cpu_var(var) |
| +#define put_locked_var(lvar, var) put_cpu_var(var) |
| + |
| +#define local_lock_cpu(lvar) get_cpu() |
| +#define local_unlock_cpu(lvar) put_cpu() |
| + |
| +#endif |
| + |
| +#endif |