|
@@ -18,6 +18,7 @@
|
|
|
#include <linux/atomic.h>
|
|
|
#include <asm/processor.h>
|
|
|
#include <linux/osq_lock.h>
|
|
|
+#include <linux/debug_locks.h>
|
|
|
|
|
|
/*
|
|
|
* Simple, straightforward mutexes with strict semantics:
|
|
@@ -48,16 +49,12 @@
|
|
|
* locks and tasks (and only those tasks)
|
|
|
*/
|
|
|
struct mutex {
|
|
|
- /* 1: unlocked, 0: locked, negative: locked, possible waiters */
|
|
|
- atomic_t count;
|
|
|
+ atomic_long_t owner;
|
|
|
spinlock_t wait_lock;
|
|
|
- struct list_head wait_list;
|
|
|
-#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_MUTEX_SPIN_ON_OWNER)
|
|
|
- struct task_struct *owner;
|
|
|
-#endif
|
|
|
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
|
|
|
struct optimistic_spin_queue osq; /* Spinner MCS lock */
|
|
|
#endif
|
|
|
+ struct list_head wait_list;
|
|
|
#ifdef CONFIG_DEBUG_MUTEXES
|
|
|
void *magic;
|
|
|
#endif
|
|
@@ -66,6 +63,11 @@ struct mutex {
|
|
|
#endif
|
|
|
};
|
|
|
|
|
|
+static inline struct task_struct *__mutex_owner(struct mutex *lock)
|
|
|
+{
|
|
|
+ return (struct task_struct *)(atomic_long_read(&lock->owner) & ~0x03);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* This is the control structure for tasks blocked on mutex,
|
|
|
* which resides on the blocked task's kernel stack:
|
|
@@ -79,9 +81,20 @@ struct mutex_waiter {
|
|
|
};
|
|
|
|
|
|
#ifdef CONFIG_DEBUG_MUTEXES
|
|
|
-# include <linux/mutex-debug.h>
|
|
|
+
|
|
|
+#define __DEBUG_MUTEX_INITIALIZER(lockname) \
|
|
|
+ , .magic = &lockname
|
|
|
+
|
|
|
+extern void mutex_destroy(struct mutex *lock);
|
|
|
+
|
|
|
#else
|
|
|
+
|
|
|
# define __DEBUG_MUTEX_INITIALIZER(lockname)
|
|
|
+
|
|
|
+static inline void mutex_destroy(struct mutex *lock) {}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
/**
|
|
|
* mutex_init - initialize the mutex
|
|
|
* @mutex: the mutex to be initialized
|
|
@@ -90,14 +103,12 @@ struct mutex_waiter {
|
|
|
*
|
|
|
* It is not allowed to initialize an already locked mutex.
|
|
|
*/
|
|
|
-# define mutex_init(mutex) \
|
|
|
-do { \
|
|
|
- static struct lock_class_key __key; \
|
|
|
- \
|
|
|
- __mutex_init((mutex), #mutex, &__key); \
|
|
|
+#define mutex_init(mutex) \
|
|
|
+do { \
|
|
|
+ static struct lock_class_key __key; \
|
|
|
+ \
|
|
|
+ __mutex_init((mutex), #mutex, &__key); \
|
|
|
} while (0)
|
|
|
-static inline void mutex_destroy(struct mutex *lock) {}
|
|
|
-#endif
|
|
|
|
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
|
# define __DEP_MAP_MUTEX_INITIALIZER(lockname) \
|
|
@@ -107,7 +118,7 @@ static inline void mutex_destroy(struct mutex *lock) {}
|
|
|
#endif
|
|
|
|
|
|
#define __MUTEX_INITIALIZER(lockname) \
|
|
|
- { .count = ATOMIC_INIT(1) \
|
|
|
+ { .owner = ATOMIC_LONG_INIT(0) \
|
|
|
, .wait_lock = __SPIN_LOCK_UNLOCKED(lockname.wait_lock) \
|
|
|
, .wait_list = LIST_HEAD_INIT(lockname.wait_list) \
|
|
|
__DEBUG_MUTEX_INITIALIZER(lockname) \
|
|
@@ -127,7 +138,10 @@ extern void __mutex_init(struct mutex *lock, const char *name,
|
|
|
*/
|
|
|
static inline int mutex_is_locked(struct mutex *lock)
|
|
|
{
|
|
|
- return atomic_read(&lock->count) != 1;
|
|
|
+ /*
|
|
|
+ * XXX think about spin_is_locked
|
|
|
+ */
|
|
|
+ return __mutex_owner(lock) != NULL;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -175,4 +189,35 @@ extern void mutex_unlock(struct mutex *lock);
|
|
|
|
|
|
extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
|
|
|
|
|
|
+/*
|
|
|
+ * These values are chosen such that FAIL and SUCCESS match the
|
|
|
+ * values of the regular mutex_trylock().
|
|
|
+ */
|
|
|
+enum mutex_trylock_recursive_enum {
|
|
|
+ MUTEX_TRYLOCK_FAILED = 0,
|
|
|
+ MUTEX_TRYLOCK_SUCCESS = 1,
|
|
|
+ MUTEX_TRYLOCK_RECURSIVE,
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * mutex_trylock_recursive - trylock variant that allows recursive locking
|
|
|
+ * @lock: mutex to be locked
|
|
|
+ *
|
|
|
+ * This function should not be used, _ever_. It is purely for hysterical GEM
|
|
|
+ * raisins, and once those are gone this will be removed.
|
|
|
+ *
|
|
|
+ * Returns:
|
|
|
+ * MUTEX_TRYLOCK_FAILED - trylock failed,
|
|
|
+ * MUTEX_TRYLOCK_SUCCESS - lock acquired,
|
|
|
+ * MUTEX_TRYLOCK_RECURSIVE - we already owned the lock.
|
|
|
+ */
|
|
|
+static inline /* __deprecated */ __must_check enum mutex_trylock_recursive_enum
|
|
|
+mutex_trylock_recursive(struct mutex *lock)
|
|
|
+{
|
|
|
+ if (unlikely(__mutex_owner(lock) == current))
|
|
|
+ return MUTEX_TRYLOCK_RECURSIVE;
|
|
|
+
|
|
|
+ return mutex_trylock(lock);
|
|
|
+}
|
|
|
+
|
|
|
#endif /* __LINUX_MUTEX_H */
|