mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-27 06:38:44 -05:00
Disallow multiple instances without a unique rig name
Because of confilicts using the shared memory to communicate with jt9 only one instance of WSJT-X may run with each unique key (rig name). Added a QLockFile for each unique key in the temp directory and logic to deal with stale locks and retries. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@4465 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
4980d0cdc9
commit
4075f5dbb7
@ -235,7 +235,7 @@ class Configuration::impl final
|
|||||||
public:
|
public:
|
||||||
using FrequencyDelta = Radio::FrequencyDelta;
|
using FrequencyDelta = Radio::FrequencyDelta;
|
||||||
|
|
||||||
explicit impl (Configuration * self, QString const& instance_key, QSettings * settings, bool test_mode, QWidget * parent);
|
explicit impl (Configuration * self, QSettings * settings, QWidget * parent);
|
||||||
~impl ();
|
~impl ();
|
||||||
|
|
||||||
bool have_rig (bool open_if_closed = true);
|
bool have_rig (bool open_if_closed = true);
|
||||||
@ -428,8 +428,8 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
// delegate to implementation class
|
// delegate to implementation class
|
||||||
Configuration::Configuration (QString const& instance_key, QSettings * settings, bool test_mode, QWidget * parent)
|
Configuration::Configuration (QSettings * settings, QWidget * parent)
|
||||||
: m_ {this, instance_key, settings, test_mode, parent}
|
: m_ {this, settings, parent}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,7 +549,7 @@ void Configuration::sync_transceiver (bool force_signal, bool enforce_mode_and_s
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Configuration::impl::impl (Configuration * self, QString const& instance_key, QSettings * settings, bool test_mode, QWidget * parent)
|
Configuration::impl::impl (Configuration * self, QSettings * settings, QWidget * parent)
|
||||||
: QDialog {parent}
|
: QDialog {parent}
|
||||||
, self_ {self}
|
, self_ {self}
|
||||||
, ui_ {new Ui::configuration_dialog}
|
, ui_ {new Ui::configuration_dialog}
|
||||||
@ -593,8 +593,6 @@ Configuration::impl::impl (Configuration * self, QString const& instance_key, QS
|
|||||||
, default_audio_input_device_selected_ {false}
|
, default_audio_input_device_selected_ {false}
|
||||||
, default_audio_output_device_selected_ {false}
|
, default_audio_output_device_selected_ {false}
|
||||||
{
|
{
|
||||||
(void)instance_key; // quell compiler warning
|
|
||||||
|
|
||||||
ui_->setupUi (this);
|
ui_->setupUi (this);
|
||||||
|
|
||||||
|
|
||||||
@ -637,11 +635,7 @@ Configuration::impl::impl (Configuration * self, QString const& instance_key, QS
|
|||||||
temp_path_.setPath (temp_location);
|
temp_path_.setPath (temp_location);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString unique_directory {instance_key};
|
QString unique_directory {QApplication::applicationName ()};
|
||||||
if (test_mode)
|
|
||||||
{
|
|
||||||
unique_directory += " - test_mode";
|
|
||||||
}
|
|
||||||
if (!temp_path_.mkpath (unique_directory) || !temp_path_.cd (unique_directory))
|
if (!temp_path_.mkpath (unique_directory) || !temp_path_.cd (unique_directory))
|
||||||
{
|
{
|
||||||
QMessageBox::critical (this, "WSJT-X", tr ("Create temporary directory error: ") + temp_path_.absolutePath ());
|
QMessageBox::critical (this, "WSJT-X", tr ("Create temporary directory error: ") + temp_path_.absolutePath ());
|
||||||
|
@ -61,7 +61,7 @@ public:
|
|||||||
|
|
||||||
enum DataMode {data_mode_none, data_mode_USB, data_mode_data};
|
enum DataMode {data_mode_none, data_mode_USB, data_mode_data};
|
||||||
|
|
||||||
explicit Configuration (QString const& instance_key, QSettings * settings, bool test_mode, QWidget * parent = nullptr);
|
explicit Configuration (QSettings * settings, QWidget * parent = nullptr);
|
||||||
~Configuration ();
|
~Configuration ();
|
||||||
|
|
||||||
int exec ();
|
int exec ();
|
||||||
|
46
main.cpp
46
main.cpp
@ -20,6 +20,7 @@
|
|||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QLockFile>
|
||||||
|
|
||||||
#if QT_VERSION >= 0x050200
|
#if QT_VERSION >= 0x050200
|
||||||
#include <QCommandLineParser>
|
#include <QCommandLineParser>
|
||||||
@ -32,12 +33,12 @@
|
|||||||
#include "TraceFile.hpp"
|
#include "TraceFile.hpp"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
|
||||||
// Multiple instances:
|
|
||||||
QSharedMemory mem_jt9;
|
|
||||||
QString my_key;
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
// Multiple instances:
|
||||||
|
QSharedMemory mem_jt9;
|
||||||
|
|
||||||
QApplication a(argc, argv);
|
QApplication a(argc, argv);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -111,9 +112,42 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
a.setApplicationName (a.applicationName () + " - " + temp_name);
|
a.setApplicationName (a.applicationName () + " - " + temp_name);
|
||||||
|
|
||||||
|
if (parser.isSet (test_option))
|
||||||
|
{
|
||||||
|
a.setApplicationName (a.applicationName () + " - test");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
multiple = true;
|
multiple = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// disallow multiple instances with same instance key
|
||||||
|
QLockFile instance_lock {QDir {QStandardPaths::writableLocation (QStandardPaths::TempLocation)}.absoluteFilePath (a.applicationName () + ".lock")};
|
||||||
|
instance_lock.setStaleLockTime (0);
|
||||||
|
auto ok = false;
|
||||||
|
while (!(ok = instance_lock.tryLock ()))
|
||||||
|
{
|
||||||
|
if (QLockFile::LockFailedError == instance_lock.error ())
|
||||||
|
{
|
||||||
|
auto button = QMessageBox::question (nullptr
|
||||||
|
, QApplication::applicationName ()
|
||||||
|
, QObject::tr ("Another instance may be running, try to remove stale lock file?")
|
||||||
|
, QMessageBox::Yes | QMessageBox::Retry | QMessageBox::No
|
||||||
|
, QMessageBox::Yes);
|
||||||
|
switch (button)
|
||||||
|
{
|
||||||
|
case QMessageBox::Yes:
|
||||||
|
instance_lock.removeStaleLockFile ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QMessageBox::Retry:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw std::runtime_error {"Multiple instances must have unique rig names"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -124,7 +158,6 @@ int main(int argc, char *argv[])
|
|||||||
throw std::runtime_error {"Cannot find a usable configuration path \"" + config_path.path ().toStdString () + '"'};
|
throw std::runtime_error {"Cannot find a usable configuration path \"" + config_path.path ().toStdString () + '"'};
|
||||||
}
|
}
|
||||||
QSettings settings(config_path.absoluteFilePath (a.applicationName () + ".ini"), QSettings::IniFormat);
|
QSettings settings(config_path.absoluteFilePath (a.applicationName () + ".ini"), QSettings::IniFormat);
|
||||||
|
|
||||||
#if WSJT_QDEBUG_TO_FILE
|
#if WSJT_QDEBUG_TO_FILE
|
||||||
// // open a trace file
|
// // open a trace file
|
||||||
TraceFile trace_file {QDir {QApplication::applicationDirPath ()}.absoluteFilePath ("wsjtx_trace.log")};
|
TraceFile trace_file {QDir {QApplication::applicationDirPath ()}.absoluteFilePath ("wsjtx_trace.log")};
|
||||||
@ -135,8 +168,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
// Create and initialize shared memory segment
|
// Create and initialize shared memory segment
|
||||||
// Multiple instances: use rig_name as shared memory key
|
// Multiple instances: use rig_name as shared memory key
|
||||||
my_key = a.applicationName ();
|
mem_jt9.setKey(a.applicationName ());
|
||||||
mem_jt9.setKey(my_key);
|
|
||||||
|
|
||||||
if(!mem_jt9.attach()) {
|
if(!mem_jt9.attach()) {
|
||||||
if (!mem_jt9.create(sizeof(jt9com_))) {
|
if (!mem_jt9.create(sizeof(jt9com_))) {
|
||||||
@ -167,7 +199,7 @@ int main(int argc, char *argv[])
|
|||||||
).toBool () ? 1u : 4u;
|
).toBool () ? 1u : 4u;
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow w(multiple, &settings, &mem_jt9, my_key, downSampleFactor, parser.isSet (test_option));
|
MainWindow w(multiple, &settings, &mem_jt9, downSampleFactor);
|
||||||
w.show();
|
w.show();
|
||||||
|
|
||||||
QObject::connect (&a, SIGNAL (lastWindowClosed()), &a, SLOT (quit()));
|
QObject::connect (&a, SIGNAL (lastWindowClosed()), &a, SLOT (quit()));
|
||||||
|
@ -68,14 +68,14 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
//--------------------------------------------------- MainWindow constructor
|
//--------------------------------------------------- MainWindow constructor
|
||||||
MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdmem, QString const& thekey,
|
MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdmem,
|
||||||
unsigned downSampleFactor, bool test_mode, QWidget *parent) :
|
unsigned downSampleFactor, QWidget *parent) :
|
||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
m_revision {revision ("$Rev$")},
|
m_revision {revision ("$Rev$")},
|
||||||
m_multiple {multiple},
|
m_multiple {multiple},
|
||||||
m_settings (settings),
|
m_settings (settings),
|
||||||
ui(new Ui::MainWindow),
|
ui(new Ui::MainWindow),
|
||||||
m_config (thekey, settings, test_mode, this),
|
m_config (settings, this),
|
||||||
m_wideGraph (new WideGraph (settings)),
|
m_wideGraph (new WideGraph (settings)),
|
||||||
m_logDlg (new LogQSO (program_title (), settings, &m_config, this)),
|
m_logDlg (new LogQSO (program_title (), settings, &m_config, this)),
|
||||||
m_dialFreq {0},
|
m_dialFreq {0},
|
||||||
@ -85,7 +85,6 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme
|
|||||||
m_diskData {false},
|
m_diskData {false},
|
||||||
m_appDir {QApplication::applicationDirPath ()},
|
m_appDir {QApplication::applicationDirPath ()},
|
||||||
mem_jt9 {shdmem},
|
mem_jt9 {shdmem},
|
||||||
mykey_jt9 {thekey},
|
|
||||||
psk_Reporter (new PSK_Reporter (this)),
|
psk_Reporter (new PSK_Reporter (this)),
|
||||||
m_msAudioOutputBuffered (0u),
|
m_msAudioOutputBuffered (0u),
|
||||||
m_framesAudioInputBuffered (RX_SAMPLE_RATE / 10),
|
m_framesAudioInputBuffered (RX_SAMPLE_RATE / 10),
|
||||||
@ -369,7 +368,7 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme
|
|||||||
lockFile.open(QIODevice::ReadWrite);
|
lockFile.open(QIODevice::ReadWrite);
|
||||||
|
|
||||||
QStringList jt9_args {
|
QStringList jt9_args {
|
||||||
"-s", mykey_jt9
|
"-s", QApplication::applicationName ()
|
||||||
, "-e", QDir::toNativeSeparators (m_appDir)
|
, "-e", QDir::toNativeSeparators (m_appDir)
|
||||||
, "-a", QDir::toNativeSeparators (m_config.data_path ().absolutePath ())
|
, "-a", QDir::toNativeSeparators (m_config.data_path ().absolutePath ())
|
||||||
};
|
};
|
||||||
|
@ -57,8 +57,8 @@ public:
|
|||||||
using Frequency = Radio::Frequency;
|
using Frequency = Radio::Frequency;
|
||||||
|
|
||||||
// Multiple instances: call MainWindow() with *thekey
|
// Multiple instances: call MainWindow() with *thekey
|
||||||
explicit MainWindow(bool multiple, QSettings *, QSharedMemory *shdmem, QString const& thekey,
|
explicit MainWindow(bool multiple, QSettings *, QSharedMemory *shdmem,
|
||||||
unsigned downSampleFactor, bool test_mode, QWidget *parent = 0);
|
unsigned downSampleFactor, QWidget *parent = 0);
|
||||||
~MainWindow();
|
~MainWindow();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
@ -349,8 +349,6 @@ private:
|
|||||||
QRect m_astroGeom;
|
QRect m_astroGeom;
|
||||||
|
|
||||||
QSharedMemory *mem_jt9;
|
QSharedMemory *mem_jt9;
|
||||||
// Multiple instances:
|
|
||||||
QString mykey_jt9;
|
|
||||||
PSK_Reporter *psk_Reporter;
|
PSK_Reporter *psk_Reporter;
|
||||||
SignalMeter *signalMeter;
|
SignalMeter *signalMeter;
|
||||||
LogBook m_logBook;
|
LogBook m_logBook;
|
||||||
|
Loading…
Reference in New Issue
Block a user