summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/core-lib.pri1
-rw-r--r--src/core/forklauncher.cpp2
-rw-r--r--src/core/pipelauncher.cpp57
-rw-r--r--src/core/pipelauncher.h4
-rw-r--r--src/core/pipeprocessbackendfactory.cpp45
-rw-r--r--src/core/pipeprocessbackendfactory.h2
-rw-r--r--src/core/preforkprocessbackendfactory.cpp27
-rw-r--r--src/core/preforkprocessbackendfactory.h3
-rw-r--r--src/core/prelaunchprocessbackendfactory.cpp63
-rw-r--r--src/core/prelaunchprocessbackendfactory.h6
-rw-r--r--src/core/processbackendfactory.cpp35
-rw-r--r--src/core/processbackendfactory.h16
-rw-r--r--src/core/processbackendmanager.cpp47
-rw-r--r--src/core/processbackendmanager.h9
-rw-r--r--src/core/processlist.h81
-rw-r--r--src/core/processmanager.cpp2
-rw-r--r--src/core/processmanager.h3
-rw-r--r--src/core/remoteprocessbackendfactory.cpp68
-rw-r--r--src/core/remoteprocessbackendfactory.h10
-rw-r--r--src/core/remoteprotocol.h8
-rw-r--r--src/core/socketlauncher.cpp84
-rw-r--r--src/core/socketlauncher.h7
-rw-r--r--src/core/socketprocessbackendfactory.cpp10
-rw-r--r--src/core/socketprocessbackendfactory.h1
24 files changed, 472 insertions, 119 deletions
diff --git a/src/core/core-lib.pri b/src/core/core-lib.pri
index 358192d..7c3f0fe 100644
--- a/src/core/core-lib.pri
+++ b/src/core/core-lib.pri
@@ -5,6 +5,7 @@ INCLUDEPATH += $$PWD
PUBLIC_HEADERS += \
$$PWD/process.h \
+ $$PWD/processlist.h \
$$PWD/processfrontend.h \
$$PWD/processbackend.h \
$$PWD/processbackendfactory.h \
diff --git a/src/core/forklauncher.cpp b/src/core/forklauncher.cpp
index 08efc4b..49ba3c0 100644
--- a/src/core/forklauncher.cpp
+++ b/src/core/forklauncher.cpp
@@ -553,7 +553,7 @@ bool ParentProcess::processFdSet(fd_set& rfds, fd_set& wfds)
// Return 'true' if this is a child process
bool ParentProcess::handleMessage(QJsonObject& message)
{
- if (message.value(RemoteProtocol::remote()).toString() == RemoteProtocol::stop()) {
+ if (message.value(RemoteProtocol::remote()).toString() == RemoteProtocol::halt()) {
// Force all children to stop
foreach (ChildProcess *child, m_children)
child->stop(0);
diff --git a/src/core/pipelauncher.cpp b/src/core/pipelauncher.cpp
index ef70185..d59168c 100644
--- a/src/core/pipelauncher.cpp
+++ b/src/core/pipelauncher.cpp
@@ -53,6 +53,10 @@ QT_BEGIN_NAMESPACE_PROCESSMANAGER
/*!
\class PipeLauncher
\brief The PipeLauncher class accepts input from STDIN and writes data to STDOUT
+
+ The PipeLauncher class is a ProcessBackendManager controlled over Unix
+ pipes. It accepts JSON-formatted commands over STDIN and returns
+ JSON-formatted messages over STDOUT.
*/
/*!
@@ -73,6 +77,47 @@ PipeLauncher::PipeLauncher(QObject *parent)
m_pipe, SLOT(send(const QJsonObject&)));
m_pipe->setFds(STDIN_FILENO, STDOUT_FILENO);
+
+ // Clear the idle delegate - we'll get this from the master
+ setIdleDelegate(0);
+}
+
+/*!
+ \internal
+
+ We override this function to send our idle cpu request back to the
+ originator. The \a request variable will be \c{true} if Idle CPU events are needed.
+ We only forward the request if we don't have an idle delegate.
+ */
+
+void PipeLauncher::handleIdleCpuRequest()
+{
+ Q_ASSERT(m_client);
+
+ if (!idleDelegate()) {
+ QJsonObject object;
+ object.insert(RemoteProtocol::remote(), RemoteProtocol::idlecpurequested());
+ object.insert(RemoteProtocol::request(), idleCpuRequest());
+ m_client->send(object);
+ }
+}
+
+/*!
+ \internal
+
+ We override this function to send our updated list of internal
+ processes back. Please note that we do not include our own process -
+ if that should be on the list, it's up to the controlling side to add it.
+*/
+
+void PipeLauncher::handleInternalProcessChange()
+{
+ Q_ASSERT(m_client);
+
+ QJsonObject object;
+ object.insert(RemoteProtocol::remote(), RemoteProtocol::internalprocesses());
+ object.insert(RemoteProtocol::processes(), pidListToArray(internalProcesses()));
+ m_client->send(object);
}
/*!
@@ -81,9 +126,17 @@ PipeLauncher::PipeLauncher(QObject *parent)
void PipeLauncher::receive(const QJsonObject& message)
{
- if (message.value(RemoteProtocol::remote()).toString() == RemoteProtocol::stop())
+ QString remote = message.value(RemoteProtocol::remote()).toString();
+ if (remote == RemoteProtocol::halt()) // ### TODO: Should halt children
exit(0);
- m_client->receive(message);
+ else if ( remote == RemoteProtocol::memory() )
+ setMemoryRestricted(message.value(RemoteProtocol::restricted()).toBool());
+ else if ( remote == RemoteProtocol::idlecpuavailable() ) {
+ if (!idleDelegate())
+ idleCpuAvailable(); // Only accept idlecpuavailable if we have no idleDelegate
+ }
+ else
+ m_client->receive(message);
}
#include "moc_pipelauncher.cpp"
diff --git a/src/core/pipelauncher.h b/src/core/pipelauncher.h
index 9a43063..afa80e2 100644
--- a/src/core/pipelauncher.h
+++ b/src/core/pipelauncher.h
@@ -56,6 +56,10 @@ class Q_ADDON_PROCESSMANAGER_EXPORT PipeLauncher : public ProcessBackendManager
public:
PipeLauncher(QObject *parent=0);
+protected:
+ virtual void handleIdleCpuRequest();
+ virtual void handleInternalProcessChange();
+
private slots:
void receive(const QJsonObject& object);
diff --git a/src/core/pipeprocessbackendfactory.cpp b/src/core/pipeprocessbackendfactory.cpp
index c9a3435..4b7e946 100644
--- a/src/core/pipeprocessbackendfactory.cpp
+++ b/src/core/pipeprocessbackendfactory.cpp
@@ -99,7 +99,7 @@ void PipeProcessBackendFactory::stopRemoteProcess()
{
if (m_process && m_process->state() == QProcess::Running) {
QJsonObject object;
- object.insert(RemoteProtocol::remote(), RemoteProtocol::stop());
+ object.insert(RemoteProtocol::remote(), RemoteProtocol::halt());
m_process->write(QJsonDocument(object).toBinaryData());
m_process->waitForBytesWritten(); // Block until they have been written
m_process = NULL;
@@ -123,18 +123,6 @@ bool PipeProcessBackendFactory::canCreate(const ProcessInfo &info) const
}
/*!
- If there is a pipe process running, it will be returned here.
- */
-
-QList<Q_PID> PipeProcessBackendFactory::internalProcesses()
-{
- QList<Q_PID> list;
- if (m_process && m_process->state() == QProcess::Running)
- list << m_process->pid();
- return list;
-}
-
-/*!
Sets the ProcessInfo that is used to create the pipe process to \a processInfo.
An internal copy is made of the \a processInfo object.
This routine will start the pipe process.
@@ -204,19 +192,25 @@ ProcessInfo *PipeProcessBackendFactory::processInfo() const
}
/*!
+ Return the local process if it is running
+ */
+
+PidList PipeProcessBackendFactory::localInternalProcesses() const
+{
+ PidList result;
+ if (m_process && m_process->state() == QProcess::Running)
+ result << m_process->pid();
+ return result;
+}
+
+/*!
Send \a message to a pipe process.
*/
bool PipeProcessBackendFactory::send(const QJsonObject& message)
{
- if (m_process->state() != QProcess::Running) {
- qCritical("Pipe process not running");
- return false;
- }
- if (m_process->write(QJsonDocument(message).toBinaryData()) == -1) {
- qCritical("Unable to write to pipe process");
- return false;
- }
- return true;
+ // qDebug() << Q_FUNC_INFO << message;
+ return (m_process->state() == QProcess::Running &&
+ m_process->write(QJsonDocument(message).toBinaryData()) != -1);
}
@@ -247,6 +241,7 @@ void PipeProcessBackendFactory::pipeReadyReadStandardError()
void PipeProcessBackendFactory::pipeStarted()
{
+ handleConnected();
}
void PipeProcessBackendFactory::pipeError(QProcess::ProcessError error)
@@ -261,9 +256,11 @@ void PipeProcessBackendFactory::pipeFinished(int exitCode, QProcess::ExitStatus
m_process = NULL;
}
-void PipeProcessBackendFactory::pipeStateChanged(QProcess::ProcessState state)
+void PipeProcessBackendFactory::pipeStateChanged(QProcess::ProcessState)
{
- Q_UNUSED(state);
+ // This may result in a small amount of extra because not all transitions
+ // result in a change in the number of internal processes.
+ setInternalProcesses(localInternalProcesses());
}
diff --git a/src/core/pipeprocessbackendfactory.h b/src/core/pipeprocessbackendfactory.h
index 7dbee9e..ed76fd6 100644
--- a/src/core/pipeprocessbackendfactory.h
+++ b/src/core/pipeprocessbackendfactory.h
@@ -54,7 +54,6 @@ public:
virtual ~PipeProcessBackendFactory();
virtual bool canCreate(const ProcessInfo &info) const;
- virtual QList<Q_PID> internalProcesses();
ProcessInfo *processInfo() const;
void setProcessInfo(ProcessInfo *processInfo);
@@ -64,6 +63,7 @@ signals:
void processInfoChanged();
protected:
+ virtual PidList localInternalProcesses() const;
virtual bool send(const QJsonObject&);
private slots:
diff --git a/src/core/preforkprocessbackendfactory.cpp b/src/core/preforkprocessbackendfactory.cpp
index 7b8eca6..d9bbba4 100644
--- a/src/core/preforkprocessbackendfactory.cpp
+++ b/src/core/preforkprocessbackendfactory.cpp
@@ -82,6 +82,7 @@ PreforkProcessBackendFactory::PreforkProcessBackendFactory(QObject *parent)
m_pipe = new QtAddOn::JsonStream::JsonPipe(this);
connect(m_pipe, SIGNAL(messageReceived(const QJsonObject&)),
SLOT(receive(const QJsonObject&)));
+ handleConnected();
}
/*!
@@ -93,7 +94,7 @@ PreforkProcessBackendFactory::~PreforkProcessBackendFactory()
const PreforkChildData *data = Prefork::instance()->at(m_index);
if (data) {
QJsonObject message;
- message.insert(RemoteProtocol::remote(), RemoteProtocol::stop());
+ message.insert(RemoteProtocol::remote(), RemoteProtocol::halt());
m_pipe->send(message);
m_pipe->waitForBytesWritten();
}
@@ -128,25 +129,29 @@ void PreforkProcessBackendFactory::setIndex(int index)
}
/*!
- Send a \a message to the preforked process
+ Return the local process
*/
-bool PreforkProcessBackendFactory::send(const QJsonObject& message)
+PidList PreforkProcessBackendFactory::localInternalProcesses() const
{
- return m_pipe->send(message);
+ Prefork *prefork = Prefork::instance();
+ Q_ASSERT(prefork);
+
+ QList<Q_PID> list;
+ if (m_index >= 0 && m_index < prefork->size()) {
+ const PreforkChildData *data = prefork->at(m_index);
+ list << data->pid;
+ }
+ return list;
}
/*!
- Return the preforked process
+ Send a \a message to the preforked process
*/
-QList<Q_PID> PreforkProcessBackendFactory::internalProcesses()
+bool PreforkProcessBackendFactory::send(const QJsonObject& message)
{
- QList<Q_PID> list;
- const PreforkChildData *data = Prefork::instance()->at(m_index);
- if (data)
- list << data->pid;
- return list;
+ return m_pipe->send(message);
}
/*!
diff --git a/src/core/preforkprocessbackendfactory.h b/src/core/preforkprocessbackendfactory.h
index 912668c..b7e79ba 100644
--- a/src/core/preforkprocessbackendfactory.h
+++ b/src/core/preforkprocessbackendfactory.h
@@ -57,12 +57,11 @@ public:
int index() const;
void setIndex(int index);
- virtual QList<Q_PID> internalProcesses();
-
signals:
void indexChanged();
protected:
+ virtual PidList localInternalProcesses() const;
virtual bool send(const QJsonObject&);
private:
diff --git a/src/core/prelaunchprocessbackendfactory.cpp b/src/core/prelaunchprocessbackendfactory.cpp
index eb64464..3d839c7 100644
--- a/src/core/prelaunchprocessbackendfactory.cpp
+++ b/src/core/prelaunchprocessbackendfactory.cpp
@@ -111,16 +111,15 @@ bool PrelaunchProcessBackendFactory::canCreate(const ProcessInfo &info) const
ProcessBackend * PrelaunchProcessBackendFactory::create(const ProcessInfo &info, QObject *parent)
{
Q_ASSERT(m_info);
-
PrelaunchProcessBackend *prelaunch = m_prelaunch;
if (hasPrelaunchedProcess()) {
// qDebug() << "Using existing prelaunch";
m_prelaunch = NULL;
- startPrelaunchTimer();
prelaunch->setInfo(info);
prelaunch->setParent(parent);
prelaunch->disconnect(this);
+ updateState();
} else {
// qDebug() << "Creating prelaunch from scratch";
prelaunch = new PrelaunchProcessBackend(*m_info, parent);
@@ -131,18 +130,6 @@ ProcessBackend * PrelaunchProcessBackendFactory::create(const ProcessInfo &info,
}
/*!
- If there is a prelaunched process running, it will be return here.
- */
-
-QList<Q_PID> PrelaunchProcessBackendFactory::internalProcesses()
-{
- QList<Q_PID> list;
- if (m_prelaunch && m_prelaunch->isReady())
- list << m_prelaunch->pid();
- return list;
-}
-
-/*!
Return the prelaunched process information
*/
@@ -164,15 +151,12 @@ void PrelaunchProcessBackendFactory::setPrelaunchEnabled(bool value)
if (m_prelaunchEnabled != value) {
m_prelaunchEnabled = value;
if (!m_prelaunchEnabled) {
- setIdleCpuRequest(false);
if (m_prelaunch) {
m_prelaunch->deleteLater();
m_prelaunch = NULL;
}
- } else {
- Q_ASSERT(m_prelaunch == NULL);
- startPrelaunchTimer();
}
+ updateState();
emit prelaunchEnabledChanged();
}
}
@@ -191,15 +175,12 @@ bool PrelaunchProcessBackendFactory::hasPrelaunchedProcess() const
void PrelaunchProcessBackendFactory::handleMemoryRestrictionChange()
{
if (m_memoryRestricted) {
- setIdleCpuRequest(false);
if (m_prelaunch) {
delete m_prelaunch; // This will kill the child process as well
m_prelaunch = NULL;
}
- } else {
- Q_ASSERT(m_prelaunch == NULL);
- startPrelaunchTimer();
}
+ updateState();
}
/*!
@@ -216,17 +197,20 @@ PrelaunchProcessBackend *PrelaunchProcessBackendFactory::prelaunchProcessBackend
void PrelaunchProcessBackendFactory::idleCpuAvailable()
{
- if (!m_prelaunch && !m_memoryRestricted && m_info) {
- setIdleCpuRequest(false); // Might delay this until the prelaunch is done....
-
+ // qDebug() << Q_FUNC_INFO;
+ if (m_prelaunchEnabled && !m_prelaunch && !m_memoryRestricted && m_info) {
+ // qDebug() << Q_FUNC_INFO << "...launching";
m_prelaunch = new PrelaunchProcessBackend(*m_info, this);
connect(m_prelaunch, SIGNAL(finished(int,QProcess::ExitStatus)),
SLOT(prelaunchFinished(int,QProcess::ExitStatus)));
connect(m_prelaunch, SIGNAL(error(QProcess::ProcessError)),
SLOT(prelaunchError(QProcess::ProcessError)));
+ connect(m_prelaunch, SIGNAL(stateChanged(QProcess::ProcessState)),
+ SLOT(updateState()));
m_prelaunch->prestart();
emit processPrelaunched();
}
+ updateState();
}
/*!
@@ -241,7 +225,7 @@ void PrelaunchProcessBackendFactory::prelaunchFinished(int exitCode, QProcess::E
m_prelaunch->deleteLater();
m_prelaunch = NULL;
}
- startPrelaunchTimer();
+ updateState();
}
/*!
@@ -259,21 +243,26 @@ void PrelaunchProcessBackendFactory::prelaunchError(QProcess::ProcessError err)
if (err == QProcess::FailedToStart) {
qWarning() << Q_FUNC_INFO << "disabling prelaunch because of process errors";
m_prelaunchEnabled = false;
-
- }
- else {
- // ### TODO: This isn't optimal
- startPrelaunchTimer();
}
+
+ updateState();
}
/*!
- Starts the prelaunch timer only if prelaunching is enabled.
+ Update our presented state, consisting of whether or not we need
+ idle CPU resources and how many internal processes we are running.
*/
-void PrelaunchProcessBackendFactory::startPrelaunchTimer()
+void PrelaunchProcessBackendFactory::updateState()
{
- if (m_prelaunchEnabled)
- setIdleCpuRequest(true);
+ Q_ASSERT(!m_prelaunch || m_prelaunchEnabled); // If prelaunch is not enabled, we must not have a prelaunch process
+ Q_ASSERT(!m_prelaunch || !m_memoryRestricted); // If memory is restricted, we must not have a prelaunch process
+
+ setIdleCpuRequest(!m_memoryRestricted && m_prelaunchEnabled && !m_prelaunch && m_info);
+
+ PidList list;
+ if (m_prelaunch && m_prelaunch->isReady())
+ list << m_prelaunch->pid();
+ setInternalProcesses(list);
}
/*!
@@ -295,10 +284,8 @@ void PrelaunchProcessBackendFactory::setProcessInfo(ProcessInfo *processInfo)
m_prelaunch->deleteLater();
m_prelaunch = NULL;
}
- startPrelaunchTimer();
- } else {
- setIdleCpuRequest(false);
}
+ updateState();
emit processInfoChanged();
}
}
diff --git a/src/core/prelaunchprocessbackendfactory.h b/src/core/prelaunchprocessbackendfactory.h
index 4a5c0b5..c2b9543 100644
--- a/src/core/prelaunchprocessbackendfactory.h
+++ b/src/core/prelaunchprocessbackendfactory.h
@@ -61,8 +61,6 @@ public:
virtual bool canCreate(const ProcessInfo &info) const;
virtual ProcessBackend *create(const ProcessInfo& info, QObject *parent);
- virtual QList<Q_PID> internalProcesses();
-
ProcessInfo *processInfo() const;
void setProcessInfo(ProcessInfo *processInfo);
void setProcessInfo(ProcessInfo& processInfo);
@@ -87,9 +85,7 @@ protected slots:
private slots:
void prelaunchFinished(int, QProcess::ExitStatus);
void prelaunchError(QProcess::ProcessError);
-
-private:
- void startPrelaunchTimer();
+ void updateState();
private:
PrelaunchProcessBackend *m_prelaunch;
diff --git a/src/core/processbackendfactory.cpp b/src/core/processbackendfactory.cpp
index 17be8d5..004a6dd 100644
--- a/src/core/processbackendfactory.cpp
+++ b/src/core/processbackendfactory.cpp
@@ -41,8 +41,6 @@
#include "matchdelegate.h"
#include "rewritedelegate.h"
-#include <QDebug>
-
QT_BEGIN_NAMESPACE_PROCESSMANAGER
/*!
@@ -53,6 +51,11 @@ QT_BEGIN_NAMESPACE_PROCESSMANAGER
*/
/*!
+ \property ProcessBackendFactory::internalProcesses
+ \brief A list of the internal processes.
+*/
+
+/*!
\property ProcessBackendFactory::matchDelegate
\brief A MatchDelegate object assigned to this factory.
*/
@@ -102,14 +105,25 @@ void ProcessBackendFactory::setMemoryRestricted(bool memoryRestricted)
}
/*!
- Override this is subclasses to return a list of internal
- processes that are contained in this factory. The default
- class returns an empty list.
+ Return a list of internal processes that are in use by this factory
*/
-QList<Q_PID> ProcessBackendFactory::internalProcesses()
+PidList ProcessBackendFactory::internalProcesses() const
{
- return QList<Q_PID>();
+ return m_internalProcesses;
+}
+
+/*!
+ Set the list of internal processes. This should be a sorted
+ list. The \a plist argument is a list of processes.
+ */
+
+void ProcessBackendFactory::setInternalProcesses(const PidList& plist)
+{
+ if (!compareSortedLists(plist, m_internalProcesses)) {
+ m_internalProcesses = plist;
+ emit internalProcessesChanged();
+ }
}
/*!
@@ -200,7 +214,6 @@ void ProcessBackendFactory::setIdleCpuRequest(bool value)
void ProcessBackendFactory::idleCpuAvailable()
{
- qDebug() << Q_FUNC_INFO;
}
/*!
@@ -237,6 +250,12 @@ void ProcessBackendFactory::rewrite(ProcessInfo& info)
}
/*!
+ \fn void ProcessBackendFactory::internalProcessesChanged()
+
+ Signal emitted whenever the list of internal processes has changed.
+*/
+
+/*!
\fn void ProcessBackendFactory::matchDelegateChanged()
Signal emitted whenever the MatchDelegate is changed.
diff --git a/src/core/processbackendfactory.h b/src/core/processbackendfactory.h
index ed17d61..0759f90 100644
--- a/src/core/processbackendfactory.h
+++ b/src/core/processbackendfactory.h
@@ -44,6 +44,7 @@
#include <QProcessEnvironment>
#include "processmanager-global.h"
+#include "processlist.h"
QT_BEGIN_NAMESPACE_PROCESSMANAGER
@@ -55,8 +56,9 @@ class RewriteDelegate;
class Q_ADDON_PROCESSMANAGER_EXPORT ProcessBackendFactory : public QObject
{
Q_OBJECT
- Q_PROPERTY(MatchDelegate* matchDelegate READ matchDelegate WRITE setMatchDelegate NOTIFY matchDelegateChanged);
- Q_PROPERTY(RewriteDelegate* rewriteDelegate READ rewriteDelegate WRITE setRewriteDelegate NOTIFY rewriteDelegateChanged);
+ Q_PROPERTY(PidList internalProcesses READ internalProcesses NOTIFY internalProcessesChanged)
+ Q_PROPERTY(MatchDelegate* matchDelegate READ matchDelegate WRITE setMatchDelegate NOTIFY matchDelegateChanged)
+ Q_PROPERTY(RewriteDelegate* rewriteDelegate READ rewriteDelegate WRITE setRewriteDelegate NOTIFY rewriteDelegateChanged)
Q_PROPERTY(bool idleCpuRequest READ idleCpuRequest NOTIFY idleCpuRequestChanged)
public:
@@ -66,8 +68,9 @@ public:
virtual void rewrite(ProcessInfo& info);
virtual ProcessBackend *create(const ProcessInfo& info, QObject *parent) = 0;
- void setMemoryRestricted(bool);
- virtual QList<Q_PID> internalProcesses();
+ void setMemoryRestricted(bool);
+
+ PidList internalProcesses() const;
MatchDelegate * matchDelegate() const;
void setMatchDelegate(MatchDelegate *);
@@ -79,15 +82,18 @@ public:
virtual void idleCpuAvailable();
signals:
+ void internalProcessesChanged();
void matchDelegateChanged();
void rewriteDelegateChanged();
void idleCpuRequestChanged();
protected:
+ void setIdleCpuRequest(bool);
+ virtual void setInternalProcesses(const PidList&);
virtual void handleMemoryRestrictionChange();
- virtual void setIdleCpuRequest(bool);
protected:
+ PidList m_internalProcesses;
MatchDelegate *m_matchDelegate;
RewriteDelegate *m_rewriteDelegate;
bool m_memoryRestricted;
diff --git a/src/core/processbackendmanager.cpp b/src/core/processbackendmanager.cpp
index 4a63f1a..2d338c4 100644
--- a/src/core/processbackendmanager.cpp
+++ b/src/core/processbackendmanager.cpp
@@ -37,6 +37,8 @@
**
****************************************************************************/
+#include <QDebug>
+
#include "processbackendmanager.h"
#include "processbackendfactory.h"
#include "processbackend.h"
@@ -165,6 +167,7 @@ void ProcessBackendManager::addFactory(ProcessBackendFactory *factory)
m_factories.append(factory);
factory->setParent(this);
factory->setMemoryRestricted(m_memoryRestricted);
+ connect(factory, SIGNAL(internalProcessesChanged()), SLOT(updateInternalProcesses()));
connect(factory, SIGNAL(idleCpuRequestChanged()), SLOT(updateIdleCpuRequest()));
updateIdleCpuRequest();
}
@@ -173,12 +176,9 @@ void ProcessBackendManager::addFactory(ProcessBackendFactory *factory)
Return a list of all internal processes being used by factories
*/
-QList<Q_PID> ProcessBackendManager::internalProcesses()
+PidList ProcessBackendManager::internalProcesses() const
{
- QList<Q_PID> plist;
- foreach (ProcessBackendFactory *factory, m_factories)
- plist.append(factory->internalProcesses());
- return plist;
+ return m_internalProcesses;
}
/*!
@@ -270,21 +270,50 @@ void ProcessBackendManager::updateIdleCpuRequest()
m_idleCpuRequest = request;
if (m_idleDelegate)
m_idleDelegate->requestIdleCpu(m_idleCpuRequest);
- handleIdleCpuRequest(m_idleCpuRequest);
+ handleIdleCpuRequest();
+ }
+}
+
+/*!
+ Update the list of internal processes
+ */
+
+void ProcessBackendManager::updateInternalProcesses()
+{
+ QList<Q_PID> plist;
+ foreach (ProcessBackendFactory *factory, m_factories)
+ plist.append(factory->internalProcesses());
+ qSort(plist);
+ if (!compareSortedLists(plist, m_internalProcesses)) {
+ m_internalProcesses = plist;
+ handleInternalProcessChange();
+ emit internalProcessesChanged();
}
}
/*!
Override this function to customize your handling of Idle CPU requests.
- The \a request variable will be \c{true} if Idle CPU events are needed.
*/
-void ProcessBackendManager::handleIdleCpuRequest(bool request)
+void ProcessBackendManager::handleIdleCpuRequest()
{
- Q_UNUSED(request);
}
/*!
+ Override this function to customize your handling of changes in the
+ list of internal processes.
+ */
+
+void ProcessBackendManager::handleInternalProcessChange()
+{
+}
+
+/*!
+ \fn void ProcessBackendManager::internalProcessesChanged()
+ Signal emitted whenever the list of internal processes has changed.
+*/
+
+/*!
\fn void ProcessBackendManager::idleDelegateChanged()
Signal emitted whenever the IdleDelegate is changed.
*/
diff --git a/src/core/processbackendmanager.h b/src/core/processbackendmanager.h
index c976cb3..bfb5597 100644
--- a/src/core/processbackendmanager.h
+++ b/src/core/processbackendmanager.h
@@ -45,6 +45,7 @@
#include <QProcessEnvironment>
#include "processmanager-global.h"
+#include "processlist.h"
QT_BEGIN_NAMESPACE_PROCESSMANAGER
@@ -65,7 +66,7 @@ public:
ProcessBackend *create(const ProcessInfo& info, QObject *parent=0);
void addFactory(ProcessBackendFactory *factory);
- QList<Q_PID> internalProcesses();
+ PidList internalProcesses() const;
void setMemoryRestricted(bool);
bool memoryRestricted() const;
@@ -75,19 +76,23 @@ public:
bool idleCpuRequest() const { return m_idleCpuRequest; }
protected:
- virtual void handleIdleCpuRequest(bool request);
+ virtual void handleIdleCpuRequest();
+ virtual void handleInternalProcessChange();
signals:
void idleDelegateChanged();
+ void internalProcessesChanged();
protected slots:
void idleCpuAvailable();
private slots:
void updateIdleCpuRequest();
+ void updateInternalProcesses();
private:
QList<ProcessBackendFactory*> m_factories;
+ PidList m_internalProcesses;
IdleDelegate *m_idleDelegate;
bool m_memoryRestricted;
bool m_idleCpuRequest;
diff --git a/src/core/processlist.h b/src/core/processlist.h
new file mode 100644
index 0000000..c96a618
--- /dev/null
+++ b/src/core/processlist.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PROCESS_LIST_H
+#define PROCESS_LIST_H
+
+#include <QList>
+#include <QProcess>
+#include <QJsonArray>
+
+#include "processmanager-global.h"
+
+QT_BEGIN_NAMESPACE_PROCESSMANAGER
+
+typedef QList<Q_PID> PidList;
+
+inline bool compareSortedLists(const PidList& a, const PidList& b)
+{
+ if (a.size() != b.size())
+ return false;
+ for (int i=0 ; i < a.size() ; i++)
+ if (a.at(i) != b.at(i))
+ return false;
+ return true;
+}
+
+inline QJsonArray pidListToArray(const PidList& plist)
+{
+ QJsonArray array;
+ foreach (Q_PID pid, plist)
+ array.append((double) pid);
+ return array;
+}
+
+inline PidList arrayToPidList(const QJsonArray& array)
+{
+ PidList plist;
+ for (int i = 0 ; i < array.size() ; i++)
+ plist.append((int) array.at(i).toDouble());
+ return plist;
+}
+
+QT_END_NAMESPACE_PROCESSMANAGER
+
+#endif // PROCESS_LIST_H
diff --git a/src/core/processmanager.cpp b/src/core/processmanager.cpp
index 9bee6aa..32eca25 100644
--- a/src/core/processmanager.cpp
+++ b/src/core/processmanager.cpp
@@ -193,7 +193,7 @@ QStringList ProcessManager::names() const
Return a list of all internal processes being used by factories
*/
-QList<Q_PID> ProcessManager::internalProcesses()
+PidList ProcessManager::internalProcesses() const
{
return m_backend->internalProcesses();
}
diff --git a/src/core/processmanager.h b/src/core/processmanager.h
index 57ef3af..70e8ef9 100644
--- a/src/core/processmanager.h
+++ b/src/core/processmanager.h
@@ -46,6 +46,7 @@
#include "processmanager-global.h"
#include "process.h"
+#include "processlist.h"
QT_BEGIN_NAMESPACE_PROCESSMANAGER
@@ -77,7 +78,7 @@ public:
Q_INVOKABLE int size() const;
Q_INVOKABLE void addBackendFactory(ProcessBackendFactory *factory);
- Q_INVOKABLE QList<Q_PID> internalProcesses();
+ Q_INVOKABLE PidList internalProcesses() const;
void setMemoryRestricted(bool);
bool memoryRestricted() const;
diff --git a/src/core/remoteprocessbackendfactory.cpp b/src/core/remoteprocessbackendfactory.cpp
index 012fc1d..67293ac 100644
--- a/src/core/remoteprocessbackendfactory.cpp
+++ b/src/core/remoteprocessbackendfactory.cpp
@@ -39,6 +39,7 @@
#include "remoteprocessbackendfactory.h"
#include "remoteprocessbackend.h"
+#include "remoteprotocol.h"
QT_BEGIN_NAMESPACE_PROCESSMANAGER
@@ -75,6 +76,9 @@ const int kRemoteTimerInterval = 1000;
\li \c{{ "command": "write", "id": NUM, "data": STRING }}
\li Write a data string to the remote process. We assume that the
data string is a valid local 8 bit string.
+ \row
+ \li \c{{ "command": "memory", "restricted": bool }}
+ \li Let the remote process know if memory use is restricted.
\endtable
The following are events that are sent by the remote process
@@ -138,15 +142,73 @@ ProcessBackend * RemoteProcessBackendFactory::create(const ProcessInfo& info, QO
}
/*!
+ Idle CPU is available. Send the message over the wire
+ */
+
+void RemoteProcessBackendFactory::idleCpuAvailable()
+{
+ QJsonObject object;
+ object.insert(RemoteProtocol::remote(), RemoteProtocol::idlecpuavailable());
+ send(object);
+}
+
+/*!
+ Tell the remote factory that memory is restricted and space should be freed up.
+ */
+
+void RemoteProcessBackendFactory::handleMemoryRestrictionChange()
+{
+ QJsonObject object;
+ object.insert(RemoteProtocol::remote(), RemoteProtocol::memory());
+ object.insert(RemoteProtocol::restricted(), m_memoryRestricted);
+ send(object);
+}
+
+/*!
+ Return a list of local internal processes. This is separate from the
+ remote internal process list, which comes from the remote host.
+ You should override this function is a subclass if your subclass is
+ holding a process object
+*/
+
+PidList RemoteProcessBackendFactory::localInternalProcesses() const
+{
+ return PidList();
+}
+
+/*!
+ Handle first connection to the remote process.
+ This function should be called by subclasses.
+ */
+
+void RemoteProcessBackendFactory::handleConnected()
+{
+ handleMemoryRestrictionChange(); // Sends command="memory" message
+}
+
+/*!
Receive a remote \a message and dispatch it to the correct recipient.
Call this function from your subclass to properly dispatch messages.
*/
void RemoteProcessBackendFactory::receive(const QJsonObject& message)
{
- int id = message.value(QLatin1String("id")).toDouble();
- if (m_backendMap.contains(id))
- m_backendMap.value(id)->receive(message);
+ // qDebug() << Q_FUNC_INFO << message;
+
+ QString remote = message.value(RemoteProtocol::remote()).toString();
+ if (remote == RemoteProtocol::idlecpurequested())
+ setIdleCpuRequest(message.value(RemoteProtocol::request()).toBool());
+ else if (remote == RemoteProtocol::internalprocesses()) {
+ PidList plist = localInternalProcesses() +
+ arrayToPidList(message.value(RemoteProtocol::processes()).toArray());
+ qSort(plist);
+ setInternalProcesses(plist);
+ }
+ else {
+ int id = message.value(QLatin1String("id")).toDouble();
+ if (m_backendMap.contains(id))
+ m_backendMap.value(id)->receive(message);
+ }
}
/*!
diff --git a/src/core/remoteprocessbackendfactory.h b/src/core/remoteprocessbackendfactory.h
index ac2dac4..86417b6 100644
--- a/src/core/remoteprocessbackendfactory.h
+++ b/src/core/remoteprocessbackendfactory.h
@@ -56,10 +56,16 @@ public:
virtual ~RemoteProcessBackendFactory();
virtual ProcessBackend *create(const ProcessInfo& info, QObject *parent);
+ virtual void idleCpuAvailable();
+
+protected slots:
+ void handleConnected();
+ void receive(const QJsonObject&);
protected:
- virtual bool send(const QJsonObject&) = 0;
- Q_INVOKABLE void receive(const QJsonObject&);
+ virtual void handleMemoryRestrictionChange();
+ virtual PidList localInternalProcesses() const;
+ virtual bool send(const QJsonObject&) = 0;
private:
void backendDestroyed(int);
diff --git a/src/core/remoteprotocol.h b/src/core/remoteprotocol.h
index 99f7131..f2b86cf 100644
--- a/src/core/remoteprotocol.h
+++ b/src/core/remoteprotocol.h
@@ -56,14 +56,22 @@ public:
static inline const QString exitCode() { return QStringLiteral("exitCode"); }
static inline const QString exitStatus() { return QStringLiteral("exitStatus"); }
static inline const QString finished() { return QStringLiteral("finished"); }
+ static inline const QString halt() { return QStringLiteral("halt"); }
static inline const QString id() { return QStringLiteral("id"); }
+ static inline const QString idlecpurequested() { return QStringLiteral("idlecpurequested"); }
+ static inline const QString idlecpuavailable() { return QStringLiteral("idlecpuavailable"); }
static inline const QString info() { return QStringLiteral("info"); }
+ static inline const QString internalprocesses() { return QStringLiteral("internalprocesses"); }
static inline const QString key() { return QStringLiteral("key"); }
+ static inline const QString memory() { return QStringLiteral("memory"); }
static inline const QString oomAdjustment() { return QStringLiteral("oomAdjustment"); }
static inline const QString output() { return QStringLiteral("output"); }
static inline const QString pid() { return QStringLiteral("pid"); }
static inline const QString priority() { return QStringLiteral("priority"); }
+ static inline const QString processes() { return QStringLiteral("processes"); }
static inline const QString remote() { return QStringLiteral("remote"); }
+ static inline const QString restricted() { return QStringLiteral("restricted"); }
+ static inline const QString request() { return QStringLiteral("request"); }
static inline const QString set() { return QStringLiteral("set"); }
static inline const QString signal() { return QStringLiteral("signal"); }
static inline const QString start() { return QStringLiteral("start"); }
diff --git a/src/core/socketlauncher.cpp b/src/core/socketlauncher.cpp
index 909dc5f..dd7be2d 100644
--- a/src/core/socketlauncher.cpp
+++ b/src/core/socketlauncher.cpp
@@ -37,10 +37,12 @@
**
****************************************************************************/
+#include <QDebug>
#include <signal.h>
#include "socketlauncher.h"
#include "launcherclient.h"
+#include "remoteprotocol.h"
QT_BEGIN_NAMESPACE_PROCESSMANAGER
@@ -69,6 +71,8 @@ SocketLauncher::SocketLauncher(QObject *parent)
SLOT(connectionAdded(const QString&)));
connect(m_server, SIGNAL(connectionRemoved(const QString&)),
SLOT(connectionRemoved(const QString&)));
+
+ setIdleDelegate(0); // Clear the idle delegate and get this from the master
}
/*!
@@ -109,6 +113,19 @@ void SocketLauncher::connectionAdded(const QString& identifier)
connect(client, SIGNAL(send(const QJsonObject&)), SLOT(send(const QJsonObject&)));
m_idToClient.insert(identifier, client);
m_clientToId.insert(client, identifier);
+
+ // Send our current idle request and internal process list
+ if (!idleDelegate()) {
+ QJsonObject object;
+ object.insert(RemoteProtocol::remote(), RemoteProtocol::idlecpurequested());
+ object.insert(RemoteProtocol::request(), idleCpuRequest());
+ sendToClient(object, client);
+ }
+
+ QJsonObject object;
+ object.insert(RemoteProtocol::remote(), RemoteProtocol::internalprocesses());
+ object.insert(RemoteProtocol::processes(), pidListToArray(internalProcesses()));
+ sendToClient(object, client);
}
/*!
@@ -124,26 +141,85 @@ void SocketLauncher::connectionRemoved(const QString& identifier)
}
/*!
+ \internal
+
+ We override this function to send our idle cpu request back to the
+ originator. This is a little odd, in that we send the idle cpu
+ request back to all connected clients. Hopefully only one will
+ respond.
+
+ We only send the idlecpurequest message if we don't have an idle delegate
+ */
+
+void SocketLauncher::handleIdleCpuRequest()
+{
+ if (!idleDelegate()) {
+ QJsonObject object;
+ object.insert(RemoteProtocol::remote(), RemoteProtocol::idlecpurequested());
+ object.insert(RemoteProtocol::request(), idleCpuRequest());
+ m_server->broadcast(object);
+ }
+}
+
+/*!
+ \internal
+
+ We override this function to send our updated list of internal
+ processes to all clients
+*/
+
+void SocketLauncher::handleInternalProcessChange()
+{
+ QJsonObject object;
+ object.insert(RemoteProtocol::remote(), RemoteProtocol::internalprocesses());
+ object.insert(RemoteProtocol::processes(), pidListToArray(internalProcesses()));
+ m_server->broadcast(object);
+}
+
+/*!
\internal
*/
+
void SocketLauncher::messageReceived(const QString& identifier, const QJsonObject& message)
{
- LauncherClient *client = m_idToClient.value(identifier);
- if (client)
- client->receive(message);
+ QString remote = message.value(RemoteProtocol::remote()).toString();
+ if (remote == RemoteProtocol::halt())
+ qDebug() << Q_FUNC_INFO << "Received halt request; ignoring";
+ else if ( remote == RemoteProtocol::memory() )
+ setMemoryRestricted(message.value(RemoteProtocol::restricted()).toBool());
+ else if ( remote == RemoteProtocol::idlecpuavailable() ) {
+ if (!idleDelegate())
+ idleCpuAvailable();
+ }
+ else {
+ LauncherClient *client = m_idToClient.value(identifier);
+ if (client)
+ client->receive(message);
+ }
}
/*!
\internal
+
+ This function should only be called from a signal raised in LauncherClient
*/
void SocketLauncher::send(const QJsonObject& message)
{
- LauncherClient *client = qobject_cast<LauncherClient *>(sender());
+ sendToClient(message, qobject_cast<LauncherClient *>(sender()));
+}
+
+/*!
+ \internal
+ */
+
+void SocketLauncher::sendToClient(const QJsonObject& message, LauncherClient *client)
+{
Q_ASSERT(client);
Q_ASSERT(m_server);
m_server->send(m_clientToId.value(client), message);
}
+
#include "moc_socketlauncher.cpp"
QT_END_NAMESPACE_PROCESSMANAGER
diff --git a/src/core/socketlauncher.h b/src/core/socketlauncher.h
index ded68cb..004ba77 100644
--- a/src/core/socketlauncher.h
+++ b/src/core/socketlauncher.h
@@ -61,6 +61,10 @@ public:
QtAddOn::JsonStream::JsonServer * server() const;
+protected:
+ virtual void handleIdleCpuRequest();
+ virtual void handleInternalProcessChange();
+
private slots:
void connectionAdded(const QString& identifier);
void connectionRemoved(const QString& identifier);
@@ -68,6 +72,9 @@ private slots:
void send(const QJsonObject& message);
private:
+ void sendToClient(const QJsonObject& message, LauncherClient *client);
+
+private:
QtAddOn::JsonStream::JsonServer *m_server;
QMap<QString, LauncherClient*> m_idToClient;
QMap<LauncherClient*, QString> m_clientToId;
diff --git a/src/core/socketprocessbackendfactory.cpp b/src/core/socketprocessbackendfactory.cpp
index a2f2de2..d30e7fc 100644
--- a/src/core/socketprocessbackendfactory.cpp
+++ b/src/core/socketprocessbackendfactory.cpp
@@ -67,6 +67,7 @@ SocketProcessBackendFactory::SocketProcessBackendFactory(QObject *parent)
: RemoteProcessBackendFactory(parent)
{
m_socket = new QLocalSocket(this);
+ connect(m_socket, SIGNAL(connected()), SLOT(connected()));
connect(m_socket, SIGNAL(disconnected()), SLOT(disconnected()));
connect(m_socket, SIGNAL(readyRead()), SLOT(readyRead()));
}
@@ -134,6 +135,15 @@ void SocketProcessBackendFactory::readyRead()
\internal
*/
+void SocketProcessBackendFactory::connected()
+{
+ handleConnected();
+}
+
+/*!
+ \internal
+ */
+
void SocketProcessBackendFactory::disconnected()
{
qWarning("Launcher process socket disconnected");
diff --git a/src/core/socketprocessbackendfactory.h b/src/core/socketprocessbackendfactory.h
index e7b3902..b305716 100644
--- a/src/core/socketprocessbackendfactory.h
+++ b/src/core/socketprocessbackendfactory.h
@@ -67,6 +67,7 @@ protected:
private slots:
void readyRead();
+ void connected();
void disconnected();
private: