aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/locking/rtmutex.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/locking/rtmutex.c')
-rw-r--r--kernel/locking/rtmutex.c68
1 files changed, 66 insertions, 2 deletions
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
index 1ec0f48962b3..2c49d76f96c3 100644
--- a/kernel/locking/rtmutex.c
+++ b/kernel/locking/rtmutex.c
@@ -65,8 +65,72 @@ static inline void clear_rt_mutex_waiters(struct rt_mutex *lock)
65 65
66static void fixup_rt_mutex_waiters(struct rt_mutex *lock) 66static void fixup_rt_mutex_waiters(struct rt_mutex *lock)
67{ 67{
68 if (!rt_mutex_has_waiters(lock)) 68 unsigned long owner, *p = (unsigned long *) &lock->owner;
69 clear_rt_mutex_waiters(lock); 69
70 if (rt_mutex_has_waiters(lock))
71 return;
72
73 /*
74 * The rbtree has no waiters enqueued, now make sure that the
75 * lock->owner still has the waiters bit set, otherwise the
76 * following can happen:
77 *
78 * CPU 0 CPU 1 CPU2
79 * l->owner=T1
80 * rt_mutex_lock(l)
81 * lock(l->lock)
82 * l->owner = T1 | HAS_WAITERS;
83 * enqueue(T2)
84 * boost()
85 * unlock(l->lock)
86 * block()
87 *
88 * rt_mutex_lock(l)
89 * lock(l->lock)
90 * l->owner = T1 | HAS_WAITERS;
91 * enqueue(T3)
92 * boost()
93 * unlock(l->lock)
94 * block()
95 * signal(->T2) signal(->T3)
96 * lock(l->lock)
97 * dequeue(T2)
98 * deboost()
99 * unlock(l->lock)
100 * lock(l->lock)
101 * dequeue(T3)
102 * ==> wait list is empty
103 * deboost()
104 * unlock(l->lock)
105 * lock(l->lock)
106 * fixup_rt_mutex_waiters()
107 * if (wait_list_empty(l) {
108 * l->owner = owner
109 * owner = l->owner & ~HAS_WAITERS;
110 * ==> l->owner = T1
111 * }
112 * lock(l->lock)
113 * rt_mutex_unlock(l) fixup_rt_mutex_waiters()
114 * if (wait_list_empty(l) {
115 * owner = l->owner & ~HAS_WAITERS;
116 * cmpxchg(l->owner, T1, NULL)
117 * ===> Success (l->owner = NULL)
118 *
119 * l->owner = owner
120 * ==> l->owner = T1
121 * }
122 *
123 * With the check for the waiter bit in place T3 on CPU2 will not
124 * overwrite. All tasks fiddling with the waiters bit are
125 * serialized by l->lock, so nothing else can modify the waiters
126 * bit. If the bit is set then nothing can change l->owner either
127 * so the simple RMW is safe. The cmpxchg() will simply fail if it
128 * happens in the middle of the RMW because the waiters bit is
129 * still set.
130 */
131 owner = READ_ONCE(*p);
132 if (owner & RT_MUTEX_HAS_WAITERS)
133 WRITE_ONCE(*p, owner & ~RT_MUTEX_HAS_WAITERS);
70} 134}
71 135
72/* 136/*