Nothing to add, but I can confirm what edekock has been saying. The only slight difference being that, even without a kernel patch to change the original assert from a BUG_ON to a WARN_ON, I get both kernel.log errors; first at rtmutex.c:472 and then rtmutex.c:724. Which correspond to the following lines, with a little preceeding code for context:
rtmutex.c:472 = BUG_ON(rt_mutex_real_waiter(task->pi_blocked_on));
- Code: Select all
/*
* Task blocks on lock.
*
* Prepare waiter and propagate pi chain
*
* This must be called with lock->wait_lock held.
*/
static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
struct rt_mutex_waiter *waiter,
struct task_struct *task,
int detect_deadlock)
{
struct task_struct *owner = rt_mutex_owner(lock);
struct rt_mutex_waiter *top_waiter = waiter;
unsigned long flags;
int chain_walk = 0, res;
raw_spin_lock_irqsave(&task->pi_lock, flags);
/*
* In the case of futex requeue PI, this will be a proxy
* lock. The task will wake unaware that it is enqueueed on
* this lock. Avoid blocking on two locks and corrupting
* pi_blocked_on via the PI_WAKEUP_INPROGRESS
* flag. futex_wait_requeue_pi() sets this when it wakes up
* before requeue (due to a signal or timeout). Do not enqueue
* the task if PI_WAKEUP_INPROGRESS is set.
*/
if (task != current && task->pi_blocked_on == PI_WAKEUP_INPROGRESS) {
raw_spin_unlock_irqrestore(&task->pi_lock, flags);
return -EAGAIN;
}
BUG_ON(rt_mutex_real_waiter(task->pi_blocked_on));
rtmutex.c:724 = BUG_ON(rt_mutex_owner(lock) == self);
- Code: Select all
/*
* Slow path lock function spin_lock style: this variant is very
* careful not to miss any non-lock wakeups.
*
* We store the current state under p->pi_lock in p->saved_state and
* the try_to_wake_up() code handles this accordingly.
*/
static void noinline __sched rt_spin_lock_slowlock(struct rt_mutex *lock)
{
struct task_struct *lock_owner, *self = current;
struct rt_mutex_waiter waiter, *top_waiter;
int ret;
rt_mutex_init_waiter(&waiter, true);
raw_spin_lock(&lock->wait_lock);
init_lists(lock);
if (__try_to_take_rt_mutex(lock, self, NULL, STEAL_LATERAL)) {
raw_spin_unlock(&lock->wait_lock);
return;
}
BUG_ON(rt_mutex_owner(lock) == self);
As suggested, I've also tried changing the CriticalSection mutex to remove the PTHREAD_MUTEX_RECURSIVE attribute. With this gone, the JuceDemo doesn't even get as far as displaying its GUI, which I assume means Juce does currently rely on recursive mutexes. No kernel lock though, which could suggest either that it is an incompatibility with PI aware and recursive mutexes, or (perhaps more likely?) that the offending code no longer gets a chance to run due to an early deadlock.
Any suggestions on how I should proceed? Does anyone know for sure if recursive and priority aware attributes are mutually exclusive? Unless anyone has a better suggestion, perhaps it might be a sensible next step for me to try and replicate this (perhaps forbidden) mutex use in a stand-alone (Juce-less) app.