From 5dd2bde59a18dea49b80afb0c2e6cf4827d79def Mon Sep 17 00:00:00 2001 From: Andrew Christian Date: Thu, 1 Mar 2012 16:25:51 +0100 Subject: Added prefork library and factory * Prefork library parses command line arguments and creates appropriate master and child processes connected by pipes. * PreforkProcessBackendFactory retrieves information about child processes from prefork library and exposes those children as remote process manager objects. * Linux test case added to start a master and child object using prefork library and run all standard tests. Change-Id: Ic76da3eb8237744dd075f55db80f46f35550c73f Reviewed-by: Chris Craig --- src/core/core-lib.pri | 8 +- src/core/core.pro | 3 + src/core/prefork.cpp | 243 +++++++++++++++++++++ src/core/prefork.h | 79 +++++++ src/core/preforkprocessbackendfactory.cpp | 208 ++++++++++++++++++ src/core/preforkprocessbackendfactory.h | 83 +++++++ tests/auto/processmanager/processmanager.pro | 10 +- .../auto/processmanager/testForkLauncher/main.cpp | 2 +- .../testForkLauncher/testForkLauncher.pro | 4 + .../processmanager/testPrefork/testPrefork.cpp | 51 +++++ .../processmanager/testPrefork/testPrefork.pro | 12 + .../processmanager/testPreforkLauncher/main.cpp | 67 ++++++ .../testPreforkLauncher/testPreforkLauncher.pro | 16 ++ tests/auto/processmanager/tst_processmanager.cpp | 47 ++++ 14 files changed, 829 insertions(+), 4 deletions(-) create mode 100644 src/core/prefork.cpp create mode 100644 src/core/prefork.h create mode 100644 src/core/preforkprocessbackendfactory.cpp create mode 100644 src/core/preforkprocessbackendfactory.h create mode 100644 tests/auto/processmanager/testPrefork/testPrefork.cpp create mode 100644 tests/auto/processmanager/testPrefork/testPrefork.pro create mode 100644 tests/auto/processmanager/testPreforkLauncher/main.cpp create mode 100644 tests/auto/processmanager/testPreforkLauncher/testPreforkLauncher.pro diff --git a/src/core/core-lib.pri b/src/core/core-lib.pri index 7378e08..42e7f69 100644 --- a/src/core/core-lib.pri +++ b/src/core/core-lib.pri @@ -21,6 +21,7 @@ PUBLIC_HEADERS += \ $$PWD/remoteprocessbackendfactory.h \ $$PWD/pipeprocessbackendfactory.h \ $$PWD/socketprocessbackendfactory.h \ + $$PWD/preforkprocessbackendfactory.h \ $$PWD/unixprocessbackend.h \ $$PWD/standardprocessbackend.h \ $$PWD/prelaunchprocessbackend.h \ @@ -31,7 +32,8 @@ PUBLIC_HEADERS += \ $$PWD/socketlauncher.h \ $$PWD/procutils.h \ $$PWD/remoteprotocol.h \ - $$PWD/forklauncher.h + $$PWD/forklauncher.h \ + $$PWD/prefork.h HEADERS += \ $$PUBLIC_HEADERS \ @@ -60,8 +62,10 @@ SOURCES += \ $$PWD/remoteprocessbackendfactory.cpp \ $$PWD/pipeprocessbackendfactory.cpp \ $$PWD/socketprocessbackendfactory.cpp \ + $$PWD/preforkprocessbackendfactory.cpp \ $$PWD/launcherclient.cpp \ $$PWD/pipelauncher.cpp \ $$PWD/socketlauncher.cpp \ $$PWD/procutils.cpp \ - $$PWD/forklauncher.cpp + $$PWD/forklauncher.cpp \ + $$PWD/prefork.cpp diff --git a/src/core/core.pro b/src/core/core.pro index 7072f12..5c54a29 100644 --- a/src/core/core.pro +++ b/src/core/core.pro @@ -12,6 +12,9 @@ DEFINES += QT_ADDON_PROCESSMANAGER_LIB CONFIG += module create_prl MODULE_PRI = ../../modules/qt_processmanager.pri +QMAKE_CXXFLAGS += -fPIC -fvisibility=hidden -fvisibility-inlines-hidden +LIBS += -ldl + include($$PWD/core-lib.pri) mac:QMAKE_FRAMEWORK_BUNDLE_NAME = $$QT.processmanager.name diff --git a/src/core/prefork.cpp b/src/core/prefork.cpp new file mode 100644 index 0000000..4c16659 --- /dev/null +++ b/src/core/prefork.cpp @@ -0,0 +1,243 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#include "prefork.h" + +#include +#include +#include +#include +#include +#include +#include + +#if defined(Q_OS_LINUX) +#include +#endif + +#include +#include +#include + + +QT_BEGIN_NAMESPACE_PROCESSMANAGER + +static struct sigaction old_child_handler; + +static void prefork_child_handler(int sig, siginfo_t* info, void *) +{ + if (sig == SIGCHLD) + Prefork::instance()->checkChildDied(info->si_pid); + + // Complicated way of calling the old child handler + void (*oldAction)(int) = ((volatile struct sigaction *)&old_child_handler)->sa_handler; + if (oldAction && oldAction != SIG_IGN) + oldAction(sig); +} + +static void makePipe(int fd[]) +{ + if (::pipe(fd) == -1) + qFatal("Unable to create pipe: %s", strerror(errno)); + if (::fcntl(fd[0], F_SETFL, O_NONBLOCK) == -1) // Set non-block on read end + qFatal("Unable to set nonblocking: %s", strerror(errno)); +} + +/**************************************************************************/ + +Prefork *Prefork::instance() { + static Prefork *s_forkit; + if (!s_forkit) + s_forkit = new Prefork; + return s_forkit; +} + +Prefork::Prefork() + : m_argc(0) + , m_argv(NULL) + , m_argv_size(0) + , m_count(0) + , m_children(NULL) +{ +} + +int Prefork::nextMarker(int index) +{ + while (index < m_argc && ::strcmp(m_argv[index], "--") != 0) + ++index; + return index; +} + +/*! + Open the application as a dll and jump to main + This function never returns. + */ + +typedef int (*main_func_t)(int argc, char *argv[]); + +// ### TODO: Remove the directory path from the program name + +void Prefork::launch(int start, int end) +{ + // Move over the old arguments to the front of the m_argv array + size_t bytes_to_skip = m_argv[start] - m_argv[0]; + size_t bytes_to_move = (m_argv[end-1] + ::strlen(m_argv[end-1])) - m_argv[start]; + + memmove(m_argv[0], m_argv[start], bytes_to_move); + memset(m_argv[0] + bytes_to_move, 0, m_argv_size - bytes_to_move); + + // Shift all of the pointers + for (int i = start ; i < end ; i++) + m_argv[i-start] = m_argv[i] - bytes_to_skip; + + void *lib = dlopen(m_argv[0], RTLD_LAZY); + if (!lib) + qFatal("Unable to open: %s", dlerror()); + void *symbol = dlsym(lib, "main"); + if (!symbol) + qFatal("No main routine in %s", m_argv[0]); + + qDebug() << "Running" << m_argv[0] << "as process" << getpid(); + int result = ((main_func_t)symbol)(end-start, m_argv); + ::exit(result); +} + +/*! + Starting at \a start, look for an end and create + a child. Return the index of the next starting point + */ + +int Prefork::makeChild(int start) +{ + int end = nextMarker(start); + if (start < end) { + int fd1[2]; // Stdin of the child + int fd2[2]; // Stdout of the child + makePipe(fd1); + makePipe(fd2); + int pid = ::fork(); + if (pid < 0) + qFatal("Failed to fork: %s", strerror(errno)); + if (pid == 0) { // Child + ::dup2(fd1[0], STDIN_FILENO); + ::dup2(fd2[1], STDOUT_FILENO); + ::close(fd1[0]); + ::close(fd1[1]); + ::close(fd2[0]); + ::close(fd2[1]); +#if defined(Q_OS_LINUX) + ::prctl(PR_SET_PDEATHSIG, SIGHUP); // Ask to be killed when parent dies +#endif + launch(start, end); // This function never returns + } + else { + // Parent + m_children[m_count].stdin = fd1[1]; // Stdin of the child (write to this) + m_children[m_count].stdout = fd2[0]; // Stdout of the child (read from this) + m_children[m_count].pid = pid; + m_count++; + ::close(fd1[0]); + ::close(fd2[1]); + } + } + return end + 1; +} + +void Prefork::execute(int *argc_ptr, char ***argv_ptr) +{ + m_argc = *argc_ptr; + m_argv = *argv_ptr; + m_argv_size = (m_argv[m_argc-1] + ::strlen(m_argv[m_argc-1])) - m_argv[0]; + + int marker_count = 0; + for (int i = 0 ; i < m_argc ; i++) + if (!::strcmp(m_argv[i], "--") == 0) + marker_count++; + + if (marker_count < 2) + qFatal("Expected to see at least two '--' markers"); + // This is excessive paranoia - I worry about a QList access in a signal handler + int count = marker_count - 1; + m_children = (PreforkChildData *) ::calloc(sizeof(PreforkChildData), count); + if (!m_children) + qFatal("Memory error"); + + int start = nextMarker(0) + 1; + int end = nextMarker(start); + if (start >= end) + qFatal("no defined main application"); + int index = end + 1; + if (index >= m_argc) + qFatal("no defined child application"); + while ((index = makeChild(index)) < m_argc) + ; + + // Set up a signal handler - we kill everyone if something goes wrong + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_sigaction = prefork_child_handler; + action.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; + ::sigaction(SIGCHLD, &action, &old_child_handler); + + launch(start, end); // This function never returns +} + +void Prefork::checkChildDied(pid_t pid) +{ + for (int i = 0 ; i < m_count ; i++) { + if (m_children[i].pid == pid) { + // ### TODO: Should we kill all of the children here? + // ### TODO: Is qFatal the right way to do this? + qFatal("Prefork child died"); + } + } +} + +int Prefork::size() const +{ + return m_count; +} + +const PreforkChildData *Prefork::at(int i) const +{ + Q_ASSERT(i >= 0 && i < m_count); + return &m_children[i]; +} + +QT_END_NAMESPACE_PROCESSMANAGER diff --git a/src/core/prefork.h b/src/core/prefork.h new file mode 100644 index 0000000..dfed853 --- /dev/null +++ b/src/core/prefork.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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 PREFORK_H +#define PREFORK_H + +#include "processmanager-global.h" + +QT_BEGIN_NAMESPACE_PROCESSMANAGER + +struct Q_ADDON_PROCESSMANAGER_EXPORT PreforkChildData { + int stdin; // Child stdin (write to this) + int stdout; // Child stdout (read from this) + int pid; // Array of pids (number of children) +}; + +class Q_ADDON_PROCESSMANAGER_EXPORT Prefork { +public: + static Prefork *instance(); + void execute(int *argc_ptr, char ***argv_ptr); + void checkChildDied(pid_t pid); + + int size() const; + const PreforkChildData *at(int i) const; + +private: + Prefork(); + + int nextMarker(int index); + void launch(int start, int end); + int makeChild(int start); + +private: + int m_argc; // Original number of arguments + char **m_argv; // Original pointer to argument + size_t m_argv_size; // Length of vector allocated to original list + int m_count; // Number of child processes forked + PreforkChildData *m_children; +}; + +QT_END_NAMESPACE_PROCESSMANAGER + +#endif // PREFORK_H diff --git a/src/core/preforkprocessbackendfactory.cpp b/src/core/preforkprocessbackendfactory.cpp new file mode 100644 index 0000000..b2336d3 --- /dev/null +++ b/src/core/preforkprocessbackendfactory.cpp @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#include "preforkprocessbackendfactory.h" +#include "prefork.h" +#include "remoteprocessbackend.h" +#include "remoteprotocol.h" + +#include +#include +#include +//#include +#include + +QT_BEGIN_NAMESPACE_PROCESSMANAGER + +const int kPreforkTimerInterval = 1000; + +/*! + \class PreforkProcessBackendFactory + \brief The PreforkProcessBackendFactory connects to a preforked client +*/ + +/*! + \property index + Index into the prefork instance of which process this should be + connected to. +*/ + +/*! + Construct a PreforkProcessBackendFactory with optional \a parent. + The \a info ProcessInfo is used to start the prefork process. +*/ + +PreforkProcessBackendFactory::PreforkProcessBackendFactory(QObject *parent) + : RemoteProcessBackendFactory(parent) + , m_index(-1) + , m_in(NULL) + , m_out(NULL) +{ +} + +/*! + Destroy this and child objects. +*/ + +PreforkProcessBackendFactory::~PreforkProcessBackendFactory() +{ + const PreforkChildData *data = Prefork::instance()->at(m_index); + if (data) { + QJsonObject message; + message.insert(RemoteProtocol::remote(), RemoteProtocol::stop()); + m_outbuf.append(QJsonDocument(message).toBinaryData()); + + while (m_outbuf.size()) { + int n = ::write(data->stdin, m_outbuf.data(), m_outbuf.size()); + if (n == -1) + qFatal("Failed to write to stdout"); + if (n < m_outbuf.size()) + m_outbuf = m_outbuf.mid(n); + else + m_outbuf.clear(); + } + } +} + +/*! + Return the process index + */ + +int PreforkProcessBackendFactory::index() const +{ + return m_index; +} + +/*! + Set the prefork index to \a index + */ + +void PreforkProcessBackendFactory::setIndex(int index) +{ + Prefork *prefork = Prefork::instance(); + Q_ASSERT(prefork); + + if (index >= 0 && index < prefork->size()) { + m_index = index; + const PreforkChildData *data = prefork->at(index); + + if (m_in) + delete m_in; + if (m_out) + delete m_out; + + m_in = new QSocketNotifier(data->stdout, QSocketNotifier::Read, this); + m_out = new QSocketNotifier(data->stdin, QSocketNotifier::Write, this); + connect(m_in, SIGNAL(activated(int)), SLOT(inReady(int))); + connect(m_out, SIGNAL(activated(int)), SLOT(outReady(int))); + m_in->setEnabled(true); + m_out->setEnabled(false); + emit indexChanged(); + } + else + qWarning() << Q_FUNC_INFO << "index out of range"; +} + + +bool PreforkProcessBackendFactory::send(const QJsonObject& message) +{ + m_outbuf.append(QJsonDocument(message).toBinaryData()); + m_out->setEnabled(true); + return true; +} + +void PreforkProcessBackendFactory::inReady(int fd) +{ + m_in->setEnabled(false); + const int bufsize = 1024; + uint oldSize = m_inbuf.size(); + m_inbuf.resize(oldSize + bufsize); + int n = ::read(fd, m_inbuf.data()+oldSize, bufsize); + if (n > 0) + m_inbuf.resize(oldSize+n); + else + m_inbuf.resize(oldSize); + + while (m_inbuf.size() >= 12) { + if (QJsonDocument::BinaryFormatTag != *((uint *) m_inbuf.data())) + qFatal("ERROR in receive buffer: %s", m_inbuf.data()); + qint32 message_size = qFromLittleEndian(((qint32 *)m_inbuf.data())[2]) + 8; + if (m_inbuf.size() < message_size) + break; + QByteArray msg = m_inbuf.left(message_size); + m_inbuf = m_inbuf.mid(message_size); + receive(QJsonDocument::fromBinaryData(msg).object()); + } + m_in->setEnabled(true); +} + +void PreforkProcessBackendFactory::outReady(int fd) +{ + m_out->setEnabled(false); + if (m_outbuf.size()) { + int n = ::write(fd, m_outbuf.data(), m_outbuf.size()); + if (n == -1) { + qDebug() << "Failed to write to stdout"; + exit(-1); + } + if (n < m_outbuf.size()) + m_outbuf = m_outbuf.mid(n); + else + m_outbuf.clear(); + } + if (m_outbuf.size()) + m_out->setEnabled(true); +} + +/*! + Return the preforked process + */ + +QList PreforkProcessBackendFactory::internalProcesses() +{ + QList list; + const PreforkChildData *data = Prefork::instance()->at(m_index); + if (data) + list << data->pid; + return list; +} + +#include "moc_preforkprocessbackendfactory.cpp" + +QT_END_NAMESPACE_PROCESSMANAGER diff --git a/src/core/preforkprocessbackendfactory.h b/src/core/preforkprocessbackendfactory.h new file mode 100644 index 0000000..d485478 --- /dev/null +++ b/src/core/preforkprocessbackendfactory.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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 PREFORK_PROCESS_BACKEND_FACTORY_H +#define PREFORK_PROCESS_BACKEND_FACTORY_H + +#include "remoteprocessbackendfactory.h" + +class QSocketNotifier; + +QT_BEGIN_NAMESPACE_PROCESSMANAGER + +class Q_ADDON_PROCESSMANAGER_EXPORT PreforkProcessBackendFactory : public RemoteProcessBackendFactory +{ + Q_OBJECT + Q_PROPERTY(int index READ index WRITE setIndex NOTIFY indexChanged) + +public: + PreforkProcessBackendFactory(QObject *parent = 0); + virtual ~PreforkProcessBackendFactory(); + + int index() const; + void setIndex(int index); + + virtual QList internalProcesses(); + +signals: + void indexChanged(); + +protected: + virtual bool send(const QJsonObject&); + +private slots: + void inReady(int fd); + void outReady(int fd); + +private: + int m_index; + QByteArray m_inbuf; + QByteArray m_outbuf; + QSocketNotifier *m_in; + QSocketNotifier *m_out; +}; + +QT_END_NAMESPACE_PROCESSMANAGER + +#endif // PREFORK_PROCESS_BACKEND_FACTORY_H diff --git a/tests/auto/processmanager/processmanager.pro b/tests/auto/processmanager/processmanager.pro index 2049057..6d0389d 100644 --- a/tests/auto/processmanager/processmanager.pro +++ b/tests/auto/processmanager/processmanager.pro @@ -1,3 +1,11 @@ TEMPLATE = subdirs -SUBDIRS = testClient testPrelaunch testPipeLauncher testSocketLauncher testForkLauncher test +SUBDIRS = \ + testClient \ + testPrelaunch \ + testPipeLauncher \ + testSocketLauncher \ + testForkLauncher \ + testPreforkLauncher \ + testPrefork \ + test diff --git a/tests/auto/processmanager/testForkLauncher/main.cpp b/tests/auto/processmanager/testForkLauncher/main.cpp index 1ac4caf..f3da36d 100644 --- a/tests/auto/processmanager/testForkLauncher/main.cpp +++ b/tests/auto/processmanager/testForkLauncher/main.cpp @@ -131,7 +131,7 @@ private: QByteArray m_inbuf, m_outbuf; }; -int +extern "C" Q_DECL_EXPORT int main(int argc, char **argv) { forklauncher(&argc, &argv); diff --git a/tests/auto/processmanager/testForkLauncher/testForkLauncher.pro b/tests/auto/processmanager/testForkLauncher/testForkLauncher.pro index b8333ea..3198b00 100644 --- a/tests/auto/processmanager/testForkLauncher/testForkLauncher.pro +++ b/tests/auto/processmanager/testForkLauncher/testForkLauncher.pro @@ -8,5 +8,9 @@ DESTDIR = ./ SOURCES += main.cpp TARGET = testForkLauncher +# Position-independent code and export symbols +QMAKE_CXXFLAGS += -fPIC -fvisibility=hidden -fvisibility-inlines-hidden +QMAKE_LFLAGS += -pie -rdynamic + target.path = $$[QT_INSTALL_TESTS]/$$TESTCASE_NAME/testForkLauncher INSTALLS += target diff --git a/tests/auto/processmanager/testPrefork/testPrefork.cpp b/tests/auto/processmanager/testPrefork/testPrefork.cpp new file mode 100644 index 0000000..da4a00b --- /dev/null +++ b/tests/auto/processmanager/testPrefork/testPrefork.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +/* This should be called "Frigg" */ + +#include "prefork.h" +#include + +QT_USE_NAMESPACE_PROCESSMANAGER + +int main(int argc, char **argv) +{ + Prefork *prefork = Prefork::instance(); + prefork->execute(&argc, &argv); // This function never returns +} diff --git a/tests/auto/processmanager/testPrefork/testPrefork.pro b/tests/auto/processmanager/testPrefork/testPrefork.pro new file mode 100644 index 0000000..05c79dc --- /dev/null +++ b/tests/auto/processmanager/testPrefork/testPrefork.pro @@ -0,0 +1,12 @@ +CONFIG -= app_bundle +QT += processmanager jsonstream +QT -= gui + +include(../processmanager.pri) + +DESTDIR = ./ +SOURCES += testPrefork.cpp +TARGET = testPrefork + +target.path = $$[QT_INSTALL_TESTS]/$$TESTCASE_NAME/testPrefork +INSTALLS += target diff --git a/tests/auto/processmanager/testPreforkLauncher/main.cpp b/tests/auto/processmanager/testPreforkLauncher/main.cpp new file mode 100644 index 0000000..ace2c05 --- /dev/null +++ b/tests/auto/processmanager/testPreforkLauncher/main.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#include +#include + +#include +#include + +#include "socketlauncher.h" +#include "preforkprocessbackendfactory.h" + +QT_USE_NAMESPACE_PROCESSMANAGER + +extern "C" Q_DECL_EXPORT int main(int argc, char **argv) +{ + QtAddOn::JsonStream::JsonServer::ValidatorFlags flags(QtAddOn::JsonStream::JsonServer::NoValidation); + QString indir, outdir; + + QCoreApplication app(argc, argv); + QStringList args = QCoreApplication::arguments(); + QString progname = args.takeFirst(); + + SocketLauncher launcher; + PreforkProcessBackendFactory *factory = new PreforkProcessBackendFactory; + factory->setIndex(0); + launcher.addFactory(factory); + + launcher.listen(args[0]); + return app.exec(); +} diff --git a/tests/auto/processmanager/testPreforkLauncher/testPreforkLauncher.pro b/tests/auto/processmanager/testPreforkLauncher/testPreforkLauncher.pro new file mode 100644 index 0000000..6813981 --- /dev/null +++ b/tests/auto/processmanager/testPreforkLauncher/testPreforkLauncher.pro @@ -0,0 +1,16 @@ +CONFIG -= app_bundle +QT += processmanager jsonstream +QT -= gui + +include(../processmanager.pri) + +DESTDIR = ./ +SOURCES += main.cpp +TARGET = testPreforkLauncher + +# Position-independent code and export symbols +QMAKE_CXXFLAGS += -fPIC -fvisibility=hidden -fvisibility-inlines-hidden +QMAKE_LFLAGS += -pie -rdynamic + +target.path = $$[QT_INSTALL_TESTS]/$$TESTCASE_NAME/testPreforkLauncher +INSTALLS += target diff --git a/tests/auto/processmanager/tst_processmanager.cpp b/tests/auto/processmanager/tst_processmanager.cpp index 3cc2cf2..cd1a3a4 100644 --- a/tests/auto/processmanager/tst_processmanager.cpp +++ b/tests/auto/processmanager/tst_processmanager.cpp @@ -814,6 +814,42 @@ static void forkLauncherTest( clientFunc func, infoFunc infoFixup=0 ) #endif } +static void preforkLauncherTest( clientFunc func, infoFunc infoFixup=0 ) +{ +#if defined(Q_OS_LINUX) + QProcess *remote = new QProcess; + QString socketName = QLatin1String("/tmp/preforklauncher"); + remote->setProcessChannelMode(QProcess::ForwardedChannels); + QStringList args; + args << "--" << "testPreforkLauncher/testPreforkLauncher" << socketName + << "--" << "testForkLauncher/testForkLauncher"; + qDebug() << "Trying to run: testPrefork/testPrefork" << args; + remote->start("testPrefork/testPrefork", args); + QVERIFY(remote->waitForStarted()); + waitForSocket(socketName); + + ProcessBackendManager *manager = new ProcessBackendManager; + SocketProcessBackendFactory *factory = new SocketProcessBackendFactory; + factory->setSocketName(socketName); + manager->addFactory(factory); + + ProcessInfo info; + info.setValue("program", "testClient/testClient"); + if (infoFixup) + infoFixup(info); + fixUidGid(info); + func(manager, info, writeLine); + + delete manager; + delete remote; +#else + Q_UNUSED(func); + Q_UNUSED(infoFixup); +#endif +} + + + @@ -905,6 +941,17 @@ private slots: void forkLauncherOomChangeBefore() { forkLauncherTest(oomChangeBeforeClient); } void forkLauncherOomChangeAfter() { forkLauncherTest(oomChangeAfterClient); } + void preforkLauncherStartAndStop() { preforkLauncherTest(startAndStopClient); } + void preforkLauncherStartAndStopMultiple() { preforkLauncherTest(startAndStopMultiple); } + void preforkLauncherStartAndKill() { preforkLauncherTest(startAndKillClient); } + void preforkLauncherStartAndKillTough() { preforkLauncherTest(startAndKillClient, makeTough); } + void preforkLauncherStartAndCrash() { preforkLauncherTest(startAndCrashClient); } + void preforkLauncherEcho() { preforkLauncherTest(echoClient); } + void preforkLauncherPriorityChangeBefore() { preforkLauncherTest(priorityChangeBeforeClient); } + void preforkLauncherPriorityChangeAfter() { preforkLauncherTest(priorityChangeAfterClient); } + void preforkLauncherOomChangeBefore() { preforkLauncherTest(oomChangeBeforeClient); } + void preforkLauncherOomChangeAfter() { preforkLauncherTest(oomChangeAfterClient); } + void prelaunchChildAbort(); void frontend(); -- cgit v1.2.3