MidiKeyboardState deadlock


#1

I believe I’ve run into a deadlock. My synth app has a MidiKeyboardComponent, which has the keyboard focus in order to let the user play it with the QWERTY keyboard… The app plays midi loops, which paint the keyboards keys to show the user what’s being played by the loop. Every so often, when I try to pull focus away from the keyboard while the keyboard is playing (by either popping up a modal window or going to another app) the program freezes. After looking at the stack I think I have a deadlock.

The main message thread’s stack trace:

#0	0x970f7b36 in semaphore_wait_trap
#1	0x970fd653 in pthread_mutex_lock
#2	0x00003df3 in juce::CriticalSection::enter at juce_posix_SharedCode.h:52
#3	0x000033d3 in juce::GenericScopedLock<juce::CriticalSection>::GenericScopedLock at juce_ScopedLock.h:69
#4	0x000a75d9 in juce::MidiKeyboardState::allNotesOff at juce_MidiKeyboardState.cpp:112
#5	0x00165b34 in juce::MidiKeyboardComponent::resetAnyKeysInUse at juce_MidiKeyboardComponent.cpp:672
#6	0x00165bc1 in juce::MidiKeyboardComponent::focusLost at juce_MidiKeyboardComponent.cpp:896
#7	0x002f45fb in juce::Component::internalFocusLoss at juce_Component.cpp:2541
#8	0x00324ea9 in juce::ComponentPeer::handleFocusLoss at juce_ComponentPeer.cpp:341
#9	0x0040773a in juce::NSViewComponentPeer::viewFocusGain at juce_mac_NSViewComponentPeer.mm:1072
#10	0x004077f5 in juce::JuceNSViewClass::becomeFirstResponder at juce_mac_NSViewComponentPeer.mm:1587
#11	0x908d08b0 in -[NSWindow makeFirstResponder:]
#12	0x004077b9 in juce::NSViewComponentPeer::grabFocus at juce_mac_NSViewComponentPeer.mm:1099
#13	0x0041488d in juce::NSViewComponentPeer::becomeKeyWindow at juce_mac_NSViewComponentPeer.mm:816
#14	0x004148d8 in juce::JuceNSWindowClass::becomeKeyWindow at juce_mac_NSViewComponentPeer.mm:1690
#15	0x908ccd7b in -[NSWindow _changeKeyAndMainLimitedOK:]
#16	0x908cca38 in -[NSWindow makeKeyWindow]
#17	0x908cc9a7 in -[NSWindow _makeKeyRegardlessOfVisibility]
#18	0x908cc8ed in -[NSWindow makeKeyAndOrderFront:]
#19	0x00414740 in juce::NSViewComponentPeer::toFront at juce_mac_NSViewComponentPeer.mm:432
#20	0x00349a26 in juce::Component::toFront at juce_Component.cpp:793
#21	0x00349bcb in juce::TopLevelWindow::visibilityChanged at juce_TopLevelWindow.cpp:197
#22	0x002f4083 in juce::Component::sendVisibilityChangeMessage at juce_Component.cpp:487
#23	0x0033328b in juce::Component::setVisible at juce_Component.cpp:468
#24	0x0032abfc in juce::Component::enterModalState at juce_Component.cpp:1620
#25	0x003485d3 in juce::Component::runModalLoop at juce_Component.cpp:1594
#26	0x00414442 in juce::AlertWindowInfo::show at juce_AlertWindow.cpp:604
#27	0x004144cf in juce::AlertWindowInfo::showCallback at juce_AlertWindow.cpp:616
#28	0x0020c428 in juce::MessageManager::callFunctionOnMessageThread at juce_MessageManager.cpp:162
#29	0x003fcaec in juce::AlertWindowInfo::invoke at juce_AlertWindow.cpp:580
#30	0x003256a0 in juce::AlertWindow::showOkCancelBox at juce_AlertWindow.cpp:679
#31	0x000153ec in ChallengeComponent::buttonClicked at ChallengeComponent.cpp:330

And one of the background thread’s stack trace:

#0	0x97125aa2 in __semwait_signal
#1	0x9712575e in _pthread_cond_wait
#2	0x971252b1 in pthread_cond_timedwait$UNIX2003
#3	0x001db6bb in juce::WaitableEventImpl::wait at juce_posix_SharedCode.h:121
#4	0x00191278 in juce::WaitableEvent::wait at juce_posix_SharedCode.h:174
#5	0x00210213 in juce::MessageManagerLock::attemptLock at juce_MessageManager.cpp:287
#6	0x002103b4 in juce::MessageManagerLock::MessageManagerLock at juce_MessageManager.cpp:249
#7	0x00052833 in MyKeyboardComponent::handleNoteOn at SynthComponent.cpp:72
#8	0x0009bef4 in juce::MidiKeyboardState::noteOnInternal at juce_MidiKeyboardState.cpp:81
#9	0x0009ea91 in juce::MidiKeyboardState::processNextMidiEvent at juce_MidiKeyboardState.cpp:130
#10	0x000ab37d in juce::MidiKeyboardState::processNextMidiBuffer at juce_MidiKeyboardState.cpp:155
#11	0x00040af4 in SynthAudioSource::getNextAudioBlock at SynthAudioSource.cpp:198

It seems that if I pull focus away at exactly the same time that the keyboard tries to play a note, the Main Message thread creates a lock while the background thread creates a MessageManagerLock. Am I correct in diagnosing this as a deadlock?

If so, I’m racking my brain as to a way around this. There’s definitely going to be times when the user pulls focus while playing, and I need the focus on the MidiKeyboard so they can play it. Any suggestions?


#2

Your code is blocking on a MessageManagerLock, and it’s deadlocking with the UI thread. Just send a message instead of blocking.


#3

:oops:

I originally had that lock on to allow my handleNoteOn to access the UI. But I had since changed that, didn’t need the lock anymore, but forgot to erase it. Thanks.