Split the inner workings of rt_mutex_slowlock() out into a separate function, which can be reused by the upcoming RT lock substitutions, e.g. for rw_semaphores.
Unified · Split
| @@ -1106,7 +1106,7 @@ static void __sched remove_waiter(struct rt_mutex_base *lock, · 1105 unmodified lines | |||
| 1106 | } | 1106 | } |
| 1107 | 1107 | ||
| 1108 | /** | 1108 | /** |
| 1109 | * __rt_mutex_slowlock() - Perform the wait-wake-try-to-take loop | 1109 | * rt_mutex_slowlock_block() - Perform the wait-wake-try-to-take loop |
| 1110 | * @lock: the rt_mutex to take | 1110 | * @lock: the rt_mutex to take |
| 1111 | * @state: the state the task should block in (TASK_INTERRUPTIBLE | 1111 | * @state: the state the task should block in (TASK_INTERRUPTIBLE |
| 1112 | * or TASK_UNINTERRUPTIBLE) | 1112 | * or TASK_UNINTERRUPTIBLE) |
| @@ -1115,10 +1115,10 @@ static void __sched remove_waiter(struct rt_mutex_base *lock, · 2 unmodified lines | |||
| 1115 | * | 1115 | * |
| 1116 | * Must be called with lock->wait_lock held and interrupts disabled | 1116 | * Must be called with lock->wait_lock held and interrupts disabled |
| 1117 | */ | 1117 | */ |
| 1118 | static int __sched __rt_mutex_slowlock(struct rt_mutex_base *lock, | 1118 | static int __sched rt_mutex_slowlock_block(struct rt_mutex_base *lock, |
| 1119 | unsigned int state, | 1119 | unsigned int state, |
| 1120 | struct hrtimer_sleeper *timeout, | 1120 | struct hrtimer_sleeper *timeout, |
| 1121 | struct rt_mutex_waiter *waiter) | 1121 | struct rt_mutex_waiter *waiter) |
| 1122 | { | 1122 | { |
| 1123 | int ret = 0; | 1123 | int ret = 0; |
| 1124 | 1124 | ||
| @@ -1168,52 +1168,37 @@ static void __sched rt_mutex_handle_deadlock(int res, int detect_deadlock, · 43 unmodified lines | |||
| 1168 | } | 1168 | } |
| 1169 | } | 1169 | } |
| 1170 | 1170 | ||
| 1171 | /* | 1171 | /** |
| 1172 | * Slow path lock function: | 1172 | * __rt_mutex_slowlock - Locking slowpath invoked with lock::wait_lock held |
| 1173 | * @lock: The rtmutex to block lock | ||
| 1174 | * @state: The task state for sleeping | ||
| 1175 | * @chwalk: Indicator whether full or partial chainwalk is requested | ||
| 1176 | * @waiter: Initializer waiter for blocking | ||
| 1173 | */ | 1177 | */ |
| 1174 | static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock, | 1178 | static int __sched __rt_mutex_slowlock(struct rt_mutex_base *lock, |
| 1175 | unsigned int state, | 1179 | unsigned int state, |
| 1176 | struct hrtimer_sleeper *timeout, | 1180 | enum rtmutex_chainwalk chwalk, |
| 1177 | enum rtmutex_chainwalk chwalk) | 1181 | struct rt_mutex_waiter *waiter) |
| 1178 | { | 1182 | { |
| 1179 | struct rt_mutex_waiter waiter; | 1183 | int ret; |
| 1180 | unsigned long flags; | ||
| 1181 | int ret = 0; | ||
| 1182 | |||
| 1183 | rt_mutex_init_waiter(&waiter); | ||
| 1184 | 1184 | ||
| 1185 | /* | 1185 | lockdep_assert_held(&lock->wait_lock); |
| 1186 | * Technically we could use raw_spin_[un]lock_irq() here, but this can | ||
| 1187 | * be called in early boot if the cmpxchg() fast path is disabled | ||
| 1188 | * (debug, no architecture support). In this case we will acquire the | ||
| 1189 | * rtmutex with lock->wait_lock held. But we cannot unconditionally | ||
| 1190 | * enable interrupts in that early boot case. So we need to use the | ||
| 1191 | * irqsave/restore variants. | ||
| 1192 | */ | ||
| 1193 | raw_spin_lock_irqsave(&lock->wait_lock, flags); | ||
| 1194 | 1186 | ||
| 1195 | /* Try to acquire the lock again: */ | 1187 | /* Try to acquire the lock again: */ |
| 1196 | if (try_to_take_rt_mutex(lock, current, NULL)) { | 1188 | if (try_to_take_rt_mutex(lock, current, NULL)) |
| 1197 | raw_spin_unlock_irqrestore(&lock->wait_lock, flags); | ||
| 1198 | return 0; | 1189 | return 0; |
| 1199 | } | ||
| 1200 | 1190 | ||
| 1201 | set_current_state(state); | 1191 | set_current_state(state); |
| 1202 | 1192 | ||
| 1203 | /* Setup the timer, when timeout != NULL */ | 1193 | ret = task_blocks_on_rt_mutex(lock, waiter, current, chwalk); |
| 1204 | if (unlikely(timeout)) | ||
| 1205 | hrtimer_start_expires(&timeout->timer, HRTIMER_MODE_ABS); | ||
| 1206 | |||
| 1207 | ret = task_blocks_on_rt_mutex(lock, &waiter, current, chwalk); | ||
| 1208 | 1194 | ||
| 1209 | if (likely(!ret)) | 1195 | if (likely(!ret)) |
| 1210 | /* sleep on the mutex */ | 1196 | ret = rt_mutex_slowlock_block(lock, state, NULL, waiter); |
| 1211 | ret = __rt_mutex_slowlock(lock, state, timeout, &waiter); | ||
| 1212 | 1197 | ||
| 1213 | if (unlikely(ret)) { | 1198 | if (unlikely(ret)) { |
| 1214 | __set_current_state(TASK_RUNNING); | 1199 | __set_current_state(TASK_RUNNING); |
| 1215 | remove_waiter(lock, &waiter); | 1200 | remove_waiter(lock, waiter); |
| 1216 | rt_mutex_handle_deadlock(ret, chwalk, &waiter); | 1201 | rt_mutex_handle_deadlock(ret, chwalk, waiter); |
| 1217 | } | 1202 | } |
| 1218 | 1203 | ||
| 1219 | /* | 1204 | /* |
| @@ -1221,14 +1206,45 @@ static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock, · 1 unmodified line | |||
| 1221 | * unconditionally. We might have to fix that up. | 1206 | * unconditionally. We might have to fix that up. |
| 1222 | */ | 1207 | */ |
| 1223 | fixup_rt_mutex_waiters(lock); | 1208 | fixup_rt_mutex_waiters(lock); |
| 1209 | return ret; | ||
| 1210 | } | ||
| 1224 | 1211 | ||
| 1225 | raw_spin_unlock_irqrestore(&lock->wait_lock, flags); | 1212 | static inline int __rt_mutex_slowlock_locked(struct rt_mutex_base *lock, |
| 1213 | unsigned int state) | ||
| 1214 | { | ||
| 1215 | struct rt_mutex_waiter waiter; | ||
| 1216 | int ret; | ||
| 1217 | |||
| 1218 | rt_mutex_init_waiter(&waiter); | ||
| 1226 | 1219 | ||
| 1227 | /* Remove pending timer: */ | 1220 | ret = __rt_mutex_slowlock(lock, state, RT_MUTEX_MIN_CHAINWALK, &waiter); |
| 1228 | if (unlikely(timeout)) | ||
| 1229 | hrtimer_cancel(&timeout->timer); | ||
| 1230 | 1221 | ||
| 1231 | debug_rt_mutex_free_waiter(&waiter); | 1222 | debug_rt_mutex_free_waiter(&waiter); |
| 1223 | return ret; | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | /* | ||
| 1227 | * rt_mutex_slowlock - Locking slowpath invoked when fast path fails | ||
| 1228 | * @lock: The rtmutex to block lock | ||
| 1229 | * @state: The task state for sleeping | ||
| 1230 | */ | ||
| 1231 | static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock, | ||
| 1232 | unsigned int state) | ||
| 1233 | { | ||
| 1234 | unsigned long flags; | ||
| 1235 | int ret; | ||
| 1236 | |||
| 1237 | /* | ||
| 1238 | * Technically we could use raw_spin_[un]lock_irq() here, but this can | ||
| 1239 | * be called in early boot if the cmpxchg() fast path is disabled | ||
| 1240 | * (debug, no architecture support). In this case we will acquire the | ||
| 1241 | * rtmutex with lock->wait_lock held. But we cannot unconditionally | ||
| 1242 | * enable interrupts in that early boot case. So we need to use the | ||
| 1243 | * irqsave/restore variants. | ||
| 1244 | */ | ||
| 1245 | raw_spin_lock_irqsave(&lock->wait_lock, flags); | ||
| 1246 | ret = __rt_mutex_slowlock_locked(lock, state); | ||
| 1247 | raw_spin_unlock_irqrestore(&lock->wait_lock, flags); | ||
| 1232 | 1248 | ||
| 1233 | return ret; | 1249 | return ret; |
| 1234 | } | 1250 | } |
| @@ -1239,7 +1255,7 @@ static __always_inline int __rt_mutex_lock(struct rt_mutex_base *lock, · 4 unmodified lines | |||
| 1239 | if (likely(rt_mutex_cmpxchg_acquire(lock, NULL, current))) | 1255 | if (likely(rt_mutex_cmpxchg_acquire(lock, NULL, current))) |
| 1240 | return 0; | 1256 | return 0; |
| 1241 | 1257 | ||
| 1242 | return rt_mutex_slowlock(lock, state, NULL, RT_MUTEX_MIN_CHAINWALK); | 1258 | return rt_mutex_slowlock(lock, state); |
| 1243 | } | 1259 | } |
| 1244 | 1260 | ||
| 1245 | static int __sched __rt_mutex_slowtrylock(struct rt_mutex_base *lock) | 1261 | static int __sched __rt_mutex_slowtrylock(struct rt_mutex_base *lock) |
| @@ -342,7 +342,7 @@ int __sched rt_mutex_wait_proxy_lock(struct rt_mutex_base *lock, · 341 unmodified lines | |||
| 342 | raw_spin_lock_irq(&lock->wait_lock); | 342 | raw_spin_lock_irq(&lock->wait_lock); |
| 343 | /* sleep on the mutex */ | 343 | /* sleep on the mutex */ |
| 344 | set_current_state(TASK_INTERRUPTIBLE); | 344 | set_current_state(TASK_INTERRUPTIBLE); |
| 345 | ret = __rt_mutex_slowlock(lock, TASK_INTERRUPTIBLE, to, waiter); | 345 | ret = rt_mutex_slowlock_block(lock, TASK_INTERRUPTIBLE, to, waiter); |
| 346 | /* | 346 | /* |
| 347 | * try_to_take_rt_mutex() sets the waiter bit unconditionally. We might | 347 | * try_to_take_rt_mutex() sets the waiter bit unconditionally. We might |
| 348 | * have to fix that up. | 348 | * have to fix that up. |