/* * Slow path lock function: */ static int __sched rt_mutex_slowlock(struct rt_mutex *lock, int state, struct hrtimer_sleeper *timeout, int detect_deadlock) { struct rt_mutex_waiter waiter; int ret = 0; debug_rt_mutex_init_waiter(&waiter); waiter.task = NULL; raw_spin_lock(&lock->wait_lock); /* Try to acquire the lock again: */ if (try_to_take_rt_mutex(lock)) { raw_spin_unlock(&lock->wait_lock); return 0; } set_current_state(state); /* Setup the timer, when timeout != NULL */ if (unlikely(timeout)) { hrtimer_start_expires(&timeout->timer, HRTIMER_MODE_ABS); if (!hrtimer_active(&timeout->timer)) timeout->task = NULL; } ret = __rt_mutex_slowlock(lock, state, timeout, &waiter, detect_deadlock); set_current_state(TASK_RUNNING); if (unlikely(waiter.task)) remove_waiter(lock, &waiter); /* * try_to_take_rt_mutex() sets the waiter bit * unconditionally. We might have to fix that up. */ fixup_rt_mutex_waiters(lock); raw_spin_unlock(&lock->wait_lock); /* Remove pending timer: */ if (unlikely(timeout)) hrtimer_cancel(&timeout->timer); /* * Readjust priority, when we did not get the lock. We might * have been the pending owner and boosted. Since we did not * take the lock, the PI boost has to go. */ if (unlikely(ret)) rt_mutex_adjust_prio(current); debug_rt_mutex_free_waiter(&waiter); return ret; }
/* * Slow path lock function: */ static int __sched rt_mutex_slowlock(struct rt_mutex *lock, int state, struct hrtimer_sleeper *timeout, int detect_deadlock) { struct rt_mutex_waiter waiter; int ret = 0; debug_rt_mutex_init_waiter(&waiter); RB_CLEAR_NODE(&waiter.pi_tree_entry); RB_CLEAR_NODE(&waiter.tree_entry); raw_spin_lock(&lock->wait_lock); /* Try to acquire the lock again: */ if (try_to_take_rt_mutex(lock, current, NULL)) { raw_spin_unlock(&lock->wait_lock); return 0; } set_current_state(state); /* Setup the timer, when timeout != NULL */ if (unlikely(timeout)) { hrtimer_start_expires(&timeout->timer, HRTIMER_MODE_ABS); if (!hrtimer_active(&timeout->timer)) timeout->task = NULL; } ret = task_blocks_on_rt_mutex(lock, &waiter, current, detect_deadlock); if (likely(!ret)) ret = __rt_mutex_slowlock(lock, state, timeout, &waiter); set_current_state(TASK_RUNNING); if (unlikely(ret)) remove_waiter(lock, &waiter); /* * try_to_take_rt_mutex() sets the waiter bit * unconditionally. We might have to fix that up. */ fixup_rt_mutex_waiters(lock); raw_spin_unlock(&lock->wait_lock); /* Remove pending timer: */ if (unlikely(timeout)) hrtimer_cancel(&timeout->timer); debug_rt_mutex_free_waiter(&waiter); return ret; }
/* * Slow path lock function: */ static int __sched rt_mutex_slowlock(struct rt_mutex *lock, int state, struct hrtimer_sleeper *timeout, int detect_deadlock) { int ret = 0, saved_lock_depth = -1; struct rt_mutex_waiter waiter; unsigned long flags; debug_rt_mutex_init_waiter(&waiter); waiter.task = NULL; spin_lock_irqsave(&lock->wait_lock, flags); init_lists(lock); /* Try to acquire the lock again: */ if (try_to_take_rt_mutex(lock)) { spin_unlock_irqrestore(&lock->wait_lock, flags); return 0; } /* * We drop the BKL here before we go into the wait loop to avoid a * possible deadlock in the scheduler. */ if (unlikely(current->lock_depth >= 0)) saved_lock_depth = rt_release_bkl(lock, flags); set_current_state(state); /* Setup the timer, when timeout != NULL */ if (unlikely(timeout)) hrtimer_start(&timeout->timer, timeout->timer.expires, HRTIMER_MODE_ABS); for (;;) { unsigned long saved_flags; /* Try to acquire the lock: */ if (try_to_take_rt_mutex(lock)) break; /* * TASK_INTERRUPTIBLE checks for signals and * timeout. Ignored otherwise. */ if (unlikely(state == TASK_INTERRUPTIBLE)) { /* Signal pending? */ if (signal_pending(current)) ret = -EINTR; if (timeout && !timeout->task) ret = -ETIMEDOUT; if (ret) break; } /* * waiter.task is NULL the first time we come here and * when we have been woken up by the previous owner * but the lock got stolen by a higher prio task. */ if (!waiter.task) { ret = task_blocks_on_rt_mutex(lock, &waiter, detect_deadlock, flags); /* * If we got woken up by the owner then start loop * all over without going into schedule to try * to get the lock now: */ if (unlikely(!waiter.task)) continue; if (unlikely(ret)) break; } saved_flags = current->flags & PF_NOSCHED; current->flags &= ~PF_NOSCHED; spin_unlock_irq(&lock->wait_lock); debug_rt_mutex_print_deadlock(&waiter); if (waiter.task) schedule_rt_mutex(lock); spin_lock_irq(&lock->wait_lock); current->flags |= saved_flags; set_current_state(state); } set_current_state(TASK_RUNNING); if (unlikely(waiter.task)) remove_waiter(lock, &waiter, flags); /* * try_to_take_rt_mutex() sets the waiter bit * unconditionally. We might have to fix that up. */ fixup_rt_mutex_waiters(lock); spin_unlock_irqrestore(&lock->wait_lock, flags); /* Remove pending timer: */ if (unlikely(timeout)) hrtimer_cancel(&timeout->timer); /* * Readjust priority, when we did not get the lock. We might * have been the pending owner and boosted. Since we did not * take the lock, the PI boost has to go. */ if (unlikely(ret)) rt_mutex_adjust_prio(current); /* Must we reaquire the BKL? */ if (unlikely(saved_lock_depth >= 0)) rt_reacquire_bkl(saved_lock_depth); debug_rt_mutex_free_waiter(&waiter); return ret; }
/* * Slow path lock function spin_lock style: this variant is very * careful not to miss any non-lock wakeups. * * The wakeup side uses wake_up_process_mutex, which, combined with * the xchg code of this function is a transparent sleep/wakeup * mechanism nested within any existing sleep/wakeup mechanism. This * enables the seemless use of arbitrary (blocking) spinlocks within * sleep/wakeup event loops. */ static void fastcall noinline __sched rt_spin_lock_slowlock(struct rt_mutex *lock) { struct rt_mutex_waiter waiter; unsigned long saved_state, state, flags; debug_rt_mutex_init_waiter(&waiter); waiter.task = NULL; spin_lock_irqsave(&lock->wait_lock, flags); init_lists(lock); /* Try to acquire the lock again: */ if (try_to_take_rt_mutex(lock)) { spin_unlock_irqrestore(&lock->wait_lock, flags); return; } BUG_ON(rt_mutex_owner(lock) == current); /* * Here we save whatever state the task was in originally, * we'll restore it at the end of the function and we'll take * any intermediate wakeup into account as well, independently * of the lock sleep/wakeup mechanism. When we get a real * wakeup the task->state is TASK_RUNNING and we change * saved_state accordingly. If we did not get a real wakeup * then we return with the saved state. */ saved_state = xchg(¤t->state, TASK_UNINTERRUPTIBLE); for (;;) { unsigned long saved_flags; int saved_lock_depth = current->lock_depth; /* Try to acquire the lock */ if (try_to_take_rt_mutex(lock)) break; /* * waiter.task is NULL the first time we come here and * when we have been woken up by the previous owner * but the lock got stolen by an higher prio task. */ if (!waiter.task) { task_blocks_on_rt_mutex(lock, &waiter, 0, flags); /* Wakeup during boost ? */ if (unlikely(!waiter.task)) continue; } /* * Prevent schedule() to drop BKL, while waiting for * the lock ! We restore lock_depth when we come back. */ saved_flags = current->flags & PF_NOSCHED; current->lock_depth = -1; current->flags &= ~PF_NOSCHED; spin_unlock_irqrestore(&lock->wait_lock, flags); debug_rt_mutex_print_deadlock(&waiter); schedule_rt_mutex(lock); spin_lock_irqsave(&lock->wait_lock, flags); current->flags |= saved_flags; current->lock_depth = saved_lock_depth; state = xchg(¤t->state, TASK_UNINTERRUPTIBLE); if (unlikely(state == TASK_RUNNING)) saved_state = TASK_RUNNING; } state = xchg(¤t->state, saved_state); if (unlikely(state == TASK_RUNNING)) current->state = TASK_RUNNING; /* * Extremely rare case, if we got woken up by a non-mutex wakeup, * and we managed to steal the lock despite us not being the * highest-prio waiter (due to SCHED_OTHER changing prio), then we * can end up with a non-NULL waiter.task: */ if (unlikely(waiter.task)) remove_waiter(lock, &waiter, flags); /* * try_to_take_rt_mutex() sets the waiter bit * unconditionally. We might have to fix that up: */ fixup_rt_mutex_waiters(lock); spin_unlock_irqrestore(&lock->wait_lock, flags); debug_rt_mutex_free_waiter(&waiter); }
/* * Slow path lock function spin_lock style: this variant is very * careful not to miss any non-lock wakeups. * * The wakeup side uses wake_up_process_mutex, which, combined with * the xchg code of this function is a transparent sleep/wakeup * mechanism nested within any existing sleep/wakeup mechanism. This * enables the seemless use of arbitrary (blocking) spinlocks within * sleep/wakeup event loops. */ static void noinline __sched rt_spin_lock_slowlock(struct rt_mutex *lock) { struct rt_mutex_waiter waiter; unsigned long saved_state, flags; /* orig_owner is only set if next_waiter is set */ struct task_struct *uninitialized_var(orig_owner); int next_waiter; int saved_lock_depth; int ret; debug_rt_mutex_init_waiter(&waiter); waiter.task = NULL; raw_spin_lock_irqsave(&lock->wait_lock, flags); init_lists(lock); if (do_try_to_take_rt_mutex(lock, current, NULL, STEAL_LATERAL)) { raw_spin_unlock_irqrestore(&lock->wait_lock, flags); return; } BUG_ON(rt_mutex_owner(lock) == current); /* * Here we save whatever state the task was in originally, * we'll restore it at the end of the function and we'll take * any intermediate wakeup into account as well, independently * of the lock sleep/wakeup mechanism. When we get a real * wakeup the task->state is TASK_RUNNING and we change * saved_state accordingly. If we did not get a real wakeup * then we return with the saved state. We need to be careful * about original state TASK_INTERRUPTIBLE as well, as we * could miss a wakeup_interruptible() */ saved_state = rt_set_current_blocked_state(current->state); /* * Prevent schedule() to drop BKL, while waiting for * the lock ! We restore lock_depth when we come back. */ saved_lock_depth = current->lock_depth; current->lock_depth = -1; ret = task_blocks_on_rt_mutex(lock, &waiter, current, 0, flags, 1); BUG_ON(ret); for (;;) { int sleep = 1; /* Try to acquire the lock again. */ if (do_try_to_take_rt_mutex(lock, current, &waiter, STEAL_LATERAL)) break; next_waiter = &waiter == rt_mutex_top_waiter(lock); if (next_waiter) { orig_owner = rt_mutex_owner(lock); if (orig_owner) get_task_struct(orig_owner); } raw_spin_unlock_irqrestore(&lock->wait_lock, flags); debug_rt_mutex_print_deadlock(&waiter); if (next_waiter && orig_owner) { if (!adaptive_wait(&waiter, orig_owner)) sleep = 0; put_task_struct(orig_owner); } if (sleep) schedule_rt_mutex(lock); raw_spin_lock_irqsave(&lock->wait_lock, flags); saved_state = rt_set_current_blocked_state(saved_state); } current->lock_depth = saved_lock_depth; rt_restore_current_state(saved_state); /* * try_to_take_rt_mutex() sets the waiter bit * unconditionally. We might have to fix that up: */ fixup_rt_mutex_waiters(lock); BUG_ON(rt_mutex_has_waiters(lock) && &waiter == rt_mutex_top_waiter(lock)); BUG_ON(!plist_node_empty(&waiter.list_entry)); raw_spin_unlock_irqrestore(&lock->wait_lock, flags); debug_rt_mutex_free_waiter(&waiter); }
/* * Slow path lock function: */ static int __sched rt_mutex_slowlock(struct rt_mutex *lock, int state, struct hrtimer_sleeper *timeout, int detect_deadlock) { int ret = 0, saved_lock_depth = -1; struct rt_mutex_waiter waiter; unsigned long flags; debug_rt_mutex_init_waiter(&waiter); raw_spin_lock_irqsave(&lock->wait_lock, flags); init_lists(lock); /* Try to acquire the lock again: */ if (try_to_take_rt_mutex(lock, current, NULL)) { raw_spin_unlock_irqrestore(&lock->wait_lock, flags); return 0; } set_current_state(state); /* Setup the timer, when timeout != NULL */ if (unlikely(timeout)) { hrtimer_start_expires(&timeout->timer, HRTIMER_MODE_ABS); if (!hrtimer_active(&timeout->timer)) timeout->task = NULL; } ret = task_blocks_on_rt_mutex(lock, &waiter, current, detect_deadlock, flags, 0); /* * We drop the BKL here before we go into the wait loop to avoid a * possible deadlock in the scheduler. * * Note: This must be done after we call task_blocks_on_rt_mutex * because rt_release_bkl() releases the wait_lock and will * cause a race between setting the mark waiters flag in * the owner field and adding this task to the wait list. Those * two must be done within the protection of the wait_lock. */ if (unlikely(current->lock_depth >= 0)) saved_lock_depth = rt_release_bkl(lock, flags); if (likely(!ret)) ret = __rt_mutex_slowlock(lock, state, timeout, &waiter, flags); set_current_state(TASK_RUNNING); if (unlikely(ret)) remove_waiter(lock, &waiter, flags); BUG_ON(!plist_node_empty(&waiter.list_entry)); /* * try_to_take_rt_mutex() sets the waiter bit * unconditionally. We might have to fix that up. */ fixup_rt_mutex_waiters(lock); raw_spin_unlock_irqrestore(&lock->wait_lock, flags); /* Remove pending timer: */ if (unlikely(timeout)) hrtimer_cancel(&timeout->timer); /* Must we reaquire the BKL? */ if (unlikely(saved_lock_depth >= 0)) rt_reacquire_bkl(saved_lock_depth); debug_rt_mutex_free_waiter(&waiter); return ret; }
/* * Slow path lock function: */ static int __sched rt_mutex_slowlock(struct rt_mutex *lock, int state, struct hrtimer_sleeper *timeout, int detect_deadlock) { struct rt_mutex_waiter waiter; int ret = 0; debug_rt_mutex_init_waiter(&waiter); waiter.task = NULL; spin_lock(&lock->wait_lock); /* Try to acquire the lock again: */ if (try_to_take_rt_mutex(lock)) { spin_unlock(&lock->wait_lock); return 0; } set_current_state(state); /* Setup the timer, when timeout != NULL */ if (unlikely(timeout)) hrtimer_start(&timeout->timer, timeout->timer.expires, HRTIMER_MODE_ABS); for (;;) { /* Try to acquire the lock: */ if (try_to_take_rt_mutex(lock)) break; /* * TASK_INTERRUPTIBLE checks for signals and * timeout. Ignored otherwise. */ if (unlikely(state == TASK_INTERRUPTIBLE)) { /* Signal pending? */ if (signal_pending(current)) ret = -EINTR; if (timeout && !timeout->task) ret = -ETIMEDOUT; if (ret) break; } /* * waiter.task is NULL the first time we come here and * when we have been woken up by the previous owner * but the lock got stolen by a higher prio task. */ if (!waiter.task) { ret = task_blocks_on_rt_mutex(lock, &waiter, detect_deadlock); /* * If we got woken up by the owner then start loop * all over without going into schedule to try * to get the lock now: */ if (unlikely(!waiter.task)) { /* * Reset the return value. We might * have returned with -EDEADLK and the * owner released the lock while we * were walking the pi chain. */ ret = 0; continue; } if (unlikely(ret)) break; } spin_unlock(&lock->wait_lock); debug_rt_mutex_print_deadlock(&waiter); if (waiter.task) schedule_rt_mutex(lock); spin_lock(&lock->wait_lock); set_current_state(state); } set_current_state(TASK_RUNNING); if (unlikely(waiter.task)) remove_waiter(lock, &waiter); /* * try_to_take_rt_mutex() sets the waiter bit * unconditionally. We might have to fix that up. */ fixup_rt_mutex_waiters(lock); spin_unlock(&lock->wait_lock); /* Remove pending timer: */ if (unlikely(timeout)) hrtimer_cancel(&timeout->timer); /* * Readjust priority, when we did not get the lock. We might * have been the pending owner and boosted. Since we did not * take the lock, the PI boost has to go. */ if (unlikely(ret)) rt_mutex_adjust_prio(current); debug_rt_mutex_free_waiter(&waiter); return ret; }