KIO

scopedprocessrunner.cpp
1#include "kiogui_debug.h"
2#include "managerinterface.h"
3#include "scopedprocessrunner_p.h"
4#include "systemdprocessrunner_p.h"
5
6#include <sys/eventfd.h>
7#include <unistd.h>
8
9using namespace org::freedesktop;
10
11ScopedProcessRunner::ScopedProcessRunner()
12 : ForkingProcessRunner()
13{
14}
15
16void ScopedProcessRunner::startProcess()
17{
18 std::function oldModifier = m_process->childProcessModifier();
19 int efd = eventfd(0, EFD_CLOEXEC);
20 m_process->setChildProcessModifier([efd, oldModifier]() {
21 // wait for the parent process to be done registering the transient unit
22 eventfd_read(efd, nullptr);
23 if (oldModifier)
24 oldModifier();
25 });
26
27 // actually start
28 ForkingProcessRunner::startProcess();
29 m_process->setChildProcessModifier(oldModifier);
30
31 Q_ASSERT(m_process->processId());
32
33 // As specified in "XDG standardization for applications" in https://systemd.io/DESKTOP_ENVIRONMENTS/
34 const QString serviceName = QStringLiteral("app-%1-%2.scope").arg(escapeUnitName(resolveServiceAlias()), QUuid::createUuid().toString(QUuid::Id128));
35
36 const auto manager = new systemd1::Manager(systemdService, systemdPath, QDBusConnection::sessionBus(), this);
37
38 // Ask systemd for a new transient service
39 const auto startReply =
40 manager->StartTransientUnit(serviceName,
41 QStringLiteral("fail"), // mode defines what to do in the case of a name conflict, in this case, just do nothing
42 {// Properties of the transient service unit
43 {QStringLiteral("Slice"), QStringLiteral("app.slice")},
44 {QStringLiteral("Description"), m_description},
45 {QStringLiteral("SourcePath"), m_desktopFilePath},
46 {QStringLiteral("PIDs"), QVariant::fromValue(QList<uint>{static_cast<uint>(m_process->processId())})}},
47 {} // aux is currently unused and should be passed as empty array.
48 );
49
50 m_transientUnitStartupwatcher = new QDBusPendingCallWatcher(startReply, this);
51 connect(m_transientUnitStartupwatcher, &QDBusPendingCallWatcher::finished, [serviceName, efd](QDBusPendingCallWatcher *watcher) {
53 watcher->deleteLater();
54 if (reply.isError()) {
55 qCWarning(KIO_GUI) << "Failed to register new cgroup:" << serviceName << reply.error().name() << reply.error().message();
56 } else {
57 qCDebug(KIO_GUI) << "Successfully registered new cgroup:" << serviceName;
58 }
59
60 // release child and close the eventfd
61 eventfd_write(efd, 1);
62 close(efd);
63 });
64}
65
66bool ScopedProcessRunner::waitForStarted(int timeout)
67{
68 if (m_process->state() == QProcess::NotRunning || m_waitingForXdgToken || !m_transientUnitStartupwatcher->isFinished()) {
69 QEventLoop loop;
71 QObject::connect(m_transientUnitStartupwatcher, &QDBusPendingCallWatcher::finished, &loop, &QEventLoop::quit);
72 QTimer::singleShot(timeout, &loop, &QEventLoop::quit);
73 loop.exec();
74 }
75 return m_process->waitForStarted(timeout);
76}
77
78#include "moc_scopedprocessrunner_p.cpp"
char * toString(const EngineQuery &query)
const QList< QKeySequence > & close()
QDBusConnection sessionBus()
QString message() const const
QString name() const const
void finished(QDBusPendingCallWatcher *self)
QDBusError error() const const
bool isError() const const
int exec(ProcessEventsFlags flags)
void quit()
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
void stateChanged(QProcess::ProcessState newState)
QString arg(Args &&... args) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QUuid createUuid()
QVariant fromValue(T &&value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 16:58:45 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.