mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 08:19:28 +00:00
![Will Deacon](/assets/img/avatar_default.png)
When CONFIG_GENERIC_LOCKBEAK=y, locking structures grow an extra int ->break_lock field which is used to implement raw_spin_is_contended() by setting the field to 1 when waiting on a lock and clearing it to zero when holding a lock. However, there are a few problems with this approach: - There is a write-write race between a CPU successfully taking the lock (and subsequently writing break_lock = 0) and a waiter waiting on the lock (and subsequently writing break_lock = 1). This could result in a contended lock being reported as uncontended and vice-versa. - On machines with store buffers, nothing guarantees that the writes to break_lock are visible to other CPUs at any particular time. - READ_ONCE/WRITE_ONCE are not used, so the field is potentially susceptible to harmful compiler optimisations, Consequently, the usefulness of this field is unclear and we'd be better off removing it and allowing architectures to implement raw_spin_is_contended() by providing a definition of arch_spin_is_contended(), as they can when CONFIG_GENERIC_LOCKBREAK=n. Signed-off-by: Will Deacon <will.deacon@arm.com> Acked-by: Peter Zijlstra <peterz@infradead.org> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Sebastian Ott <sebott@linux.vnet.ibm.com> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/1511894539-7988-3-git-send-email-will.deacon@arm.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
85 lines
2 KiB
C
85 lines
2 KiB
C
#ifndef __LINUX_SPINLOCK_TYPES_H
|
|
#define __LINUX_SPINLOCK_TYPES_H
|
|
|
|
/*
|
|
* include/linux/spinlock_types.h - generic spinlock type definitions
|
|
* and initializers
|
|
*
|
|
* portions Copyright 2005, Red Hat, Inc., Ingo Molnar
|
|
* Released under the General Public License (GPL).
|
|
*/
|
|
|
|
#if defined(CONFIG_SMP)
|
|
# include <asm/spinlock_types.h>
|
|
#else
|
|
# include <linux/spinlock_types_up.h>
|
|
#endif
|
|
|
|
#include <linux/lockdep.h>
|
|
|
|
typedef struct raw_spinlock {
|
|
arch_spinlock_t raw_lock;
|
|
#ifdef CONFIG_DEBUG_SPINLOCK
|
|
unsigned int magic, owner_cpu;
|
|
void *owner;
|
|
#endif
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
struct lockdep_map dep_map;
|
|
#endif
|
|
} raw_spinlock_t;
|
|
|
|
#define SPINLOCK_MAGIC 0xdead4ead
|
|
|
|
#define SPINLOCK_OWNER_INIT ((void *)-1L)
|
|
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
# define SPIN_DEP_MAP_INIT(lockname) .dep_map = { .name = #lockname }
|
|
#else
|
|
# define SPIN_DEP_MAP_INIT(lockname)
|
|
#endif
|
|
|
|
#ifdef CONFIG_DEBUG_SPINLOCK
|
|
# define SPIN_DEBUG_INIT(lockname) \
|
|
.magic = SPINLOCK_MAGIC, \
|
|
.owner_cpu = -1, \
|
|
.owner = SPINLOCK_OWNER_INIT,
|
|
#else
|
|
# define SPIN_DEBUG_INIT(lockname)
|
|
#endif
|
|
|
|
#define __RAW_SPIN_LOCK_INITIALIZER(lockname) \
|
|
{ \
|
|
.raw_lock = __ARCH_SPIN_LOCK_UNLOCKED, \
|
|
SPIN_DEBUG_INIT(lockname) \
|
|
SPIN_DEP_MAP_INIT(lockname) }
|
|
|
|
#define __RAW_SPIN_LOCK_UNLOCKED(lockname) \
|
|
(raw_spinlock_t) __RAW_SPIN_LOCK_INITIALIZER(lockname)
|
|
|
|
#define DEFINE_RAW_SPINLOCK(x) raw_spinlock_t x = __RAW_SPIN_LOCK_UNLOCKED(x)
|
|
|
|
typedef struct spinlock {
|
|
union {
|
|
struct raw_spinlock rlock;
|
|
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
|
|
struct {
|
|
u8 __padding[LOCK_PADSIZE];
|
|
struct lockdep_map dep_map;
|
|
};
|
|
#endif
|
|
};
|
|
} spinlock_t;
|
|
|
|
#define __SPIN_LOCK_INITIALIZER(lockname) \
|
|
{ { .rlock = __RAW_SPIN_LOCK_INITIALIZER(lockname) } }
|
|
|
|
#define __SPIN_LOCK_UNLOCKED(lockname) \
|
|
(spinlock_t ) __SPIN_LOCK_INITIALIZER(lockname)
|
|
|
|
#define DEFINE_SPINLOCK(x) spinlock_t x = __SPIN_LOCK_UNLOCKED(x)
|
|
|
|
#include <linux/rwlock_types.h>
|
|
|
|
#endif /* __LINUX_SPINLOCK_TYPES_H */
|