Updated decoder subprocess error handling to restart instead of crash the app

This commit is contained in:
Jordan Sherer 2019-11-22 15:00:06 -05:00
parent cb7f84d952
commit 2159ea0cfb
4 changed files with 91 additions and 52 deletions

View File

@ -91,15 +91,15 @@ void Decoder::processQuit(){
}
//
void Decoder::processError(int errorCode){
if(JS8_DEBUG_DECODE) qDebug() << "decoder process error" << errorCode;
emit error(errorCode);
void Decoder::processError(int errorCode, QString errorString){
if(JS8_DEBUG_DECODE) qDebug() << "decoder process error" << errorCode << errorString;
emit error(errorCode, errorString);
}
//
void Decoder::processFinished(int exitCode, int statusCode){
if(JS8_DEBUG_DECODE) qDebug() << "decoder process finished" << exitCode << statusCode;
emit finished(exitCode, statusCode);
void Decoder::processFinished(int exitCode, int statusCode, QString errorString){
if(JS8_DEBUG_DECODE) qDebug() << "decoder process finished" << exitCode << statusCode << errorString;
emit finished(exitCode, statusCode, errorString);
}
////////////////////////////////////////
@ -138,12 +138,12 @@ void Worker::start(QString path, QStringList args){
connect(proc, static_cast<void (QProcess::*) (QProcess::ProcessError)> (&QProcess::error),
[this, proc] (QProcess::ProcessError errorCode) {
emit error(int(errorCode));
emit error(int(errorCode), proc->errorString());
});
connect(proc, static_cast<void (QProcess::*) (int, QProcess::ExitStatus)> (&QProcess::finished),
[this, proc] (int exitCode, QProcess::ExitStatus status) {
emit finished(exitCode, int(status));
emit finished(exitCode, int(status), QString{proc->readAllStandardError()});
});
QProcessEnvironment env {QProcessEnvironment::systemEnvironment ()};

View File

@ -21,13 +21,14 @@ public slots:
void start(QString path, QStringList args);
void quit();
QProcess* process() const { return m_proc.data(); }
private:
void setProcess(QProcess *proc, int msecs=1000);
signals:
void ready(QByteArray t);
void error(int errorCode);
void finished(int exitCode, int statusCode);
void error(int errorCode, QString errorString);
void finished(int exitCode, int statusCode, QString errorString);
private:
QScopedPointer<QProcess> m_proc;
@ -44,6 +45,20 @@ public:
void lock();
void unlock();
QString program() const {
if(!m_worker.isNull() && m_worker->process() != nullptr){
return m_worker->process()->program();
}
return {};
}
QStringList arguments() const {
if(!m_worker.isNull() && m_worker->process() != nullptr){
return m_worker->process()->arguments();
}
return {};
}
private:
Worker* createWorker();
@ -56,16 +71,16 @@ public slots:
void processReady(QByteArray t);
void processQuit();
void processError(int errorCode);
void processFinished(int exitCode, int statusCode);
void processError(int errorCode, QString errorString);
void processFinished(int exitCode, int statusCode, QString errorString);
signals:
void startWorker(QString path, QStringList args);
void quitWorker();
void ready(QByteArray t);
void error(int errorCode);
void finished(int exitCode, int statusCode);
void error(int errorCode, QString errorString);
void finished(int exitCode, int statusCode, QString errorString);
private:
QPointer<Worker> m_worker;

View File

@ -542,6 +542,13 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
//connect (&m_decodeThread, &QThread::finished, m_notification, &QObject::deleteLater);
//connect(this, &MainWindow::decodedLineReady, this, &MainWindow::processDecodedLine);
connect(&m_decoder, &Decoder::ready, this, &MainWindow::processDecodedLine);
connect(&m_decoder, &Decoder::error, this, [this](int errorCode, QString errorString){
subProcessError(m_decoder.program(), m_decoder.arguments(), errorCode, errorString);
});
connect(&m_decoder, &Decoder::finished, this, [this](int exitCode, int statusCode, QString errorString){
subProcessFailed(m_decoder.program(), m_decoder.arguments(), exitCode, statusCode, errorString);
});
on_EraseButton_clicked ();
@ -1617,6 +1624,10 @@ void MainWindow::initDecoderSubprocess(){
if(m_decoderBusy){
decodeBusy(false);
}
if(!m_valid){
m_valid = true;
}
}
QPair<QPair<int, int>, int> splitVersion(QString v){
@ -3484,46 +3495,59 @@ void MainWindow::setup_status_bar (bool vhf)
}
}
void MainWindow::subProcessFailed (QProcess * process, int exit_code, QProcess::ExitStatus status)
{
if (m_valid && (exit_code || QProcess::NormalExit != status))
{
QStringList arguments;
for (auto argument: process->arguments ())
{
if (argument.contains (' ')) argument = '"' + argument + '"';
arguments << argument;
}
if (m_splash && m_splash->isVisible ()) m_splash->hide ();
MessageBox::critical_message (this, tr ("Subprocess Error")
, tr ("Subprocess failed with exit code %1")
.arg (exit_code)
, tr ("Running: %1\n%2")
.arg (process->program () + ' ' + arguments.join (' '))
.arg (QString {process->readAllStandardError()}));
QTimer::singleShot (0, this, SLOT (close ()));
m_valid = false; // ensures exit if still constructing
void MainWindow::subProcessFailed (QString program, QStringList args, int exitCode, int status, QString errorString){
if(!m_valid){
return;
}
if(!exitCode || QProcess::NormalExit == QProcess::ExitStatus(status)){
return;
}
// surpress any other process notifications until restart
m_valid = false;
QStringList arguments;
for (auto argument: args){
if (argument.contains (' ')) argument = '"' + argument + '"';
arguments << argument;
}
if (m_splash && m_splash->isVisible ()) m_splash->hide ();
MessageBox::critical_message (this, tr ("Subprocess Error")
, tr ("Subprocess failed with exit code %1 and will restart.")
.arg (exitCode)
, tr ("Running: %1\n%2")
.arg (program + ' ' + arguments.join (' '))
.arg (errorString));
initDecoderSubprocess();
}
void MainWindow::subProcessError (QProcess * process, QProcess::ProcessError)
{
if (m_valid)
{
QStringList arguments;
for (auto argument: process->arguments ())
{
if (argument.contains (' ')) argument = '"' + argument + '"';
arguments << argument;
}
if (m_splash && m_splash->isVisible ()) m_splash->hide ();
MessageBox::critical_message (this, tr ("Subprocess error")
, tr ("Running: %1\n%2")
.arg (process->program () + ' ' + arguments.join (' '))
.arg (process->errorString ()));
QTimer::singleShot (0, this, SLOT (close ()));
m_valid = false; // ensures exit if still constructing
void MainWindow::subProcessError (QString program, QStringList args, int errorCode, QString errorString){
if(!m_valid){
return;
}
// surpress any other process notifications until process restart
m_valid = false;
QStringList arguments;
for(auto argument: args){
if (argument.contains (' ')) argument = '"' + argument + '"';
arguments << argument;
}
if (m_splash && m_splash->isVisible ()) m_splash->hide ();
MessageBox::critical_message (this, tr ("Subprocess error")
, tr ("Subprocess errored with code %1 and will restart.").arg(errorCode)
, tr ("Running: %1\n%2")
.arg (program + ' ' + arguments.join (' '))
.arg (errorString));
initDecoderSubprocess();
}
void MainWindow::closeEvent(QCloseEvent * e)

View File

@ -1029,8 +1029,8 @@ private:
void resetAutomaticIntervalTransmissions(bool stopCQ, bool stopHB);
void resetCQTimer(bool stop);
void resetHeartbeatTimer(bool stop);
void subProcessFailed (QProcess *, int exit_code, QProcess::ExitStatus);
void subProcessError (QProcess *, QProcess::ProcessError);
void subProcessFailed (QString program, QStringList args, int exitCode, int status, QString errorString);
void subProcessError (QString program, QStringList arguments, int errorCode, QString errorString);
void statusUpdate () const;
void update_watchdog_label ();
void on_the_minute ();