summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Christian <andrew.christian@nokia.com>2012-03-01 16:25:51 +0100
committerChris Craig <ext-chris.craig@nokia.com>2012-03-06 17:31:52 +0100
commit5dd2bde59a18dea49b80afb0c2e6cf4827d79def (patch)
tree3ac696131d7791afc7443ecea003ebee1035388b
parentf47aab326b583bc8a44c8e0702257667918f3faf (diff)
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 <ext-chris.craig@nokia.com>
-rw-r--r--src/core/core-lib.pri8
-rw-r--r--src/core/core.pro3
-rw-r--r--src/core/prefork.cpp243
-rw-r--r--src/core/prefork.h79
-rw-r--r--src/core/preforkprocessbackendfactory.cpp208
-rw-r--r--src/core/preforkprocessbackendfactory.h83
-rw-r--r--tests/auto/processmanager/processmanager.pro10
-rw-r--r--tests/auto/processmanager/testForkLauncher/main.cpp2
-rw-r--r--tests/auto/processmanager/testForkLauncher/testForkLauncher.pro4
-rw-r--r--tests/auto/processmanager/testPrefork/testPrefork.cpp51
-rw-r--r--tests/auto/processmanager/testPrefork/testPrefork.pro12
-rw-r--r--tests/auto/processmanager/testPreforkLauncher/main.cpp67
-rw-r--r--tests/auto/processmanager/testPreforkLauncher/testPreforkLauncher.pro16
-rw-r--r--tests/auto/processmanager/tst_processmanager.cpp47
14 files changed, 829 insertions, 4 deletions
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 <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+
+#if defined(Q_OS_LINUX)
+#include <sys/prctl.h>
+#endif
+
+#include <QtGlobal>
+#include <QDebug>
+#include <QFileInfo>
+
+
+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 <QDebug>
+#include <QJsonDocument>
+#include <QSocketNotifier>
+//#include <QFileInfo>
+#include <QtEndian>
+
+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<Q_PID> PreforkProcessBackendFactory::internalProcesses()
+{
+ QList<Q_PID> 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<Q_PID> 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 <QDebug>
+
+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 <QCoreApplication>
+#include <QDebug>
+
+#include <jsonserver.h>
+#include <schemavalidator.h>
+
+#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();