diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index f056999455f97c838b27fc3ac1900d0fb6e4b980..85adc4fabdfd2b3317e7478c26ec8f8f2a39a355 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -529,6 +529,7 @@ HEADERS += \ src/Joystick/JoystickSDL.h \ src/QGCFileDialog.h \ src/QGCMessageBox.h \ + src/RunGuard.h \ src/ViewWidgets/CustomCommandWidget.h \ src/ViewWidgets/CustomCommandWidgetController.h \ src/ViewWidgets/ViewWidgetController.h \ @@ -677,6 +678,7 @@ SOURCES += \ src/GPS/RTCM/RTCMMavlink.cc \ src/Joystick/JoystickSDL.cc \ src/QGCFileDialog.cc \ + src/RunGuard.cc \ src/ViewWidgets/CustomCommandWidget.cc \ src/ViewWidgets/CustomCommandWidgetController.cc \ src/ViewWidgets/ViewWidgetController.cc \ diff --git a/src/RunGuard.cc b/src/RunGuard.cc new file mode 100644 index 0000000000000000000000000000000000000000..5e8a4925337b5b58aee1890b12ce975ecb7dec70 --- /dev/null +++ b/src/RunGuard.cc @@ -0,0 +1,87 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#include "RunGuard.h" + +#include + +namespace +{ + +QString generateKeyHash( const QString& key, const QString& salt ) +{ + QByteArray data; + + data.append( key.toUtf8() ); + data.append( salt.toUtf8() ); + data = QCryptographicHash::hash( data, QCryptographicHash::Sha1 ).toHex(); + + return data; +} + +} + +RunGuard::RunGuard( const QString& key ) + : key( key ) + , memLockKey( generateKeyHash( key, "_memLockKey" ) ) + , sharedmemKey( generateKeyHash( key, "_sharedmemKey" ) ) + , sharedMem( sharedmemKey ) + , memLock( memLockKey, 1 ) +{ + memLock.acquire(); + { + QSharedMemory fix( sharedmemKey ); // Fix for *nix: http://habrahabr.ru/post/173281/ + fix.attach(); + } + memLock.release(); +} + +RunGuard::~RunGuard() +{ + release(); +} + +bool RunGuard::isAnotherRunning() +{ + if ( sharedMem.isAttached() ) + return false; + + memLock.acquire(); + const bool isRunning = sharedMem.attach(); + if ( isRunning ) + sharedMem.detach(); + memLock.release(); + + return isRunning; +} + +bool RunGuard::tryToRun() +{ + if ( isAnotherRunning() ) // Extra check + return false; + + memLock.acquire(); + const bool result = sharedMem.create( sizeof( quint64 ) ); + memLock.release(); + if ( !result ) + { + release(); + return false; + } + + return true; +} + +void RunGuard::release() +{ + memLock.acquire(); + if ( sharedMem.isAttached() ) + sharedMem.detach(); + memLock.release(); +} diff --git a/src/RunGuard.h b/src/RunGuard.h new file mode 100644 index 0000000000000000000000000000000000000000..0e82f5b6231e8d51816aa43e016c5e3ab36bbdeb --- /dev/null +++ b/src/RunGuard.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#ifndef RunGuard_H +#define RunGuard_H + +#include +#include +#include + +class RunGuard +{ +public: + RunGuard( const QString& key ); + ~RunGuard(); + + bool isAnotherRunning(); + bool tryToRun(); + void release(); + +private: + const QString key; + const QString memLockKey; + const QString sharedmemKey; + + QSharedMemory sharedMem; + QSystemSemaphore memLock; + + Q_DISABLE_COPY( RunGuard ) +}; + +#endif diff --git a/src/main.cc b/src/main.cc index 80000cd33c10dcb4ef135d18830296df448681b2..4dec260fa0bc31e3c518ee9d8851624672144c67 100644 --- a/src/main.cc +++ b/src/main.cc @@ -27,10 +27,9 @@ #include "QGCApplication.h" #include "AppMessages.h" -#define SINGLE_INSTANCE_PORT 14499 - #ifndef __mobile__ #include "QGCSerialPortInfo.h" + #include "RunGuard.h" #endif #ifdef UNITTEST_BUILD @@ -103,6 +102,13 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) int main(int argc, char *argv[]) { +#ifndef __mobile__ + RunGuard guard("QGroundControlRunGuardKey"); + if (!guard.tryToRun()) { + return 0; + } +#endif + #ifdef Q_OS_UNIX //Force writing to the console on UNIX/BSD devices if (!qEnvironmentVariableIsSet("QT_LOGGING_TO_CONSOLE")) @@ -112,16 +118,6 @@ int main(int argc, char *argv[]) // install the message handler AppMessages::installHandler(); -#ifndef __mobile__ - //-- Test for another instance already running. If that's the case, we simply exit. - QHostAddress host("127.0.0.1"); - QUdpSocket socket; - if(!socket.bind(host, SINGLE_INSTANCE_PORT, QAbstractSocket::DontShareAddress)) { - qWarning() << "Another instance already running. Exiting."; - exit(-1); - } -#endif - #ifdef Q_OS_MAC #ifndef __ios__ // Prevent Apple's app nap from screwing us over