Skip to content

Commit fe98a9a

Browse files
DomClarkzonkmachine
authored andcommitted
Fix some VST deadlocks/hangs
1 parent 9d7c340 commit fe98a9a

5 files changed

Lines changed: 179 additions & 54 deletions

File tree

include/MainWindow.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <QtCore/QTimer>
3030
#include <QtCore/QList>
3131
#include <QMainWindow>
32+
#include <QThread>
3233

3334
#include "ConfigManager.h"
3435
#include "SubWindow.h"
@@ -248,4 +249,11 @@ private slots:
248249

249250
} ;
250251

252+
class AutoSaveThread : public QThread
253+
{
254+
Q_OBJECT
255+
public:
256+
void run();
257+
} ;
258+
251259
#endif

include/RemotePlugin.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,14 @@ RemotePluginBase::message RemotePluginBase::waitForMessage(
10721072
const message & _wm,
10731073
bool _busy_waiting )
10741074
{
1075+
#ifndef BUILD_REMOTE_PLUGIN_CLIENT
1076+
if( _busy_waiting )
1077+
{
1078+
// No point processing events outside of the main thread
1079+
_busy_waiting = QThread::currentThread() ==
1080+
QCoreApplication::instance()->thread();
1081+
}
1082+
#endif
10751083
while( !isInvalid() )
10761084
{
10771085
#ifndef BUILD_REMOTE_PLUGIN_CLIENT

plugins/vst_base/RemoteVstPlugin.cpp

Lines changed: 142 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444

4545
#ifdef LMMS_BUILD_LINUX
4646

47+
#ifndef NOMINMAX
48+
#define NOMINMAX
49+
#endif
50+
4751
#ifndef O_BINARY
4852
#define O_BINARY 0
4953
#endif
@@ -67,6 +71,7 @@
6771

6872

6973
#include <vector>
74+
#include <queue>
7075
#include <string>
7176

7277

@@ -113,7 +118,7 @@ class RemoteVstPlugin;
113118

114119
RemoteVstPlugin * __plugin = NULL;
115120

116-
DWORD __GuiThreadID = 0;
121+
HWND __MessageHwnd = NULL;
117122

118123

119124

@@ -244,8 +249,38 @@ class RemoteVstPlugin : public RemotePluginClient
244249
pthread_mutex_unlock( &m_pluginLock );
245250
}
246251

252+
inline bool isProcessing() const
253+
{
254+
return m_processing;
255+
}
256+
257+
inline void setProcessing( bool processing )
258+
{
259+
m_processing = processing;
260+
}
261+
262+
inline void queueMessage( const message & m ) {
263+
m_messageList.push( m );
264+
}
265+
266+
inline bool shouldGiveIdle() const
267+
{
268+
return m_shouldGiveIdle;
269+
}
270+
271+
inline void setShouldGiveIdle( bool shouldGiveIdle )
272+
{
273+
m_shouldGiveIdle = shouldGiveIdle;
274+
}
275+
276+
void idle();
277+
void processUIThreadMessages();
278+
247279
static DWORD WINAPI processingThread( LPVOID _param );
248-
static DWORD WINAPI guiEventLoop( LPVOID _param );
280+
static bool setupMessageWindow();
281+
static DWORD WINAPI guiEventLoop();
282+
static LRESULT CALLBACK messageWndProc( HWND hwnd, UINT uMsg,
283+
WPARAM wParam, LPARAM lParam );
249284

250285

251286
private:
@@ -303,6 +338,10 @@ class RemoteVstPlugin : public RemotePluginClient
303338
bool m_initialized;
304339

305340
pthread_mutex_t m_pluginLock;
341+
bool m_processing;
342+
343+
std::queue<message> m_messageList;
344+
bool m_shouldGiveIdle;
306345

307346

308347
float * * m_inputs;
@@ -348,6 +387,9 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) :
348387
m_windowHeight( 0 ),
349388
m_initialized( false ),
350389
m_pluginLock(),
390+
m_processing( false ),
391+
m_messageList(),
392+
m_shouldGiveIdle( false ),
351393
m_inputs( NULL ),
352394
m_outputs( NULL ),
353395
m_midiEvents(),
@@ -1418,8 +1460,7 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
14181460
SHOW_CALLBACK ("amc: audioMasterIdle\n" );
14191461
// call application idle routine (this will
14201462
// call effEditIdle for all open editors too)
1421-
PostThreadMessage( __GuiThreadID,
1422-
WM_USER, GiveIdle, 0 );
1463+
PostMessage( __MessageHwnd, WM_USER, GiveIdle, 0 );
14231464
return 0;
14241465

14251466
case audioMasterPinConnected:
@@ -1720,8 +1761,7 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
17201761
case audioMasterUpdateDisplay:
17211762
SHOW_CALLBACK( "amc: audioMasterUpdateDisplay\n" );
17221763
// something has changed, update 'multi-fx' display
1723-
PostThreadMessage( __GuiThreadID,
1724-
WM_USER, GiveIdle, 0 );
1764+
PostMessage( __MessageHwnd, WM_USER, GiveIdle, 0 );
17251765
return 0;
17261766

17271767
#if kVstVersion > 2
@@ -1754,6 +1794,43 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
17541794

17551795

17561796

1797+
void RemoteVstPlugin::idle()
1798+
{
1799+
if( isProcessing() )
1800+
{
1801+
setShouldGiveIdle( true );
1802+
return;
1803+
}
1804+
setProcessing( true );
1805+
pluginDispatch( effEditIdle );
1806+
setShouldGiveIdle( false );
1807+
setProcessing( false );
1808+
// We might have received a message whilst idling
1809+
processUIThreadMessages();
1810+
}
1811+
1812+
1813+
1814+
1815+
void RemoteVstPlugin::processUIThreadMessages()
1816+
{
1817+
setProcessing( true );
1818+
while( m_messageList.size() )
1819+
{
1820+
processMessage( m_messageList.front() );
1821+
m_messageList.pop();
1822+
if( shouldGiveIdle() )
1823+
{
1824+
pluginDispatch( effEditIdle );
1825+
setShouldGiveIdle( false );
1826+
}
1827+
}
1828+
setProcessing( false );
1829+
}
1830+
1831+
1832+
1833+
17571834
DWORD WINAPI RemoteVstPlugin::processingThread( LPVOID _param )
17581835
{
17591836
RemoteVstPlugin * _this = static_cast<RemoteVstPlugin *>( _param );
@@ -1767,80 +1844,99 @@ DWORD WINAPI RemoteVstPlugin::processingThread( LPVOID _param )
17671844
}
17681845
else
17691846
{
1770-
PostThreadMessage( __GuiThreadID,
1847+
PostMessage( __MessageHwnd,
17711848
WM_USER,
17721849
ProcessPluginMessage,
17731850
(LPARAM) new message( m ) );
17741851
}
17751852
}
17761853

17771854
// notify GUI thread about shutdown
1778-
PostThreadMessage( __GuiThreadID, WM_USER, ClosePlugin, 0 );
1855+
PostMessage( __MessageHwnd, WM_USER, ClosePlugin, 0 );
17791856

17801857
return 0;
17811858
}
17821859

17831860

17841861

17851862

1786-
DWORD WINAPI RemoteVstPlugin::guiEventLoop( LPVOID _param )
1863+
bool RemoteVstPlugin::setupMessageWindow()
17871864
{
1788-
RemoteVstPlugin * _this = static_cast<RemoteVstPlugin *>( _param );
1789-
17901865
HMODULE hInst = GetModuleHandle( NULL );
17911866
if( hInst == NULL )
17921867
{
1793-
_this->debugMessage( "guiEventLoop(): can't get "
1868+
__plugin->debugMessage( "setupMessageWindow(): can't get "
17941869
"module handle\n" );
1795-
return -1;
1870+
return false;
17961871
}
17971872

1798-
HWND timerWindow = CreateWindowEx( 0, "LVSL", "dummy",
1873+
__MessageHwnd = CreateWindowEx( 0, "LVSL", "dummy",
17991874
0, 0, 0, 0, 0, NULL, NULL,
18001875
hInst, NULL );
1876+
SetWindowLongPtr( __MessageHwnd, GWLP_WNDPROC,
1877+
reinterpret_cast<LONG_PTR>( RemoteVstPlugin::messageWndProc ) );
18011878
// install GUI update timer
1802-
SetTimer( timerWindow, 1000, 50, NULL );
1879+
SetTimer( __MessageHwnd, 1000, 50, NULL );
1880+
1881+
return true;
1882+
}
1883+
18031884

1804-
MSG msg;
18051885

1806-
bool quit = false;
1807-
while( quit == false && GetMessage( &msg, NULL, 0, 0 ) )
1886+
1887+
DWORD WINAPI RemoteVstPlugin::guiEventLoop()
1888+
{
1889+
MSG msg;
1890+
while( GetMessage( &msg, NULL, 0, 0 ) > 0 )
18081891
{
18091892
TranslateMessage( &msg );
18101893
DispatchMessage( &msg );
1894+
}
18111895

1812-
if( msg.message == WM_TIMER && _this->isInitialized() )
1813-
{
1814-
// give plugin some idle-time for GUI-update
1815-
_this->pluginDispatch( effEditIdle );
1816-
}
1817-
else if( msg.message == WM_USER )
1896+
return 0;
1897+
}
1898+
1899+
1900+
1901+
1902+
LRESULT CALLBACK RemoteVstPlugin::messageWndProc( HWND hwnd, UINT uMsg,
1903+
WPARAM wParam, LPARAM lParam )
1904+
{
1905+
if( uMsg == WM_TIMER && __plugin->isInitialized() )
1906+
{
1907+
// give plugin some idle-time for GUI-update
1908+
__plugin->idle();
1909+
return 0;
1910+
}
1911+
else if( uMsg == WM_USER )
1912+
{
1913+
switch( wParam )
18181914
{
1819-
switch( msg.wParam )
1915+
case ProcessPluginMessage:
18201916
{
1821-
case ProcessPluginMessage:
1917+
message * m = (message *) lParam;
1918+
__plugin->queueMessage( *m );
1919+
delete m;
1920+
if( !__plugin->isProcessing() )
18221921
{
1823-
message * m = (message *) msg.lParam;
1824-
_this->processMessage( *m );
1825-
delete m;
1826-
break;
1922+
__plugin->processUIThreadMessages();
18271923
}
1924+
return 0;
1925+
}
18281926

1829-
case GiveIdle:
1830-
_this->pluginDispatch( effEditIdle );
1831-
break;
1927+
case GiveIdle:
1928+
__plugin->idle();
1929+
return 0;
18321930

1833-
case ClosePlugin:
1834-
quit = true;
1835-
break;
1931+
case ClosePlugin:
1932+
PostQuitMessage(0);
1933+
return 0;
18361934

1837-
default:
1838-
break;
1839-
}
1935+
default:
1936+
break;
18401937
}
18411938
}
1842-
1843-
return 0;
1939+
return DefWindowProc( hwnd, uMsg, wParam, lParam );
18441940
}
18451941

18461942

@@ -1893,15 +1989,18 @@ int main( int _argc, char * * _argv )
18931989

18941990
if( __plugin->isInitialized() )
18951991
{
1896-
__GuiThreadID = GetCurrentThreadId();
1992+
if( RemoteVstPlugin::setupMessageWindow() == false )
1993+
{
1994+
return -1;
1995+
}
18971996
if( CreateThread( NULL, 0, RemoteVstPlugin::processingThread,
18981997
__plugin, 0, NULL ) == NULL )
18991998
{
19001999
__plugin->debugMessage( "could not create "
19012000
"processingThread\n" );
19022001
return -1;
19032002
}
1904-
RemoteVstPlugin::guiEventLoop( __plugin );
2003+
RemoteVstPlugin::guiEventLoop();
19052004
}
19062005

19072006

0 commit comments

Comments
 (0)