| #ifndef _LINUX_LOCALLOCK_H |
| #define _LINUX_LOCALLOCK_H |
| |
| #include <linux/percpu.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 DECLARE_LOCAL_IRQ_LOCK(lvar) \ |
| DECLARE_PER_CPU(struct local_irq_lock, lvar) |
| |
| #define local_irq_lock_init(lvar) \ |
| do { \ |
| int __cpu; \ |
| for_each_possible_cpu(__cpu) \ |
| spin_lock_init(&per_cpu(lvar, __cpu).lock); \ |
| } while (0) |
| |
| /* |
| * spin_lock|trylock|unlock_local flavour that does not migrate disable |
| * used for __local_lock|trylock|unlock where get_local_var/put_local_var |
| * already takes care of the migrate_disable/enable |
| * for CONFIG_PREEMPT_BASE map to the normal spin_* calls. |
| */ |
| #ifdef CONFIG_PREEMPT_RT_FULL |
| # define spin_lock_local(lock) rt_spin_lock(lock) |
| # define spin_trylock_local(lock) rt_spin_trylock(lock) |
| # define spin_unlock_local(lock) rt_spin_unlock(lock) |
| #else |
| # define spin_lock_local(lock) spin_lock(lock) |
| # define spin_trylock_local(lock) spin_trylock(lock) |
| # define spin_unlock_local(lock) spin_unlock(lock) |
| #endif |
| |
| static inline void __local_lock(struct local_irq_lock *lv) |
| { |
| if (lv->owner != current) { |
| spin_lock_local(&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) |
| |
| #define local_lock_on(lvar, cpu) \ |
| do { __local_lock(&per_cpu(lvar, cpu)); } while (0) |
| |
| static inline int __local_trylock(struct local_irq_lock *lv) |
| { |
| if (lv->owner != current && spin_trylock_local(&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_local(&lv->lock); |
| } |
| |
| #define local_unlock(lvar) \ |
| do { \ |
| __local_unlock(this_cpu_ptr(&lvar)); \ |
| put_local_var(lvar); \ |
| } while (0) |
| |
| #define local_unlock_on(lvar, cpu) \ |
| do { __local_unlock(&per_cpu(lvar, cpu)); } 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) |
| |
| #define local_lock_irq_on(lvar, cpu) \ |
| do { __local_lock_irq(&per_cpu(lvar, cpu)); } 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(this_cpu_ptr(&lvar)); \ |
| put_local_var(lvar); \ |
| } while (0) |
| |
| #define local_unlock_irq_on(lvar, cpu) \ |
| do { \ |
| __local_unlock_irq(&per_cpu(lvar, cpu)); \ |
| } 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 = __this_cpu_read(lvar.flags); \ |
| } while (0) |
| |
| #define local_lock_irqsave_on(lvar, _flags, cpu) \ |
| do { \ |
| __local_lock_irqsave(&per_cpu(lvar, cpu)); \ |
| _flags = per_cpu(lvar, cpu).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(this_cpu_ptr(&lvar), flags)) \ |
| put_local_var(lvar); \ |
| } while (0) |
| |
| #define local_unlock_irqrestore_on(lvar, flags, cpu) \ |
| do { \ |
| __local_unlock_irqrestore(&per_cpu(lvar, cpu), flags); \ |
| } 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); \ |
| this_cpu_ptr(&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 |
| #define DECLARE_LOCAL_IRQ_LOCK(lvar) extern __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 |