mirror of
https://github.com/mumble-voip/mumble.git
synced 2025-10-26 11:19:16 +00:00
Add restart limiter to OverlayPrivateWin to avoid bombing the system with process spawns.
We need this in case there's a bug in one of the overlay helpers. Without this, we would restart a crashed helper immediately. If this bug is triggered every time the helper is run, we'd get into an infinite restart loop, potentially making the host computer unresponsive.
This commit is contained in:
parent
8e31de788f
commit
bb0ccc4629
@ -88,6 +88,10 @@ OverlayPrivateWin::OverlayPrivateWin(QObject *p) : OverlayPrivate(p) {
|
||||
connect(m_helper_process, SIGNAL(finished(int, QProcess::ExitStatus)),
|
||||
this, SLOT(onHelperProcessExited(int, QProcess::ExitStatus)));
|
||||
|
||||
m_helper_restart_timer = new QTimer(this);
|
||||
m_helper_restart_timer->setSingleShot(true);
|
||||
connect(m_helper_restart_timer, SIGNAL(timeout()), this, SLOT(onDelayedRestartTimerTriggered()));
|
||||
|
||||
m_helper64_exe_path = QString::fromLatin1("%1/mumble_ol_x64.exe").arg(qApp->applicationDirPath());
|
||||
m_helper64_exe_args = m_helper_exe_args;
|
||||
m_helper64_process = new QProcess(this);
|
||||
@ -100,6 +104,10 @@ OverlayPrivateWin::OverlayPrivateWin(QObject *p) : OverlayPrivate(p) {
|
||||
|
||||
connect(m_helper64_process, SIGNAL(finished(int, QProcess::ExitStatus)),
|
||||
this, SLOT(onHelperProcessExited(int, QProcess::ExitStatus)));
|
||||
|
||||
m_helper64_restart_timer = new QTimer(this);
|
||||
m_helper64_restart_timer->setSingleShot(true);
|
||||
connect(m_helper64_restart_timer, SIGNAL(timeout()), this, SLOT(onDelayedRestartTimerTriggered()));
|
||||
}
|
||||
|
||||
OverlayPrivateWin::~OverlayPrivateWin() {
|
||||
@ -110,8 +118,10 @@ void OverlayPrivateWin::startHelper(QProcess *helper) {
|
||||
if (helper->state() == QProcess::NotRunning) {
|
||||
if (helper == m_helper_process) {
|
||||
helper->start(m_helper_exe_path, m_helper_exe_args);
|
||||
m_helper_start_time.restart();
|
||||
} else if (helper == m_helper64_process) {
|
||||
helper->start(m_helper64_exe_path, m_helper64_exe_args);
|
||||
m_helper64_start_time.restart();
|
||||
}
|
||||
} else {
|
||||
qWarning("OverlayPrivateWin: startHelper() called while process is already running. skipping.");
|
||||
@ -194,11 +204,18 @@ void OverlayPrivateWin::onHelperProcessError(QProcess::ProcessError processError
|
||||
|
||||
void OverlayPrivateWin::onHelperProcessExited(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
QProcess *helper = qobject_cast<QProcess *>(sender());
|
||||
|
||||
QString path;
|
||||
qint64 elapsedMsec;
|
||||
QTimer *restartTimer;
|
||||
if (helper == m_helper_process) {
|
||||
path = m_helper_exe_path;
|
||||
elapsedMsec = m_helper_start_time.elapsed();
|
||||
restartTimer = m_helper_restart_timer;
|
||||
} else if (helper == m_helper64_process) {
|
||||
path = m_helper64_exe_path;
|
||||
elapsedMsec = m_helper64_start_time.elapsed();
|
||||
restartTimer = m_helper64_restart_timer;
|
||||
}
|
||||
|
||||
const char *helperErrString = OverlayHelperErrorToString(static_cast<OverlayHelperError>(exitCode));
|
||||
@ -210,7 +227,43 @@ void OverlayPrivateWin::onHelperProcessExited(int exitCode, QProcess::ExitStatus
|
||||
// If the helper process exited while we're in 'active'
|
||||
// mode, restart it.
|
||||
if (m_active) {
|
||||
// If the helper was only recently started, be
|
||||
// a little more patient with restarting it.
|
||||
// We could be hitting a crash bug in the helper,
|
||||
// and we don't want to do too much harm in that
|
||||
// case by spawning thousands of processes.
|
||||
qint64 cooldownMsec = (qint64) g.s.iOverlayWinHelperRestartCooldownMsec;
|
||||
if (elapsedMsec < cooldownMsec) {
|
||||
qint64 delayMsec = cooldownMsec - elapsedMsec;
|
||||
qWarning("OverlayPrivateWin: waiting %llu seconds until restarting helper process '%s'. last restart was %llu seconds ago.",
|
||||
(unsigned long long) delayMsec/1000ULL,
|
||||
qPrintable(path),
|
||||
(unsigned long long) elapsedMsec/1000ULL);
|
||||
if (!restartTimer->isActive()) {
|
||||
restartTimer->start(delayMsec);
|
||||
}
|
||||
} else {
|
||||
startHelper(helper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayPrivateWin::onDelayedRestartTimerTriggered() {
|
||||
if (!m_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer *timer = qobject_cast<QTimer *>(sender());
|
||||
|
||||
QProcess *helper = NULL;
|
||||
if (timer == m_helper_restart_timer) {
|
||||
helper = m_helper_process;
|
||||
} else if (timer == m_helper64_restart_timer) {
|
||||
helper = m_helper64_process;
|
||||
}
|
||||
|
||||
if (helper->state() == QProcess::NotRunning) {
|
||||
startHelper(helper);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -35,6 +35,8 @@
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QProcess>
|
||||
#include <QTimer>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include "Overlay.h"
|
||||
|
||||
@ -52,15 +54,20 @@ class OverlayPrivateWin : public OverlayPrivate {
|
||||
void onHelperProcessStarted();
|
||||
void onHelperProcessError(QProcess::ProcessError);
|
||||
void onHelperProcessExited(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void onDelayedRestartTimerTriggered();
|
||||
|
||||
protected:
|
||||
QProcess *m_helper_process;
|
||||
QString m_helper_exe_path;
|
||||
QStringList m_helper_exe_args;
|
||||
QElapsedTimer m_helper_start_time;
|
||||
QTimer *m_helper_restart_timer;
|
||||
|
||||
QProcess *m_helper64_process;
|
||||
QString m_helper64_exe_path;
|
||||
QStringList m_helper64_exe_args;
|
||||
QElapsedTimer m_helper64_start_time;
|
||||
QTimer *m_helper64_restart_timer;
|
||||
|
||||
bool m_active;
|
||||
bool m_allow64bit;
|
||||
|
||||
@ -345,6 +345,9 @@ Settings::Settings() {
|
||||
fAudioMaxDistVolume = 0.80f;
|
||||
fAudioBloom = 0.5f;
|
||||
|
||||
// OverlayPrivateWin
|
||||
iOverlayWinHelperRestartCooldownMsec = 10000;
|
||||
|
||||
iLCDUserViewMinColWidth = 50;
|
||||
iLCDUserViewSplitterWidth = 2;
|
||||
|
||||
@ -696,7 +699,9 @@ void Settings::load(QSettings* settings_ptr) {
|
||||
SAVELOAD(bDisableCELT, "audio/disablecelt");
|
||||
SAVELOAD(disablePublicList, "ui/disablepubliclist");
|
||||
SAVELOAD(disableConnectDialogEditing, "ui/disableconnectdialogediting");
|
||||
|
||||
|
||||
// OverlayPrivateWin
|
||||
SAVELOAD(iOverlayWinHelperRestartCooldownMsec, "overlay_win/helper/restart_cooldown_msec");
|
||||
|
||||
// LCD
|
||||
SAVELOAD(iLCDUserViewMinColWidth, "lcd/userview/mincolwidth");
|
||||
@ -990,6 +995,9 @@ void Settings::save() {
|
||||
SAVELOAD(disablePublicList, "ui/disablepubliclist");
|
||||
SAVELOAD(disableConnectDialogEditing, "ui/disableconnectdialogediting");
|
||||
|
||||
// OverlayPrivateWin
|
||||
SAVELOAD(iOverlayWinHelperRestartCooldownMsec, "overlay_win/helper/restart_cooldown_msec");
|
||||
|
||||
// LCD
|
||||
SAVELOAD(iLCDUserViewMinColWidth, "lcd/userview/mincolwidth");
|
||||
SAVELOAD(iLCDUserViewSplitterWidth, "lcd/userview/splitterwidth");
|
||||
|
||||
@ -230,6 +230,8 @@ struct Settings {
|
||||
|
||||
OverlaySettings os;
|
||||
|
||||
int iOverlayWinHelperRestartCooldownMsec;
|
||||
|
||||
int iLCDUserViewMinColWidth;
|
||||
int iLCDUserViewSplitterWidth;
|
||||
QMap<QString, bool> qmLCDDevices;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user