@@ -254,6 +254,29 @@ double_unlock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
spin_unlock(&hb2->lock);
}
+static inline void futex_trylock_hblock(spinlock_t *lock)
+{
+ do {
+ ktime_t chill_time;;
+
+ /*
+ * Current is not longer pi_blocked_on if it owns the lock. It
+ * can still have pi_blocked_on set if the lock acquiring was
+ * interrupted by signal or timeout. The trylock operation does
+ * not clobber pi_blocked_on so it is the only option.
+ * Should the try-lock operation fail then it needs leave the CPU
+ * to avoid a busy loop in case it is the task with the highest
+ * priority.
+ */
+ if (spin_trylock(lock))
+ return;
+
+ chill_time = ktime_set(0, NSEC_PER_MSEC);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_hrtimeout(&chill_time, HRTIMER_MODE_REL_HARD);
+ } while (1);
+}
+
/* syscalls */
extern int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, u32
@@ -1046,7 +1046,10 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl
ret = rt_mutex_wait_proxy_lock(&q.pi_state->pi_mutex, to, &rt_waiter);
cleanup:
- spin_lock(q.lock_ptr);
+ rt_mutex_post_schedule();
+
+ futex_trylock_hblock(q.lock_ptr);
+
/*
* If we failed to acquire the lock (deadlock/signal/timeout), we must
* first acquire the hb->lock before removing the lock from the
@@ -1058,11 +1061,6 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl
*/
if (ret && !rt_mutex_cleanup_proxy_lock(&q.pi_state->pi_mutex, &rt_waiter))
ret = 0;
-
- /*
- * Waiter is unqueued.
- */
- rt_mutex_post_schedule();
no_block:
/*
* Fixup the pi_state owner and possibly acquire the lock if we
@@ -850,8 +850,8 @@ int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
pi_mutex = &q.pi_state->pi_mutex;
ret = rt_mutex_wait_proxy_lock(pi_mutex, to, &rt_waiter);
- /* Current is not longer pi_blocked_on */
- spin_lock(q.lock_ptr);
+ futex_trylock_hblock(q.lock_ptr);
+
if (ret && !rt_mutex_cleanup_proxy_lock(pi_mutex, &rt_waiter))
ret = 0;
@@ -1166,10 +1166,13 @@ try_to_take_rt_mutex(struct rt_mutex_base *lock, struct task_struct *task,
* Clear @task->pi_blocked_on. Requires protection by
* @task->pi_lock. Redundant operation for the @waiter == NULL
* case, but conditionals are more expensive than a redundant
- * store.
+ * store. But then there is FUTEX and if rt_mutex_wait_proxy_lock()
+ * did not acquire the lock it try-locks another lock before it clears
+ * @task->pi_blocked_on so we mustn't clear it here premature.
*/
raw_spin_lock(&task->pi_lock);
- task->pi_blocked_on = NULL;
+ if (waiter)
+ task->pi_blocked_on = NULL;
/*
* Finish the lock acquisition. @task is the new owner. If
* other waiters exist we have to insert the highest priority
@@ -1045,7 +1045,7 @@ static bool report_idle_softirq(void)
return false;
/* On RT, softirqs handling may be waiting on some lock */
- if (!local_bh_blocked())
+ if (local_bh_blocked())
return false;
pr_warn("NOHZ tick-stop error: local softirq work is pending, handler #%02x!!!\n",
@@ -1 +1 @@
--rt5
+-rt6