Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent lmms freezing when a vst hangs #4790

Closed
wants to merge 3 commits into from
Closed

Prevent lmms freezing when a vst hangs #4790

wants to merge 3 commits into from

Conversation

ghost
Copy link

@ghost ghost commented Jan 24, 2019

I've added a detection to see if a VST hangs using timed mutexes. When a VST hangs it will block the msg semaphore, but lmms still sends an idleUpdate. That idleUpdate will also block and call invalidate on the plugin.

I've added m_process.kill in case the plugin is embedded. This is necessary because at that time the windows input queues are linked and one can block the other.

justnope added 2 commits January 24, 2019 21:28
* use timed mutexes to avoid hangs
* removed HWNDPARENT call
* terminate process when invalidating
* 32 bit remote process install location change
plugins/vst_base/RemoteVstPlugin32.cmake Outdated Show resolved Hide resolved
plugins/vst_base/VstPlugin.cpp Outdated Show resolved Hide resolved

QProcess m_process;
ProcessWatcher m_watcher;

QMutex m_commMutex;
std::recursive_timed_mutex m_commMutex;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason you changed to std::recursive_timed_mutex? I think we can keep using QMutex, avoiding the MinGW compatibility problems.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to avoid QT at as much as possible when it's not related to the UI. In the longer term it would, hopefully, make it easier to separate lmms into two parts: a library and what it is now.

If it's not possible to not use QMutex for this, I'll of course change it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand wanting to avoid Qt for core functionality. I'm just not very happy about the MinGW mutex support detection & workaround and would like to avoid it being copy&pasted around the CMake scripts.

What do you think about reverting this PR to QMutex for now until (a) we find a cleaner solution or (b) we drop support for old MinGW versions? An example of how (a) could look like can be seen in 57ca681 which is part of #4443. In this commit, I added include/mingw-std-threads/mutex which shadows the system mutex using include_directories(BEFORE include/mingw-std-threads) when it's found necessary. If done correctly, this could fix MinGW thread support for all targets in the project without the need of #ifdef USE_MINGW_THREADS_REPLACEMENT checks at every include.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Give me a couple of days to think this over... I've deleted my previous msg because I responded to quickly; there may be other options.

Are we using mingw for any other reason than to cross-compile to windows?

This pr won't be merged any time soon, so we have all the time we need to find a solution that's clean and acceptable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@justnope Don't worry about using QtCore functionality inside our core, this is completely fine and we'll probably always do it. It doesn't create any coupling between core and UI. The only reason I can see to use std mutex here is re-usability outside of LMMS. However, If you ever need to use this code outside of LMMS, you can simply swap QMutex for std::recursive_timed_mutex, their APIs are compatible.

Are we using mingw for any other reason than to cross-compile to windows?

We use winegcc for RemoteVstPlugin, and we support MSYS2 on Windows which uses MinGW.

lock();
sendMessage( message( IdVstSetTempo ).addInt( _bpm ) );
unlock();
if (try_lock())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we invert the control flow here and at the other places where try_lock is used to this:

if (! try_lock())
    return;
}

I think it's more natural this way because it doesn't have the normal case inside an if condition and as a bonus we avoid all the indentation changes, which makes reviewing easier.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider it done :)

SetWindowLongPtr( (HWND)(intptr_t) m_pluginWindowID,
GWLP_HWNDPARENT,
(LONG_PTR) gui->mainWindow()->winId() );
//SetWindowLongPtr( (HWND)(intptr_t) m_pluginWindowID,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what this is for or why it was removed. @DomClark, you added this code in fcc883f. Can you chime in?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my point of view:

It's complicated.

When you do stuff like this, it solves some problems but also creates others. What this does, short version, it links processes together in a single message queue and therefor when one hangs, the other one does too.

I think this was the first version because something similar happens when the user selects "plugging embedding". I deleted it so nothing happens when they select "no embedding" and normally the same things happen when they select qt or win32 embedding.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is here to make plugin UIs always-on-top when not embedded. It does indeed attach the input queues, but that shouldn't cause any extra problems since the queues are attached in embed mode anyway. Also, plugins are generally designed to have the same input queue as the host, since most hosts load the plugin into the host's own process, so this isn't exactly a bad idea.

@ghost ghost closed this Mar 12, 2019
@lukas-w
Copy link
Member

lukas-w commented Mar 12, 2019

What's the reason for closing this @justnope? In my eyes this PR is a valuable contribution, I'd very much like to see it merged.

@ghost
Copy link
Author

ghost commented Mar 12, 2019

It's quicker to start from scratch than to revert everything.

@ghost
Copy link
Author

ghost commented Mar 18, 2019

@lukas-w I don't know what to do.

Recap: This isn't a fix, this is a work-around. When @DomClark said it isn't a bad idea to have the input queues linked together, it actually made this work-around invalid. I explained it in discord and they agreed. If they already forgot what makes this work then maybe we should rethink the approach.

Long story short: A thread blocks because a vst blocks. Also: lmms transmits using win msg queues keep alives. I've added timeouts to detect blocks (in the msg queue). If it timeouts, we kill the process and whatever. This results in also unblocking the thread waiting for a reply. And presto, lmms doesn't freeze.

If Dom already forgot what the key point of this fix is, then maybe we should rethink it. QCore doesn't provide a timeout for what we use to communicate across processes. Therefor, I used this helter-skelter fix/work-around.

It's easy to reproduce. Attach a debugger to lmms, attach one to the vst process. In the debugger, hang the vst process; lmms should recover.

  • Do I keep the current method with timeout via msg queue but that means that either GWLP_HWNDPARENT should disappear or be at least configurable.
  • Do I implement a fix for QSystemSemaphore: This can be done by waiting on https://bugreports.qt.io/browse/QTBUG-2443 or removing QSystemSemaphore and implement our own thing.

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants