mirror of
https://invent.kde.org/marcoa/a-la-karte.git
synced 2026-03-26 17:03:08 +00:00
Harden transient scope lifecycle
Improve GameCenter daemon handling of systemd transient scopes. - Watch monitored-launch scopes early and avoid dropping Launching sessions when the unit disappears before PIDs are attached. - Stop leaked scopes on AttachProcessesToUnit failures. - Make Stop() resilient for recovered sessions by falling back to TERM/KILL on scope PIDs when StopUnit fails unexpectedly. - Only recover scopes that match the expected A-La-Karte description.
This commit is contained in:
parent
d56b91dbd0
commit
985f6dac03
1 changed files with 70 additions and 1 deletions
|
|
@ -803,6 +803,18 @@ void GameCenterDaemon::handleSystemdUnitRemoved(const QString &unitName, const Q
|
|||
return;
|
||||
}
|
||||
|
||||
if (sit.value().scanner) {
|
||||
if (!sit.value().unitPath.path().isEmpty()) {
|
||||
const QString unitPathKey = sit.value().unitPath.path();
|
||||
m_unitPathToSessionId.remove(unitPathKey);
|
||||
if (QObject *watcher = m_unitPathWatchers.take(unitPathKey)) {
|
||||
watcher->deleteLater();
|
||||
}
|
||||
}
|
||||
sit.value().unitPath = {};
|
||||
return;
|
||||
}
|
||||
|
||||
unwatchSystemdUnit(sit.value().unitName, sit.value().unitPath);
|
||||
removeSessionInternal(sessionId, sit.value().stopping ? QStringLiteral("Stopped") : QStringLiteral("Exited"));
|
||||
}
|
||||
|
|
@ -833,6 +845,25 @@ void GameCenterDaemon::handleSystemdUnitPropertiesChanged(const QDBusObjectPath
|
|||
}
|
||||
const QString activeState = activeStateV.toString();
|
||||
|
||||
if (sit.value().scanner) {
|
||||
if (activeState == QLatin1String("active") || activeState == QLatin1String("activating") || activeState == QLatin1String("deactivating")) {
|
||||
const QList<uint> pids = m_systemd.scopePids(unitPath);
|
||||
if (!pids.isEmpty()) {
|
||||
sit.value().mainPid = pids.first();
|
||||
}
|
||||
} else {
|
||||
const QString unitPathKey = unitPath.path();
|
||||
m_unitPathToSessionId.remove(unitPathKey);
|
||||
if (QObject *watcher = m_unitPathWatchers.take(unitPathKey)) {
|
||||
watcher->deleteLater();
|
||||
}
|
||||
sit.value().unitPath = {};
|
||||
}
|
||||
|
||||
Q_EMIT SessionChanged(sessionToVariantMap(sit.value(), sessionState(sit.value())));
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeState == QLatin1String("active") || activeState == QLatin1String("activating") || activeState == QLatin1String("deactivating")) {
|
||||
const QList<uint> pids = m_systemd.scopePids(unitPath);
|
||||
if (!pids.isEmpty()) {
|
||||
|
|
@ -1495,6 +1526,8 @@ QString GameCenterDaemon::launchMonitored(const QVariantMap &launchSpec, const Q
|
|||
|
||||
m_sessions[sessionId] = session;
|
||||
|
||||
watchSystemdUnit(sessionId, session.unitName, session.unitPath);
|
||||
|
||||
connect(bootstrap, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this, [this, sessionId](int, QProcess::ExitStatus) {
|
||||
const auto it = m_sessions.find(sessionId);
|
||||
if (it == m_sessions.end()) {
|
||||
|
|
@ -1609,6 +1642,11 @@ void GameCenterDaemon::attachPidsToSession(const QString &sessionId, const QList
|
|||
{QStringLiteral("error"), attachReply.error().message()},
|
||||
};
|
||||
|
||||
if (!it.value().unitName.isEmpty()) {
|
||||
m_systemd.stopUnit(it.value().unitName);
|
||||
unwatchSystemdUnit(it.value().unitName, it.value().unitPath);
|
||||
}
|
||||
|
||||
QVariantMap finalState = sessionToVariantMap(it.value(), QStringLiteral("Failed"));
|
||||
if (it.value().process) {
|
||||
it.value().process->deleteLater();
|
||||
|
|
@ -1780,6 +1818,32 @@ void GameCenterDaemon::Stop(const QString &sessionId)
|
|||
return;
|
||||
}
|
||||
|
||||
QDBusObjectPath unitPath = it.value().unitPath;
|
||||
if (unitPath.path().isEmpty()) {
|
||||
const QDBusReply<QDBusObjectPath> getUnitReply = m_systemd.getUnit(it.value().unitName);
|
||||
if (getUnitReply.isValid()) {
|
||||
unitPath = getUnitReply.value();
|
||||
it.value().unitPath = unitPath;
|
||||
watchSystemdUnit(sessionId, it.value().unitName, unitPath);
|
||||
}
|
||||
}
|
||||
|
||||
QList<uint> pids;
|
||||
if (!unitPath.path().isEmpty()) {
|
||||
pids = m_systemd.scopePids(unitPath);
|
||||
}
|
||||
if (pids.isEmpty() && it.value().mainPid > 0) {
|
||||
pids = {it.value().mainPid};
|
||||
}
|
||||
if (!pids.isEmpty()) {
|
||||
terminatePids(pids);
|
||||
QTimer::singleShot(5000, this, [pids]() {
|
||||
killPids(pids);
|
||||
});
|
||||
Q_EMIT SessionChanged(sessionToVariantMap(it.value(), QStringLiteral("Stopping")));
|
||||
return;
|
||||
}
|
||||
|
||||
if (it.value().process && it.value().process->state() != QProcess::NotRunning) {
|
||||
it.value().process->terminate();
|
||||
QTimer::singleShot(5000, it.value().process, [process = it.value().process]() {
|
||||
|
|
@ -1886,7 +1950,8 @@ void GameCenterDaemon::recoverExistingSessions()
|
|||
|
||||
static const QString prefix = QStringLiteral("alakarte-game-");
|
||||
static const QString suffix = QStringLiteral(".scope");
|
||||
static const QString descPrefix = QStringLiteral("A-La-Karte game ");
|
||||
static const QString descBase = QStringLiteral("A-La-Karte game");
|
||||
static const QString descPrefix = descBase + QLatin1Char(' ');
|
||||
|
||||
const SystemdUnitInfoList units = reply.value();
|
||||
for (const SystemdUnitInfo &unit : units) {
|
||||
|
|
@ -1897,6 +1962,10 @@ void GameCenterDaemon::recoverExistingSessions()
|
|||
continue;
|
||||
}
|
||||
|
||||
if (unit.description != descBase && !unit.description.startsWith(descPrefix)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const QString sessionId = unit.name.mid(prefix.length(), unit.name.length() - prefix.length() - suffix.length());
|
||||
if (sessionId.isEmpty() || m_sessions.contains(sessionId)) {
|
||||
continue;
|
||||
|
|
|
|||
Loading…
Reference in a new issue