Merge pull request #2739 from jasp00/sync-socket

Synchronize with remote plugins using local sockets
This commit is contained in:
Javier Serrano Polo
2016-06-04 00:34:30 +00:00
9 changed files with 409 additions and 91 deletions

View File

@@ -40,6 +40,12 @@
#include <unistd.h>
#endif
#ifndef SYNC_WITH_SHM_FIFO
#include <QtCore/QUuid>
#include <sys/socket.h>
#include <sys/un.h>
#endif
// simple helper thread monitoring our RemotePlugin - if process terminates
// unexpectedly invalidate plugin so LMMS doesn't lock up
@@ -70,7 +76,12 @@ void ProcessWatcher::run()
RemotePlugin::RemotePlugin() :
QObject(),
#ifdef SYNC_WITH_SHM_FIFO
RemotePluginBase( new shmFifo(), new shmFifo() ),
#else
RemotePluginBase(),
#endif
m_failed( true ),
m_process(),
m_watcher( this ),
@@ -86,6 +97,34 @@ RemotePlugin::RemotePlugin() :
m_inputCount( DEFAULT_CHANNELS ),
m_outputCount( DEFAULT_CHANNELS )
{
#ifndef SYNC_WITH_SHM_FIFO
struct sockaddr_un sa;
sa.sun_family = AF_LOCAL;
m_socketFile = QDir::tempPath() + QDir::separator() +
QUuid::createUuid().toString();
const char * path = m_socketFile.toUtf8().constData();
size_t length = strlen( path );
if ( length >= sizeof sa.sun_path )
{
length = sizeof sa.sun_path - 1;
qWarning( "Socket path too long." );
}
memcpy( sa.sun_path, path, length );
sa.sun_path[length] = '\0';
m_server = socket( PF_LOCAL, SOCK_STREAM, 0 );
if ( m_server == -1 )
{
qWarning( "Unable to start the server." );
}
remove( path );
int ret = bind( m_server, (struct sockaddr *) &sa, sizeof sa );
if ( ret == -1 || listen( m_server, 1 ) == -1 )
{
qWarning( "Unable to start the server." );
}
#endif
}
@@ -117,6 +156,14 @@ RemotePlugin::~RemotePlugin()
shmctl( m_shmID, IPC_RMID, NULL );
#endif
}
#ifndef SYNC_WITH_SHM_FIFO
if ( close( m_server ) == -1)
{
qWarning( "Error freeing resources." );
}
remove( m_socketFile.toUtf8().constData() );
#endif
}
@@ -128,15 +175,36 @@ bool RemotePlugin::init( const QString &pluginExecutable,
lock();
if( m_failed )
{
#ifdef SYNC_WITH_SHM_FIFO
reset( new shmFifo(), new shmFifo() );
#endif
m_failed = false;
}
QString exec = QFileInfo(QDir("plugins:"), pluginExecutable).absoluteFilePath();
#ifdef LMMS_BUILD_WIN32
if( ! exec.endsWith( ".exe", Qt::CaseInsensitive ) )
{
exec += ".exe";
}
#endif
if( ! QFile( exec ).exists() )
{
qWarning( "Remote plugin '%s' not found.",
exec.toUtf8().constData() );
m_failed = true;
unlock();
return failed();
}
QStringList args;
#ifdef SYNC_WITH_SHM_FIFO
// swap in and out for bidirectional communication
args << QString::number( out()->shmKey() );
args << QString::number( in()->shmKey() );
#else
args << m_socketFile;
#endif
#ifndef DEBUG_REMOTE_PLUGIN
m_process.setProcessChannelMode( QProcess::ForwardedChannels );
m_process.setWorkingDirectory( QCoreApplication::applicationDirPath() );
@@ -146,6 +214,33 @@ bool RemotePlugin::init( const QString &pluginExecutable,
qDebug() << exec << args;
#endif
connect( &m_process, SIGNAL( finished( int, QProcess::ExitStatus ) ),
this, SLOT( processFinished( int, QProcess::ExitStatus ) ) );
#ifndef SYNC_WITH_SHM_FIFO
struct pollfd pollin;
pollin.fd = m_server;
pollin.events = POLLIN;
switch ( poll( &pollin, 1, 30000 ) )
{
case -1:
qWarning( "Unexpected poll error." );
break;
case 0:
qWarning( "Remote plugin did not connect." );
break;
default:
m_socket = accept( m_server, NULL, NULL );
if ( m_socket == -1 )
{
qWarning( "Unexpected socket error." );
}
}
#endif
resizeSharedProcessingMemory();
if( waitForInitDoneMsg )
@@ -337,6 +432,17 @@ void RemotePlugin::resizeSharedProcessingMemory()
void RemotePlugin::processFinished( int exitCode,
QProcess::ExitStatus exitStatus )
{
#ifndef SYNC_WITH_SHM_FIFO
invalidate();
#endif
}
bool RemotePlugin::processMessage( const message & _m )
{
lock();
@@ -345,6 +451,7 @@ bool RemotePlugin::processMessage( const message & _m )
switch( _m.id )
{
case IdUndefined:
unlock();
return false;
case IdInitDone:

View File

@@ -59,6 +59,8 @@
#include <unistd.h>
#endif
#include <signal.h>
#include "MemoryManager.h"
#include "ConfigManager.h"
#include "NotePlayHandle.h"
@@ -611,6 +613,20 @@ int main( int argc, char * * argv )
}
#endif
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sa.sa_flags = SA_SIGINFO;
if ( sigemptyset( &sa.sa_mask ) )
{
fprintf( stderr, "Signal initialization failed.\n" );
}
if ( sigaction( SIGPIPE, &sa, NULL ) )
{
fprintf( stderr, "Signal initialization failed.\n" );
}
#endif
// if we have an output file for rendering, just render the song
// without starting the GUI
if( !renderOut.isEmpty() )