diff options
author | Andrew Christian <andrew.christian@nokia.com> | 2012-02-02 09:33:38 -0500 |
---|---|---|
committer | Chris Craig <ext-chris.craig@nokia.com> | 2012-02-02 22:54:36 +0100 |
commit | c103fef8e03c91679778d731d70b058674c6c737 (patch) | |
tree | 89e27f30986824dafe8132d7afc9373c39533d73 | |
parent | 3621dfe4098bb550a91517e641deecaeb08c780f (diff) |
Updated oom adjustment. Fixed test cases to work on Linux and MacOS
Change-Id: I71d2544bc883fed759dab5e33d041bf66f1369da
Reviewed-by: Chris Craig <ext-chris.craig@nokia.com>
-rw-r--r-- | src/core/core-lib.pri | 11 | ||||
-rw-r--r-- | src/core/procutils.cpp | 52 | ||||
-rw-r--r-- | src/core/procutils.h | 3 | ||||
-rw-r--r-- | src/core/remoteprocessbackend.cpp | 7 | ||||
-rw-r--r-- | src/core/unixprocessbackend.cpp | 19 | ||||
-rw-r--r-- | src/launcher/pipelauncher.cpp | 2 | ||||
-rw-r--r-- | tests/auto/processmanager/tst_processmanager.cpp | 85 |
7 files changed, 159 insertions, 20 deletions
diff --git a/src/core/core-lib.pri b/src/core/core-lib.pri index 361c8c8..e6540f4 100644 --- a/src/core/core-lib.pri +++ b/src/core/core-lib.pri @@ -20,12 +20,8 @@ PUBLIC_HEADERS += \ $$PWD/standardprocessbackend.h \ $$PWD/prelaunchprocessbackend.h \ $$PWD/remoteprocessbackend.h \ - $$PWD/processmanager-global.h - -*linux* { - PUBLIC_HEADERS += $$PWD/procutils.h - SOURCES += $$PWD/procutils.cpp -} + $$PWD/processmanager-global.h \ + $$PWD/procutils.h HEADERS += \ $$PUBLIC_HEADERS \ @@ -49,4 +45,5 @@ SOURCES += \ $$PWD/remoteprocessbackend.cpp \ $$PWD/remoteprocessbackendfactory.cpp \ $$PWD/pipeprocessbackendfactory.cpp \ - $$PWD/socketprocessbackendfactory.cpp + $$PWD/socketprocessbackendfactory.cpp \ + $$PWD/procutils.cpp diff --git a/src/core/procutils.cpp b/src/core/procutils.cpp index f6965b3..484d57f 100644 --- a/src/core/procutils.cpp +++ b/src/core/procutils.cpp @@ -58,22 +58,23 @@ ProcUtils::ProcUtils() QString ProcUtils::execNameForPid(qint64 pid) { +#if defined(Q_OS_LINUX) enum { BUFFERSIZE = 1024 }; char buf[BUFFERSIZE]; QString fn = QLatin1String("/proc/") + QString::number(pid).toLatin1() + QLatin1String("/exe"); ssize_t len = readlink(fn.toLatin1(), buf, sizeof(buf) - 1); - if (len != -1) { buf[len] = '\0'; - } else { - return QString(); + return QString(buf); } - - return QString(buf); +#endif + return QString(); } qint64 ProcUtils::ppidForPid(pid_t pid) { + int ppid = 0; +#if defined(Q_OS_LINUX) QFile statFile(QLatin1String("/proc/") + QString::number(pid) + "/stat"); statFile.open(QIODevice::ReadOnly); @@ -81,15 +82,16 @@ qint64 ProcUtils::ppidForPid(pid_t pid) statFile.close(); // 954 (ofono-jdb-daemo) S 1 int readPid = 0; - int ppid = 0; char strDummy[64]; char state; sscanf(contents.constData(), "%d %s %c %d %s", &readPid, strDummy, &state, &ppid, strDummy); +#endif return ppid; } qint64 ProcUtils::pidForFilename(const QString &filename) { +#if defined(Q_OS_LINUX) QFile file(filename); if (!file.exists()) return 0; @@ -112,31 +114,65 @@ qint64 ProcUtils::pidForFilename(const QString &filename) } } closedir(d); +#endif return 0; } qint64 ProcUtils::pidForLocalSocket(const QLocalSocket *socket) { +#if defined(Q_OS_LINUX) if (socket) { struct ucred cr; socklen_t len = sizeof(struct ucred); int r = ::getsockopt(socket->socketDescriptor(), SOL_SOCKET, SO_PEERCRED, &cr, &len); - if (r == 0) { + if (r == 0) return (qint64)cr.pid; - } } +#endif return 0; } QByteArray ProcUtils::cmdlineForPid(qint64 pid) { QByteArray cmdline; +#if defined(Q_OS_LINUX) if (pid) { QFile file(QLatin1String("/proc/") + QString::number(pid) + QLatin1String("/cmdline")); file.open(QIODevice::ReadOnly); cmdline = file.readAll(); } return cmdline; +#endif } +qint32 ProcUtils::oomAdjustment(pid_t pid, bool *ok) +{ + if (ok) + *ok = false; +#if defined(Q_OS_LINUX) + QFile file(QString::fromLatin1("/proc/%1/oom_score_adj").arg(pid)); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QByteArray ba = file.read(100); + ba.truncate(ba.count() - 1); // Drop the '\n' at the end + if (ba.count()) + return ba.toInt(ok); + } +#endif + return -1001; +} + +bool ProcUtils::setOomAdjustment(pid_t pid, qint32 oomAdjustment) +{ +#if defined(Q_OS_LINUX) + QFile file(QString::fromLatin1("/proc/%1/oom_score_adj").arg(pid)); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) + return false; + QByteArray value = QByteArray::number(oomAdjustment) + '\n'; + if (file.write(value) == value.count()) + return true; +#endif + return false; +} + + QT_END_NAMESPACE_PROCESSMANAGER diff --git a/src/core/procutils.h b/src/core/procutils.h index 4fe5d6f..f40fea4 100644 --- a/src/core/procutils.h +++ b/src/core/procutils.h @@ -58,6 +58,9 @@ public: static qint64 pidForFilename(const QString &filename); static qint64 pidForLocalSocket(const QLocalSocket *socket); static QByteArray cmdlineForPid(qint64 pid); + + static qint32 oomAdjustment(pid_t pid, bool *ok=NULL); + static bool setOomAdjustment(pid_t pid, qint32 oomAdjustment); }; QT_END_NAMESPACE_PROCESSMANAGER diff --git a/src/core/remoteprocessbackend.cpp b/src/core/remoteprocessbackend.cpp index b7a79f7..6ea130b 100644 --- a/src/core/remoteprocessbackend.cpp +++ b/src/core/remoteprocessbackend.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "remoteprocessbackend.h" +#include "procutils.h" #include <sys/resource.h> #include <errno.h> #include <signal.h> @@ -141,7 +142,11 @@ void RemoteProcessBackend::setDesiredPriority(qint32 priority) qint32 RemoteProcessBackend::actualOomAdjustment() const { if (m_pid != -1) { - // ### TODO: Read correctly from /proc/<pid>/oom_score_adj + bool ok; + qint32 result = ProcUtils::oomAdjustment(m_pid, &ok); + if (ok) + return result; + qWarning() << "Unable to read oom adjustment for" << m_pid; } return ProcessBackend::actualOomAdjustment(); } diff --git a/src/core/unixprocessbackend.cpp b/src/core/unixprocessbackend.cpp index de7a9c5..b019ebc 100644 --- a/src/core/unixprocessbackend.cpp +++ b/src/core/unixprocessbackend.cpp @@ -41,9 +41,11 @@ #include "unixprocessbackend.h" #include "unixsandboxprocess.h" +#include "procutils.h" #include <sys/resource.h> #include <errno.h> #include <QDebug> +#include <QFile> QT_BEGIN_NAMESPACE_PROCESSMANAGER @@ -119,8 +121,14 @@ void UnixProcessBackend::setDesiredPriority(qint32 priority) qint32 UnixProcessBackend::actualOomAdjustment() const { + // ### TODO: What if m_process doesn't have a valid PID yet? + if (m_process) { - // ### TODO: Read correctly from /proc/<pid>/oom_score_adj + bool ok; + qint32 result = ProcUtils::oomAdjustment(m_process->pid(), &ok); + if (ok) + return result; + qWarning() << "Unable to read oom adjustment for" << m_process->pid(); } return ProcessBackend::actualOomAdjustment(); } @@ -133,7 +141,8 @@ void UnixProcessBackend::setDesiredOomAdjustment(qint32 oomAdjustment) { ProcessBackend::setDesiredOomAdjustment(oomAdjustment); if (m_process) { - // ### Write to /proc/<pid>/oom_score_adj + if (!ProcUtils::setOomAdjustment(m_process->pid(), oomAdjustment)) + qWarning() << "Unable to set oom adjustment for" << m_process->pid(); } } @@ -240,7 +249,11 @@ void UnixProcessBackend::handleProcessStarted() { if (m_info.contains("priority") && setpriority(PRIO_PROCESS, m_process->pid(), m_info.priority())) qWarning() << "Failed to set process priority at startup from " << actualPriority() << - "to" << m_info.priority() << " : errno = " << errno; + "to" << m_info.priority() << " : errno = " << errno; + if (m_info.contains("oomAdjustment") && + !ProcUtils::setOomAdjustment(m_process->pid(), m_info.oomAdjustment())) + qWarning() << "Failed to set process oom score at startup from " << actualOomAdjustment() << + "to" << m_info.oomAdjustment(); } /*! Override this in subclasses. Make sure you call the parent class with \a error. diff --git a/src/launcher/pipelauncher.cpp b/src/launcher/pipelauncher.cpp index 45dec45..d3bcf6e 100644 --- a/src/launcher/pipelauncher.cpp +++ b/src/launcher/pipelauncher.cpp @@ -98,7 +98,7 @@ void PipeLauncher::inReady(int fd) m_inbuf = m_inbuf.mid(message_size); QJsonObject message = QJsonDocument::fromBinaryData(msg).object(); if (message.value("remote").toString() == "stop") - deleteLater(); + exit(0); m_client->receive(message); } m_in->setEnabled(true); diff --git a/tests/auto/processmanager/tst_processmanager.cpp b/tests/auto/processmanager/tst_processmanager.cpp index 788c143..043f48b 100644 --- a/tests/auto/processmanager/tst_processmanager.cpp +++ b/tests/auto/processmanager/tst_processmanager.cpp @@ -490,6 +490,71 @@ static void priorityChangeAfterClient(ProcessBackendManager *manager, ProcessInf delete process; } +#if defined(Q_OS_LINUX) + +static void waitForOom(ProcessBackend *process, int oom, int timeout=5000) +{ + QTime stopWatch; + stopWatch.start(); + forever { + if (process->actualOomAdjustment() == oom) + break; + QTestEventLoop::instance().enterLoop(1); + if (stopWatch.elapsed() >= timeout) + QFAIL("Timed out"); + } +} + +static void oomChangeBeforeClient(ProcessBackendManager *manager, ProcessInfo info, CommandFunc func) +{ + info.setOomAdjustment(500); + ProcessBackend *process = manager->create(info); + QVERIFY(process); + + Spy spy(process); + process->start(); + spy.waitStart(); + QVERIFY(process->state() == QProcess::Running); + QCOMPARE(process->actualOomAdjustment(), 500); + + func(process, "stop"); + spy.waitFinished(); + spy.check(1,0,1,3); + spy.checkExitCode(0); + spy.checkExitStatus(QProcess::NormalExit); + + QVERIFY(process->state() == QProcess::NotRunning); + QVERIFY(process->parent() == NULL); + delete process; +} + +static void oomChangeAfterClient(ProcessBackendManager *manager, ProcessInfo info, CommandFunc func) +{ + ProcessBackend *process = manager->create(info); + QVERIFY(process); + QVERIFY(process->state() == QProcess::NotRunning); + + Spy spy(process); + process->start(); + spy.waitStart(); + QVERIFY(process->state() == QProcess::Running); + + process->setDesiredOomAdjustment(499); + waitForOom(process, 499); + + func(process, "stop"); + spy.waitFinished(); + spy.check(1,0,1,3); + spy.checkExitCode(0); + spy.checkExitStatus(QProcess::NormalExit); + + QVERIFY(process->state() == QProcess::NotRunning); + QVERIFY(process->parent() == NULL); + delete process; +} + +#endif // defined(Q_OS_LINUX) + typedef void (*clientFunc)(ProcessBackendManager *, ProcessInfo, CommandFunc); @@ -597,6 +662,10 @@ private slots: void standardEcho() { standardFactoryTest(echoClient); } void standardPriorityChangeBefore() { standardFactoryTest(priorityChangeBeforeClient); } void standardPriorityChangeAfter() { standardFactoryTest(priorityChangeAfterClient); } +#if defined(Q_OS_LINUX) + void standardOomChangeBefore() { standardFactoryTest(oomChangeBeforeClient); } + void standardOomChangeAfter() { standardFactoryTest(oomChangeAfterClient); } +#endif void prelaunchStartAndStop() { prelaunchFactoryTest(startAndStopClient); } void prelaunchStartAndKill() { prelaunchFactoryTest(startAndKillClient); } @@ -604,6 +673,10 @@ private slots: void prelaunchEcho() { prelaunchFactoryTest(echoClient); } void prelaunchPriorityChangeBefore() { prelaunchFactoryTest(priorityChangeBeforeClient); } void prelaunchPriorityChangeAfter() { prelaunchFactoryTest(priorityChangeAfterClient); } +#if defined(Q_OS_LINUX) + void prelaunchOomChangeBefore() { prelaunchFactoryTest(oomChangeBeforeClient); } + void prelaunchOomChangeAfter() { prelaunchFactoryTest(oomChangeAfterClient); } +#endif void prelaunchRestrictedStartAndStop() { prelaunchRestrictedTest(startAndStopClient); } void prelaunchRestrictedStartAndKill() { prelaunchRestrictedTest(startAndKillClient); } @@ -611,6 +684,10 @@ private slots: void prelaunchRestrictedEcho() { prelaunchRestrictedTest(echoClient); } void prelaunchRestrictedPriorityChangeBefore() { prelaunchRestrictedTest(priorityChangeBeforeClient); } void prelaunchRestrictedPriorityChangeAfter() { prelaunchRestrictedTest(priorityChangeAfterClient); } +#if defined(Q_OS_LINUX) + void prelaunchRestrictedOomChangeBefore() { prelaunchRestrictedTest(oomChangeBeforeClient); } + void prelaunchRestrictedOomChangeAfter() { prelaunchRestrictedTest(oomChangeAfterClient); } +#endif void pipeLauncherStartAndStop() { pipeLauncherTest(startAndStopClient); } void pipeLauncherStartAndKill() { pipeLauncherTest(startAndKillClient); } @@ -618,6 +695,10 @@ private slots: void pipeLauncherEcho() { pipeLauncherTest(echoClient); } void pipeLauncherPriorityChangeBefore() { pipeLauncherTest(priorityChangeBeforeClient); } void pipeLauncherPriorityChangeAfter() { pipeLauncherTest(priorityChangeAfterClient); } +#if defined(Q_OS_LINUX) + void pipeLauncherOomChangeBefore() { pipeLauncherTest(oomChangeBeforeClient); } + void pipeLauncherOomChangeAfter() { pipeLauncherTest(oomChangeAfterClient); } +#endif void socketLauncherStartAndStop() { socketLauncherTest(startAndStopClient); } void socketLauncherStartAndKill() { socketLauncherTest(startAndKillClient); } @@ -625,6 +706,10 @@ private slots: void socketLauncherEcho() { socketLauncherTest(echoClient); } void socketLauncherPriorityChangeBefore() { socketLauncherTest(priorityChangeBeforeClient); } void socketLauncherPriorityChangeAfter() { socketLauncherTest(priorityChangeAfterClient); } +#if defined(Q_OS_LINUX) + void socketLauncherOomChangeBefore() { socketLauncherTest(oomChangeBeforeClient); } + void socketLauncherOomChangeAfter() { socketLauncherTest(oomChangeAfterClient); } +#endif void frontend(); void subclassFrontend(); |