Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qprocesstask.h
Go to the documentation of this file.
1// Copyright (C) 2024 Jarek Kobus
2// Copyright (C) 2024 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef TASKING_QPROCESSTASK_H
6#define TASKING_QPROCESSTASK_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include "tasking_global.h"
20
21#include "tasktree.h"
22
23#include <QtCore/QProcess>
24
26
27#if QT_CONFIG(process)
28
29namespace Tasking {
30
31// Deleting a running QProcess may block the caller thread up to 30 seconds and issue warnings.
32// To avoid these issues we move the running QProcess into a separate thread
33// managed by the internal ProcessReaper, instead of deleting it immediately.
34// Inside the ProcessReaper's thread we try to finish the process in a most gentle way:
35// we call QProcess::terminate() with 500 ms timeout, and if the process is still running
36// after this timeout passed, we call QProcess::kill() and wait for the process to finish.
37// All these handlings are done is a separate thread, so the main thread doesn't block at all
38// when the QProcessTask is destructed.
39// Finally, on application quit, QProcessDeleter::deleteAll() should be called in order
40// to synchronize all the processes being still potentially reaped in a separate thread.
41// The call to QProcessDeleter::deleteAll() is blocking in case some processes
42// are still being reaped.
43// This strategy seems most sensible, since when passing the running QProcess into the
44// ProcessReaper we don't block immediately, but postpone the possible (not certain) block
45// until the end of an application.
46// In this way we terminate the running processes in the most safe way and keep the main thread
47// responsive. That's a common case when the running application wants to terminate the QProcess
48// immediately (e.g. on Cancel button pressed), without keeping and managing the handle
49// to the still running QProcess.
50
51// The implementation of the internal reaper is inspired by the Utils::ProcessReaper taken
52// from the QtCreator codebase.
53
54class TASKING_EXPORT QProcessDeleter
55{
56public:
57 // Blocking, should be called after all QProcessAdapter instances are deleted.
58 static void deleteAll();
59 void operator()(QProcess *process);
60};
61
62class TASKING_EXPORT QProcessAdapter : public TaskAdapter<QProcess, QProcessDeleter>
63{
64private:
65 void start() final {
66 connect(task(), &QProcess::finished, this, [this] {
67 const bool success = task()->exitStatus() == QProcess::NormalExit
68 && task()->error() == QProcess::UnknownError
69 && task()->exitCode() == 0;
70 Q_EMIT done(toDoneResult(success));
71 });
72 connect(task(), &QProcess::errorOccurred, this, [this](QProcess::ProcessError error) {
73 if (error != QProcess::FailedToStart)
74 return;
75 Q_EMIT done(DoneResult::Error);
76 });
77 task()->start();
78 }
79};
80
81using QProcessTask = CustomTask<QProcessAdapter>;
82
83} // namespace Tasking
84
85#endif // QT_CONFIG(process)
86
88
89#endif // TASKING_QPROCESSTASK_H
Combined button and popup list for selecting options.
\inmodule TaskingSolution
Definition barrier.cpp:9
DoneResult toDoneResult(bool success)
DBusConnection const char DBusError * error
GLuint start
#define Q_EMIT
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
#define TASKING_EXPORT