improve terminate fit in musredit qt5/qt6.
Build and Deploy Documentation / build-and-deploy (push) Successful in 22s
Build and Deploy Documentation / build-and-deploy (push) Successful in 22s
This commit is contained in:
@@ -173,25 +173,49 @@ void PFitOutputHandler::processDone(int exitCode, QProcess::ExitStatus exitStatu
|
||||
qDebug() << "**ERROR** PFitOutputHandler::processDone: exitCode = " << exitCode << Qt::endl;
|
||||
#endif
|
||||
}
|
||||
fQuitButton->setText("Done");
|
||||
|
||||
if (fQuitRequested) {
|
||||
// the process has now actually terminated in response to quitButtonPressed(); close the dialog
|
||||
accept();
|
||||
} else {
|
||||
fQuitButton->setText("Done");
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* <p>If the quit button is pressed while the fit is still running, try to terminate musrfit, if this
|
||||
* does not work, try to kill musrfit.
|
||||
* <p>If the quit button is pressed while the fit is still running, request musrfit to terminate
|
||||
* (SIGTERM) and disable the button; a single-shot timer escalates to kill() (SIGKILL) if musrfit
|
||||
* has not reacted within a few seconds. The dialog is NOT closed here: processDone() (connected to
|
||||
* QProcess::finished()) calls accept() once the process has actually terminated.
|
||||
*
|
||||
* <p>This deliberately never blocks on QProcess::waitForFinished(). A blocking wait here would
|
||||
* freeze the whole (modal) dialog for up to its default 30 s timeout with no user feedback, which
|
||||
* in practice led users to force-quit musredit itself while musrfit was still being terminated -
|
||||
* orphaning the musrfit process, since ~PFitOutputHandler() (the actual terminate/kill/kill-9
|
||||
* safety net) never got the chance to run.
|
||||
*/
|
||||
void PFitOutputHandler::quitButtonPressed()
|
||||
{
|
||||
// if the fitting is still taking place, kill it
|
||||
if (fProc->state() == QProcess::Running) {
|
||||
fProc->terminate();
|
||||
if (!fProc->waitForFinished()) {
|
||||
fProc->kill();
|
||||
}
|
||||
if (fProc->state() == QProcess::NotRunning) {
|
||||
accept();
|
||||
return;
|
||||
}
|
||||
|
||||
accept();
|
||||
if (fQuitRequested) // termination already in progress, ignore repeated clicks
|
||||
return;
|
||||
fQuitRequested = true;
|
||||
|
||||
fQuitButton->setEnabled(false);
|
||||
fQuitButton->setText(tr("Terminating..."));
|
||||
fProc->terminate();
|
||||
|
||||
// escalate to SIGKILL if musrfit does not react to SIGTERM in time
|
||||
// (e.g. blocked in slow disk/NFS I/O); accept() happens via processDone()
|
||||
QTimer::singleShot(5000, this, [this]() {
|
||||
if (fProc->state() != QProcess::NotRunning)
|
||||
fProc->kill();
|
||||
});
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -65,6 +65,7 @@ class PFitOutputHandler : public QDialog
|
||||
private:
|
||||
Q_PID fProcPID; ///< keeps the process PID
|
||||
std::unique_ptr<QProcess> fProc; ///< pointer to the musrfit process
|
||||
bool fQuitRequested = false; ///< set once the user pressed Quit while the process was still running
|
||||
|
||||
std::unique_ptr<QVBoxLayout> fVbox; ///< pointer to the dialog layout manager
|
||||
std::unique_ptr<QPlainTextEdit> fOutput; ///< the captured musrfit output is written (read only) into this text edit object.
|
||||
|
||||
@@ -217,7 +217,13 @@ void PFitOutputHandler::processDone(int exitCode, QProcess::ExitStatus exitStatu
|
||||
if ((exitStatus == QProcess::CrashExit) && (exitCode != 0)) {
|
||||
qDebug() << "**ERROR** PFitOutputHandler::processDone: exitCode = " << exitCode << Qt::endl;
|
||||
}
|
||||
fQuitButton->setText("Done");
|
||||
|
||||
if (fQuitRequested) {
|
||||
// the process has now actually terminated in response to quitButtonPressed(); close the dialog
|
||||
accept();
|
||||
} else {
|
||||
fQuitButton->setText("Done");
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
@@ -226,25 +232,41 @@ void PFitOutputHandler::processDone(int exitCode, QProcess::ExitStatus exitStatu
|
||||
*
|
||||
* @details Handles user request to close the dialog. The behavior depends on
|
||||
* whether the fit is still running:
|
||||
* - If running: Attempts to terminate musrfit gracefully using QProcess::terminate().
|
||||
* If graceful termination fails within the timeout period, forcefully kills
|
||||
* the process using QProcess::kill().
|
||||
* - If finished: Simply closes the dialog.
|
||||
* - If running: Requests graceful termination via QProcess::terminate() (SIGTERM)
|
||||
* and disables the button. A single-shot timer escalates to QProcess::kill()
|
||||
* (SIGKILL) if musrfit has not reacted within a few seconds. The dialog is
|
||||
* NOT closed here; processDone() (connected to QProcess::finished()) calls
|
||||
* accept() once the process has actually terminated.
|
||||
* - If already finished: Simply closes the dialog.
|
||||
*
|
||||
* After ensuring the process is stopped (or was already stopped), accepts the
|
||||
* dialog (closes it with QDialog::Accepted result).
|
||||
* @note This slot deliberately never blocks on QProcess::waitForFinished().
|
||||
* A blocking wait here would freeze the whole (modal) dialog for up to its
|
||||
* default 30 s timeout with no user feedback, which in practice led users to
|
||||
* force-quit musredit itself while musrfit was still being terminated -
|
||||
* orphaning the musrfit process, since ~PFitOutputHandler() (the actual
|
||||
* terminate/kill/kill-9 safety net) never got the chance to run.
|
||||
*/
|
||||
void PFitOutputHandler::quitButtonPressed()
|
||||
{
|
||||
// if the fitting is still taking place, kill it
|
||||
if (fProc->state() == QProcess::Running) {
|
||||
fProc->terminate();
|
||||
if (!fProc->waitForFinished()) {
|
||||
fProc->kill();
|
||||
}
|
||||
if (fProc->state() == QProcess::NotRunning) {
|
||||
accept();
|
||||
return;
|
||||
}
|
||||
|
||||
accept();
|
||||
if (fQuitRequested) // termination already in progress, ignore repeated clicks
|
||||
return;
|
||||
fQuitRequested = true;
|
||||
|
||||
fQuitButton->setEnabled(false);
|
||||
fQuitButton->setText(tr("Terminating..."));
|
||||
fProc->terminate();
|
||||
|
||||
// escalate to SIGKILL if musrfit does not react to SIGTERM in time
|
||||
// (e.g. blocked in slow disk/NFS I/O); accept() happens via processDone()
|
||||
QTimer::singleShot(5000, this, [this]() {
|
||||
if (fProc->state() != QProcess::NotRunning)
|
||||
fProc->kill();
|
||||
});
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -132,6 +132,7 @@ class PFitOutputHandler : public QDialog
|
||||
*/
|
||||
qint64 fProcPID; ///< Process ID of the running musrfit process.
|
||||
std::unique_ptr<QProcess> fProc; ///< QProcess object managing the musrfit execution.
|
||||
bool fQuitRequested = false; ///< Set once the user pressed Quit while the process was still running.
|
||||
/** @} */
|
||||
|
||||
/** @name UI Components
|
||||
|
||||
Reference in New Issue
Block a user