-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ProcessBider, allows waiting for an arbitrary process to end
- Loading branch information
1 parent
3447fc2
commit fae59cb
Showing
11 changed files
with
1,677 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
#ifndef QX_PROCCESSBIDER_H | ||
#define QX_PROCCESSBIDER_H | ||
|
||
// Shared Lib Support | ||
#include "qx/core/qx_core_export.h" | ||
|
||
// Qt Includes | ||
#include <QObject> | ||
|
||
// Inter-component Includes | ||
#include <qx/core/qx-abstracterror.h> | ||
|
||
using namespace std::chrono_literals; | ||
|
||
namespace Qx | ||
{ | ||
|
||
class QX_CORE_EXPORT ProcessBiderError final : public AbstractError<"Qx::ProcessBiderError", 6> | ||
{ | ||
friend class ProcessBider; | ||
//-Class Enums------------------------------------------------------------- | ||
public: | ||
enum Type | ||
{ | ||
NoError, | ||
FailedToHook, | ||
FailedToClose | ||
}; | ||
|
||
//-Class Variables------------------------------------------------------------- | ||
private: | ||
static inline const QHash<Type, QString> ERR_STRINGS{ | ||
{NoError, u""_s}, | ||
{FailedToHook, u"Could not hook the process in order to bide on it."_s}, | ||
{FailedToClose, u"Could not close the bided process."_s} | ||
}; | ||
|
||
//-Instance Variables------------------------------------------------------------- | ||
private: | ||
Type mType; | ||
QString mProcessName; | ||
|
||
//-Constructor------------------------------------------------------------- | ||
private: | ||
ProcessBiderError(Type t, const QString& pn); | ||
|
||
//-Instance Functions------------------------------------------------------------- | ||
private: | ||
quint32 deriveValue() const override; | ||
QString derivePrimary() const override; | ||
QString deriveSecondary() const override; | ||
|
||
public: | ||
bool isValid() const; | ||
Type type() const; | ||
QString processName() const; | ||
}; | ||
|
||
class QX_CORE_EXPORT ProcessBider : public QObject | ||
{ | ||
friend class ProcessBiderManager; | ||
Q_OBJECT | ||
//-Class Types---------------------------------------------------------------------------------------------- | ||
public: | ||
enum ResultType { Fail, Expired, Abandoned }; | ||
|
||
//-Instance Members------------------------------------------------------------------------------------------ | ||
private: | ||
// Data | ||
QString mName; | ||
std::chrono::milliseconds mGrace; | ||
#ifdef __linux__ | ||
std::chrono::milliseconds mPollRate; | ||
#endif | ||
bool mInitialGrace; | ||
|
||
// Functional | ||
bool mBiding; | ||
|
||
//-Constructor---------------------------------------------------------------------------------------------- | ||
public: | ||
explicit ProcessBider(QObject* parent = nullptr, const QString& processName = {}); | ||
|
||
//-Instance Functions---------------------------------------------------------------------------------------------- | ||
public: | ||
bool isBiding() const; | ||
QString processName() const; | ||
std::chrono::milliseconds respawnGrace() const; | ||
bool initialGrace() const; | ||
|
||
void setProcessName(const QString& name); | ||
void setRespawnGrace(std::chrono::milliseconds grace); | ||
void setInitialGrace(bool initialGrace); | ||
|
||
#ifdef __linux__ | ||
std::chrono::milliseconds pollRate() const; | ||
void setPollRate(std::chrono::milliseconds rate); | ||
#endif | ||
|
||
//-Slots------------------------------------------------------------------------------------------------------------ | ||
private slots: | ||
void handleResultReady(ResultType result); | ||
void handleCloseFailure(); | ||
|
||
public slots: | ||
void start(); | ||
void stop(); | ||
void closeProcess(std::chrono::milliseconds timeout = 1000ms, bool force = false); | ||
|
||
//-Signals------------------------------------------------------------------------------------------------------------ | ||
signals: | ||
void started(); | ||
void established(); | ||
void graceStarted(); | ||
void processStopped(); | ||
void processClosing(); | ||
void stopped(); | ||
void errorOccurred(ProcessBiderError error); | ||
void finished(ResultType result); | ||
|
||
/*! @cond */ | ||
// Temporary until using PIMPL or changing implementation otherwise | ||
void __startClose(std::chrono::milliseconds timeout, bool force); | ||
/*! @endcond */ | ||
}; | ||
|
||
} | ||
|
||
#endif // QX_PROCCESSBIDER_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// Unit Includes | ||
#include "qx-processwaiter.h" | ||
|
||
namespace Qx | ||
{ | ||
/*! @cond */ | ||
|
||
//=============================================================================================================== | ||
// AbstractProcessWaiter | ||
//=============================================================================================================== | ||
|
||
//-Constructor---------------------------------------------------------------------------------------------- | ||
//Public: | ||
AbstractProcessWaiter::AbstractProcessWaiter(QObject* parent) : | ||
QObject(parent), | ||
mId(0) | ||
{} | ||
|
||
//-Instance Functions--------------------------------------------------------------------------------------------- | ||
//Private: | ||
void AbstractProcessWaiter::postDeadWait(bool died) | ||
{ | ||
// Move out callback incase the callback replaces itself | ||
auto cb = std::move(mDeadWaitCallback); | ||
mDeadWaitCallback = {}; | ||
|
||
// Call | ||
cb(died); | ||
} | ||
|
||
void AbstractProcessWaiter::timerEvent(QTimerEvent* event) | ||
{ | ||
Q_UNUSED(event); | ||
mDeadWaitTimer.stop(); | ||
postDeadWait(false); | ||
} | ||
|
||
//Protected: | ||
void AbstractProcessWaiter::waitForDead(std::chrono::milliseconds timeout, std::function<void(bool)> callback) | ||
{ | ||
Q_ASSERT(!mDeadWaitCallback); // Current implementation doesn't support multiple callbacks | ||
|
||
// Store callback | ||
mDeadWaitCallback = std::move(callback); | ||
|
||
// One-shot wait on dead signal | ||
connect(this, &AbstractProcessWaiter::dead, this, [this]{ | ||
if(mDeadWaitTimer.isActive()) // In case timer already expired and this was behind in queue | ||
{ | ||
mDeadWaitTimer.stop(); | ||
postDeadWait(true); | ||
} | ||
}, Qt::ConnectionType(Qt::DirectConnection | Qt::SingleShotConnection)); | ||
mDeadWaitTimer.start(timeout, this); | ||
} | ||
|
||
//Public: | ||
void AbstractProcessWaiter::close(std::chrono::milliseconds timeout, bool force) | ||
{ | ||
// If waiting happened to stop, ignore | ||
if(!isWaiting()) | ||
return; | ||
|
||
closeImpl(timeout, force); | ||
} | ||
|
||
void AbstractProcessWaiter::setId(quint32 id) { mId = id; } | ||
|
||
/*! @endcond */ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
#ifndef QX_PROCCESSWAITER_H | ||
#define QX_PROCCESSWAITER_H | ||
|
||
// Qt Includes | ||
#include <QObject> | ||
#include <QBasicTimer> | ||
|
||
namespace Qx | ||
{ | ||
/*! @cond */ | ||
|
||
class AbstractProcessWaiter : public QObject | ||
{ | ||
Q_OBJECT | ||
//-Class Members------------------------------------------------------------------------------------------ | ||
protected: | ||
static const int CLEAN_KILL_GRACE_MS = 5000; | ||
|
||
//-Instance Members------------------------------------------------------------------------------------------ | ||
protected: | ||
// Data | ||
quint32 mId; | ||
|
||
// Functional | ||
QBasicTimer mDeadWaitTimer; | ||
std::function<void(bool)> mDeadWaitCallback; | ||
|
||
//-Constructor---------------------------------------------------------------------------------------------- | ||
public: | ||
explicit AbstractProcessWaiter(QObject* parent); | ||
|
||
//-Instance Functions---------------------------------------------------------------------------------------------- | ||
private: | ||
void postDeadWait(bool died); | ||
void timerEvent(QTimerEvent* event) override; | ||
|
||
protected: | ||
void waitForDead(std::chrono::milliseconds timeout, std::function<void(bool)> callback); | ||
virtual void closeImpl(std::chrono::milliseconds timeout, bool force) = 0; | ||
|
||
public: | ||
virtual bool wait() = 0; | ||
virtual bool isWaiting() const = 0; | ||
void close(std::chrono::milliseconds timeout, bool force); | ||
void setId(quint32 id); | ||
|
||
//-Slots------------------------------------------------------------------------------------------------------------ | ||
protected slots: | ||
virtual void handleProcessSignaled() = 0; | ||
|
||
//-Signals------------------------------------------------------------------------------------------------------------ | ||
signals: | ||
void dead(); | ||
void closeFailed(); | ||
}; | ||
|
||
/*! @endcond */ | ||
} | ||
|
||
#endif // QX_PROCCESSWAITER_H |
Oops, something went wrong.