]> granicus.if.org Git - icinga2/commitdiff
Refactor the Process class. Remove the Windows implementation for now.
authorGunnar Beutner <gunnar.beutner@netways.de>
Wed, 13 Feb 2013 10:39:24 +0000 (11:39 +0100)
committerGunnar Beutner <gunnar.beutner@netways.de>
Wed, 13 Feb 2013 10:39:24 +0000 (11:39 +0100)
lib/base/Makefile.am
lib/base/base.vcxproj
lib/base/process-unix.cpp [new file with mode: 0644]
lib/base/process-windows.cpp [new file with mode: 0644]
lib/base/process.cpp
lib/base/process.h

index 537884c1731ad01ec79f4aae2ed85415f46128e1..eb6b036ef51e02642e54027700974e0e32f2323d 100644 (file)
@@ -34,6 +34,8 @@ libbase_la_SOURCES =  \
        object.cpp \
        object.h \
        process.cpp \
+       process-unix.cpp \
+       process-windows.cpp \
        process.h \
        qstring.cpp \
        qstring.h \
index 754254405b8a8f7af5a4e731095ee07adf81aba3..7f136821c7871e84628c700e1f1bbf9efb192f04 100644 (file)
@@ -39,6 +39,8 @@
     <ClCompile Include="netstring.cpp" />
     <ClCompile Include="object.cpp" />
     <ClCompile Include="process.cpp" />
+    <ClCompile Include="process-unix.cpp" />
+    <ClCompile Include="process-windows.cpp" />
     <ClCompile Include="qstring.cpp" />
     <ClCompile Include="ringbuffer.cpp" />
     <ClCompile Include="scriptfunction.cpp" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/lib/base/process-unix.cpp b/lib/base/process-unix.cpp
new file mode 100644 (file)
index 0000000..17eb7e8
--- /dev/null
@@ -0,0 +1,323 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/)        *
+ *                                                                            *
+ * This program is free software; you can redistribute it and/or              *
+ * modify it under the terms of the GNU General Public License                *
+ * as published by the Free Software Foundation; either version 2             *
+ * of the License, or (at your option) any later version.                     *
+ *                                                                            *
+ * This program is distributed in the hope that it will be useful,            *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
+ * GNU General Public License for more details.                               *
+ *                                                                            *
+ * You should have received a copy of the GNU General Public License          *
+ * along with this program; if not, write to the Free Software Foundation     *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
+ ******************************************************************************/
+
+#ifndef _WIN32
+#include "i2-base.h"
+
+#ifndef _MSC_VER
+#include <execvpe.h>
+#endif /* _MSC_VER */
+
+using namespace icinga;
+
+int Process::m_TaskFd;
+extern char **environ;
+
+void Process::CreateWorkers(void)
+{
+       int fds[2];
+
+       if (pipe(fds) < 0)
+               BOOST_THROW_EXCEPTION(PosixException("pipe() failed.", errno));
+
+       m_TaskFd = fds[1];
+
+       for (int i = 0; i < thread::hardware_concurrency(); i++) {
+               int childTaskFd;
+
+               childTaskFd = dup(fds[0]);
+
+               if (childTaskFd < 0)
+                       BOOST_THROW_EXCEPTION(PosixException("dup() failed.", errno));
+
+               int flags;
+               flags = fcntl(childTaskFd, F_GETFL, 0);
+               if (flags < 0)
+                       BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno));
+
+               if (fcntl(childTaskFd, F_SETFL, flags | O_NONBLOCK | O_CLOEXEC) < 0)
+                       BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno));
+
+               thread t(&Process::WorkerThreadProc, childTaskFd);
+               t.detach();
+       }
+}
+
+void Process::WorkerThreadProc(int taskFd)
+{
+       map<int, Process::Ptr> tasks;
+       pollfd *pfds = NULL;
+
+       for (;;) {
+               map<int, Process::Ptr>::iterator it, prev;
+
+               pfds = (pollfd *)realloc(pfds, (1 + tasks.size()) * sizeof(pollfd));
+
+               if (pfds == NULL)
+                       BOOST_THROW_EXCEPTION(PosixException("realloc() failed.", errno));
+
+               int idx = 0;
+
+               int fd;
+               BOOST_FOREACH(tie(fd, tuples::ignore), tasks) {
+                       pfds[idx].fd = fd;
+                       pfds[idx].events = POLLIN | POLLHUP;
+                       idx++;
+               }
+
+               if (tasks.size() < MaxTasksPerThread) {
+                       pfds[idx].fd = taskFd;
+                       pfds[idx].events = POLLIN;
+                       idx++;
+               }
+
+               int rc = poll(pfds, idx, -1);
+
+               if (rc < 0 && errno != EINTR)
+                       BOOST_THROW_EXCEPTION(PosixException("poll() failed.", errno));
+
+               if (rc == 0)
+                       continue;
+
+
+               for (int i = 0; i < idx; i++) {
+                       if ((pfds[i].revents & (POLLIN|POLLHUP)) == 0)
+                               continue;
+
+                       while (pfds[i].fd == taskFd && tasks.size() < MaxTasksPerThread) {
+                               Process::Ptr task;
+
+                               {
+                                       boost::mutex::scoped_lock lock(m_Mutex);
+
+                                       /* Read one byte for every task we take from the pending tasks list. */
+                                       char buffer;
+                                       int rc = read(taskFd, &buffer, sizeof(buffer));
+
+                                       if (rc < 0) {
+                                               if (errno == EAGAIN)
+                                                       break; /* Someone else was faster and took our task. */
+
+                                               BOOST_THROW_EXCEPTION(PosixException("read() failed.", errno));
+                                       }
+
+                                       assert(!m_Tasks.empty());
+
+                                       task = m_Tasks.front();
+                                       m_Tasks.pop_front();
+                               }
+
+                               try {
+                                       task->InitTask();
+
+                                       int fd = task->m_FD;
+
+                                       if (fd >= 0)
+                                               tasks[fd] = task;
+                               } catch (...) {
+                                       Event::Post(boost::bind(&Process::FinishException, task, boost::current_exception()));
+                               }
+                       }
+
+                       it = tasks.find(pfds[i].fd);
+
+                       if (it == tasks.end())
+                               continue;
+
+                       Process::Ptr task = it->second;
+
+                       if (!task->RunTask()) {
+                               prev = it;
+                               tasks.erase(prev);
+
+                               Event::Post(boost::bind(&Process::FinishResult, task, task->m_Result));
+                       }
+               }
+       }
+}
+
+void Process::NotifyWorker(void)
+{
+       /**
+        * This little gem which is commonly known as the "self-pipe trick"
+        * takes care of waking up the select() call in the worker thread.
+        */
+       if (write(m_TaskFd, "T", 1) < 0)
+               BOOST_THROW_EXCEPTION(PosixException("write() failed.", errno));
+}
+
+void Process::InitTask(void)
+{
+       m_Result.ExecutionStart = Utility::GetTime();
+
+       assert(m_FD == -1);
+
+       int fds[2];
+
+#ifdef HAVE_PIPE2
+       if (pipe2(fds, O_NONBLOCK | O_CLOEXEC) < 0)
+#else /* HAVE_PIPE2 */
+       if (pipe(fds) < 0)
+#endif /* HAVE_PIPE2 */
+               BOOST_THROW_EXCEPTION(PosixException("pipe() failed.", errno));
+
+#ifndef HAVE_PIPE2
+       int flags;
+       flags = fcntl(fds[0], F_GETFL, 0);
+       if (flags < 0)
+               BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno));
+
+       if (fcntl(fds[0], F_SETFL, flags | O_NONBLOCK | O_CLOEXEC) < 0)
+               BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno));
+
+       flags = fcntl(fds[1], F_GETFL, 0);
+       if (flags < 0)
+               BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno));
+
+       if (fcntl(fds[1], F_SETFL, flags | O_NONBLOCK | O_CLOEXEC) < 0)
+               BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno));
+#endif /* HAVE_PIPE2 */
+
+       // build argv
+       char **argv = new char *[m_Arguments.size() + 1];
+
+       for (int i = 0; i < m_Arguments.size(); i++)
+               argv[i] = strdup(m_Arguments[i].CStr());
+
+       argv[m_Arguments.size()] = NULL;
+
+       m_Arguments.clear();
+
+       // build envp
+       int envc = 0;
+
+       /* count existing environment variables */
+       while (environ[envc] != NULL)
+               envc++;
+
+       char **envp = new char *[envc + (m_ExtraEnvironment ? m_ExtraEnvironment->GetLength() : 0) + 1];
+
+       for (int i = 0; i < envc; i++)
+               envp[i] = strdup(environ[i]);
+
+       if (m_ExtraEnvironment) {
+               String key;
+               Value value;
+               int index = envc;
+               BOOST_FOREACH(tie(key, value), m_ExtraEnvironment) {
+                       String kv = key + "=" + Convert::ToString(value);
+                       envp[index] = strdup(kv.CStr());
+                       index++;
+               }
+       }
+
+       envp[envc + (m_ExtraEnvironment ? m_ExtraEnvironment->GetLength() : 0)] = NULL;
+
+       m_ExtraEnvironment.reset();
+
+#ifdef HAVE_VFORK
+       m_Pid = vfork();
+#else /* HAVE_VFORK */
+       m_Pid = fork();
+#endif /* HAVE_VFORK */
+
+       if (m_Pid < 0)
+               BOOST_THROW_EXCEPTION(PosixException("fork() failed.", errno));
+
+       if (m_Pid == 0) {
+               // child process
+
+               if (dup2(fds[1], STDOUT_FILENO) < 0 || dup2(fds[1], STDERR_FILENO) < 0) {
+                       perror("dup2() failed.");
+                       _exit(128);
+               }
+
+               (void) close(fds[0]);
+               (void) close(fds[1]);
+
+               if (execvpe(argv[0], argv, envp) < 0) {
+                       perror("execvpe() failed.");
+                       _exit(128);
+               }
+
+               _exit(128);
+       }
+
+       // parent process
+
+       // free arguments
+       for (int i = 0; argv[i] != NULL; i++)
+               free(argv[i]);
+
+       delete [] argv;
+
+       // free environment
+       for (int i = 0; envp[i] != NULL; i++)
+               free(envp[i]);
+
+       delete [] envp;
+
+       m_FD = fds[0];
+       (void) close(fds[1]);
+}
+
+bool Process::RunTask(void)
+{
+       char buffer[512];
+       int rc;
+
+       do {
+               rc = read(m_FD, buffer, sizeof(buffer));
+
+               if (rc > 0) {
+                       m_OutputStream.write(buffer, rc);
+               }
+       } while (rc > 0);
+
+       if (rc < 0 && errno == EAGAIN)
+               return true;
+
+       String output = m_OutputStream.str();
+
+       int status, exitcode;
+
+       (void) close(m_FD);
+
+       if (waitpid(m_Pid, &status, 0) != m_Pid)
+               BOOST_THROW_EXCEPTION(PosixException("waitpid() failed.", errno));
+
+       if (WIFEXITED(status)) {
+               exitcode = WEXITSTATUS(status);
+       } else if (WIFSIGNALED(status)) {
+               stringstream outputbuf;
+               outputbuf << "Process was terminated by signal " << WTERMSIG(status);
+               output = outputbuf.str();
+               exitcode = 128;
+       } else {
+               exitcode = 128;
+       }
+
+       m_Result.ExecutionEnd = Utility::GetTime();
+       m_Result.ExitStatus = exitcode;
+       m_Result.Output = output;
+
+       return false;
+}
+
+#endif /* _WIN32 */
diff --git a/lib/base/process-windows.cpp b/lib/base/process-windows.cpp
new file mode 100644 (file)
index 0000000..954644b
--- /dev/null
@@ -0,0 +1,54 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/)        *
+ *                                                                            *
+ * This program is free software; you can redistribute it and/or              *
+ * modify it under the terms of the GNU General Public License                *
+ * as published by the Free Software Foundation; either version 2             *
+ * of the License, or (at your option) any later version.                     *
+ *                                                                            *
+ * This program is distributed in the hope that it will be useful,            *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
+ * GNU General Public License for more details.                               *
+ *                                                                            *
+ * You should have received a copy of the GNU General Public License          *
+ * along with this program; if not, write to the Free Software Foundation     *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
+ ******************************************************************************/
+
+#ifdef _WIN32
+#include "i2-base.h"
+
+#ifndef _MSC_VER
+#include <execvpe.h>
+#endif /* _MSC_VER */
+
+using namespace icinga;
+
+void Process::CreateWorkers(void)
+{
+       // TODO: implement
+}
+
+void Process::WorkerThreadProc(void)
+{
+       // TODO: implement
+}
+
+void Process::NotifyWorker(void)
+{
+       // TODO: implement
+}
+
+void Process::InitTask(void)
+{
+       // TODO: implement
+}
+
+bool Process::RunTask(void)
+{
+       // TODO: implement
+}
+
+#endif /* _WIN32 */
index 8c1aa0239ec25c0f12c937ca38002c7e6e17107e..3ac71fb53bcee528ac96f77497dd26e571ce7cfb 100644 (file)
 
 using namespace icinga;
 
-bool Process::m_ThreadCreated = false;
+bool Process::m_WorkersCreated = false;
 boost::mutex Process::m_Mutex;
 deque<Process::Ptr> Process::m_Tasks;
-#ifndef _MSC_VER
-int Process::m_TaskFd;
-extern char **environ;
-#endif /* _MSC_VER */
 
 Process::Process(const vector<String>& arguments, const Dictionary::Ptr& extraEnvironment)
-       : AsyncTask<Process, ProcessResult>(),
-#ifndef _MSC_VER
-       m_FD(-1)
-#else /* _MSC_VER */
-       m_FP(NULL)
-#endif /* _MSC_VER */
+       : AsyncTask<Process, ProcessResult>(), m_Arguments(arguments), m_ExtraEnvironment(extraEnvironment)
 {
        assert(Application::IsMainThread());
 
-       if (!m_ThreadCreated) {
-#ifndef _MSC_VER
-               int fds[2];
-
-               if (pipe(fds) < 0)
-                       BOOST_THROW_EXCEPTION(PosixException("pipe() failed.", errno));
-
-               m_TaskFd = fds[1];
-#endif /* _MSC_VER */
-
-               for (int i = 0; i < thread::hardware_concurrency(); i++) {
-                       int childTaskFd;
+       if (!m_WorkersCreated) {
+               CreateWorkers();
 
-#ifdef _MSC_VER
-                       childTaskFd = 0;
-#else /* _MSC_VER */
-                       childTaskFd = dup(fds[0]);
-
-                       if (childTaskFd < 0)
-                               BOOST_THROW_EXCEPTION(PosixException("dup() failed.", errno));
-
-                       int flags;
-                       flags = fcntl(childTaskFd, F_GETFL, 0);
-                       if (flags < 0)
-                               BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno));
-
-                       if (fcntl(childTaskFd, F_SETFL, flags | O_NONBLOCK | O_CLOEXEC) < 0)
-                               BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno));
-#endif /* _MSC_VER */
-
-                       thread t(&Process::WorkerThreadProc, childTaskFd);
-                       t.detach();
-               }
-
-               m_ThreadCreated = true;
+               m_WorkersCreated = true;
        }
 
-       // build argv
-       m_Arguments = new char *[arguments.size() + 1];
-
-       for (int i = 0; i < arguments.size(); i++)
-               m_Arguments[i] = strdup(arguments[i].CStr());
-
-       m_Arguments[arguments.size()] = NULL;
-
-       // build envp
-       int envc = 0;
-
-       /* count existing environment variables */
-       while (environ[envc] != NULL)
-               envc++;
-
-       m_Environment = new char *[envc + (extraEnvironment ? extraEnvironment->GetLength() : 0) + 1];
-
-       for (int i = 0; i < envc; i++)
-               m_Environment[i] = strdup(environ[i]);
-
-       if (extraEnvironment) {
-               String key;
-               Value value;
-               int index = envc;
-               BOOST_FOREACH(tie(key, value), extraEnvironment) {
-                       String kv = key + "=" + Convert::ToString(value);
-                       m_Environment[index] = strdup(kv.CStr());
-                       index++;
-               }
-       }
-
-       m_Environment[envc + (extraEnvironment ? extraEnvironment->GetLength() : 0)] = NULL;
+#ifndef _WIN32
+       m_FD = -1;
+#endif /* _MSC_VER */
 }
 
 vector<String> Process::ParseCommand(const String& command)
 {
        // TODO: implement
        vector<String> args;
-#ifdef _MSC_VER
+#ifdef _WIN32
        args.push_back(command);
-#else /* MSC_VER */
+#else /* _WIN32 */
        args.push_back("sh");
        args.push_back("-c");
        args.push_back(command);
@@ -135,320 +66,5 @@ void Process::Run(void)
                m_Tasks.push_back(GetSelf());
        }
 
-#ifndef _MSC_VER
-       /**
-        * This little gem which is commonly known as the "self-pipe trick"
-        * takes care of waking up the select() call in the worker thread.
-        */
-       if (write(m_TaskFd, "T", 1) < 0)
-               BOOST_THROW_EXCEPTION(PosixException("write() failed.", errno));
-#endif /* _MSC_VER */
-}
-
-void Process::WorkerThreadProc(int taskFd)
-{
-       map<int, Process::Ptr> tasks;
-       pollfd *pfds = NULL;
-
-       for (;;) {
-               map<int, Process::Ptr>::iterator it, prev;
-
-#ifndef _MSC_VER
-               pfds = (pollfd *)realloc(pfds, (1 + tasks.size()) * sizeof(pollfd));
-
-               if (pfds == NULL)
-                       BOOST_THROW_EXCEPTION(PosixException("realloc() failed.", errno));
-
-               int idx = 0;
-
-               int fd;
-               BOOST_FOREACH(tie(fd, tuples::ignore), tasks) {
-                       pfds[idx].fd = fd;
-                       pfds[idx].events = POLLIN | POLLHUP;
-                       idx++;
-               }
-
-               if (tasks.size() < MaxTasksPerThread) {
-                       pfds[idx].fd = taskFd;
-                       pfds[idx].events = POLLIN;
-                       idx++;
-               }
-
-               int rc = poll(pfds, idx, -1);
-
-               if (rc < 0 && errno != EINTR)
-                       BOOST_THROW_EXCEPTION(PosixException("poll() failed.", errno));
-
-               if (rc == 0)
-                       continue;
-
-#else /* _MSC_VER */
-               Utility::Sleep(1);
-#endif /* _MSC_VER */
-
-#ifndef _MSC_VER
-               for (int i = 0; i < idx; i++) {
-                       if ((pfds[i].revents & (POLLIN|POLLHUP)) == 0)
-                               continue;
-
-                       if (pfds[i].fd == taskFd) {
-#endif /* _MSC_VER */
-
-                               while (tasks.size() < MaxTasksPerThread) {
-                                       Process::Ptr task;
-
-                                       {
-                                               boost::mutex::scoped_lock lock(m_Mutex);
-
-#ifndef _MSC_VER
-                                               /* Read one byte for every task we take from the pending tasks list. */
-                                               char buffer;
-                                               int rc = read(taskFd, &buffer, sizeof(buffer));
-
-                                               if (rc < 0) {
-                                                       if (errno == EAGAIN)
-                                                               break; /* Someone else was faster and took our task. */
-
-                                                       BOOST_THROW_EXCEPTION(PosixException("read() failed.", errno));
-                                               }
-
-                                               assert(!m_Tasks.empty());
-#else /* _MSC_VER */
-                                               if (m_Tasks.empty())
-                                                       break;
-#endif /* _MSC_VER */
-
-                                               task = m_Tasks.front();
-                                               m_Tasks.pop_front();
-                                       }
-
-                                       try {
-                                               task->InitTask();
-
-#ifdef _MSC_VER
-                                               int fd = fileno(task->m_FP);
-#else /* _MSC_VER */
-                                               int fd = task->m_FD;
-#endif /* _MSC_VER */
-
-                                               if (fd >= 0)
-                                                       tasks[fd] = task;
-                                       } catch (...) {
-                                               Event::Post(boost::bind(&Process::FinishException, task, boost::current_exception()));
-                                       }
-                               }
-#ifndef _MSC_VER
-
-                               continue;
-                       }
-
-                       it = tasks.find(pfds[i].fd);
-
-                       if (it == tasks.end())
-                               continue;
-#else /* _MSC_VER */
-                       for (it = tasks.begin(); it != tasks.end(); ) {
-                               int fd = it->first;
-#endif /* _MSC_VER */
-                               Process::Ptr task = it->second;
-
-                               if (!task->RunTask()) {
-                                       prev = it;
-#ifdef _MSC_VER
-                                       it++;
-#endif /* _MSC_VER */
-                                       tasks.erase(prev);
-
-                                       Event::Post(boost::bind(&Process::FinishResult, task, task->m_Result));
-#ifdef _MSC_VER
-                               } else {
-                                       it++;
-#endif /* _MSC_VER */
-                               }
-#ifdef _MSC_VER
-                       }
-#else /* _MSC_VER */
-               }
-#endif /* _MSC_VER */
-       }
-}
-
-void Process::InitTask(void)
-{
-       m_Result.ExecutionStart = Utility::GetTime();
-
-#ifdef _MSC_VER
-       assert(m_FP == NULL);
-#else /* _MSC_VER */
-       assert(m_FD == -1);
-#endif /* _MSC_VER */
-
-#ifdef _MSC_VER
-       String cmdLine;
-
-       // This is almost certainly wrong, but will have to do for now. (#3684)
-       for (int i = 0; m_Arguments[i] != NULL ; i++) {
-               cmdLine += "\"";
-               cmdLine += m_Arguments[i];
-               cmdLine += "\" ";
-       }
-
-       // free arguments
-       for (int i = 0; m_Arguments[i] != NULL; i++)
-               free(m_Arguments[i]);
-
-       delete [] m_Arguments;
-
-       // free environment
-       for (int i = 0; m_Environment[i] != NULL; i++)
-               free(m_Environment[i]);
-
-       delete [] m_Environment;
-
-       m_FP = _popen(cmdLine.CStr(), "r");
-#else /* _MSC_VER */
-       int fds[2];
-
-#ifdef HAVE_PIPE2
-       if (pipe2(fds, O_NONBLOCK | O_CLOEXEC) < 0)
-#else /* HAVE_PIPE2 */
-       if (pipe(fds) < 0)
-#endif /* HAVE_PIPE2 */
-               BOOST_THROW_EXCEPTION(PosixException("pipe() failed.", errno));
-
-#ifndef HAVE_PIPE2
-       int flags;
-       flags = fcntl(fds[0], F_GETFL, 0);
-       if (flags < 0)
-               BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno));
-
-       if (fcntl(fds[0], F_SETFL, flags | O_NONBLOCK | O_CLOEXEC) < 0)
-               BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno));
-
-       flags = fcntl(fds[1], F_GETFL, 0);
-       if (flags < 0)
-               BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno));
-
-       if (fcntl(fds[1], F_SETFL, flags | O_NONBLOCK | O_CLOEXEC) < 0)
-               BOOST_THROW_EXCEPTION(PosixException("fcntl failed", errno));
-#endif /* HAVE_PIPE2 */
-
-#ifdef HAVE_VFORK
-       m_Pid = vfork();
-#else /* HAVE_VFORK */
-       m_Pid = fork();
-#endif /* HAVE_VFORK */
-
-       if (m_Pid < 0)
-               BOOST_THROW_EXCEPTION(PosixException("fork() failed.", errno));
-
-       if (m_Pid == 0) {
-               // child process
-
-               if (dup2(fds[1], STDOUT_FILENO) < 0 || dup2(fds[1], STDERR_FILENO) < 0) {
-                       perror("dup2() failed.");
-                       _exit(128);
-               }
-
-               (void) close(fds[0]);
-               (void) close(fds[1]);
-
-               if (execvpe(m_Arguments[0], m_Arguments, m_Environment) < 0) {
-                       perror("execvpe() failed.");
-                       _exit(128);
-               }
-
-               _exit(128);
-       }
-
-       // parent process
-
-       // free arguments
-       for (int i = 0; m_Arguments[i] != NULL; i++)
-               free(m_Arguments[i]);
-
-       delete [] m_Arguments;
-
-       // free environment
-       for (int i = 0; m_Environment[i] != NULL; i++)
-               free(m_Environment[i]);
-
-       delete [] m_Environment;
-
-       (void) close(fds[1]);
-
-       m_FD = fds[0];
-#endif /* _MSC_VER */
-}
-
-bool Process::RunTask(void)
-{
-       char buffer[512];
-       int rc;
-
-#ifndef _MSC_VER
-       do {
-               rc = read(m_FD, buffer, sizeof(buffer));
-#else /* _MSC_VER */
-               if (!feof(m_FP))
-                       rc =  fread(buffer, 1, sizeof(buffer), m_FP);
-               else
-                       rc = 0;
-#endif /* _MSC_VER */
-
-               if (rc > 0) {
-                       m_OutputStream.write(buffer, rc);
-#ifdef _MSC_VER
-                       return true;
-#endif /* _MSC_VER */
-               }
-#ifndef _MSC_VER
-       } while (rc > 0);
-
-       if (rc < 0 && errno == EAGAIN)
-               return true;
-#endif /* _MSC_VER */
-
-       String output = m_OutputStream.str();
-
-       int status, exitcode;
-
-#ifdef _MSC_VER
-       status = _pclose(m_FP);
-#else /* _MSC_VER */
-       (void) close(m_FD);
-
-       if (waitpid(m_Pid, &status, 0) != m_Pid)
-               BOOST_THROW_EXCEPTION(PosixException("waitpid() failed.", errno));
-#endif /* _MSC_VER */
-
-#ifndef _MSC_VER
-       if (WIFEXITED(status)) {
-               exitcode = WEXITSTATUS(status);
-#else /* _MSC_VER */
-               exitcode = status;
-
-               /* cmd.exe returns error code 1 (warning) when the plugin
-                * could not be executed - change the exit status to "unknown"
-                * when we have no plugin output. */
-               if (output.IsEmpty())
-                       exitcode = 128;
-#endif /* _MSC_VER */
-
-#ifndef _MSC_VER
-       } else if (WIFSIGNALED(status)) {
-               stringstream outputbuf;
-               outputbuf << "Process was terminated by signal " << WTERMSIG(status);
-               output = outputbuf.str();
-               exitcode = 128;
-       } else {
-               exitcode = 128;
-       }
-#endif /* _MSC_VER */
-
-       m_Result.ExecutionEnd = Utility::GetTime();
-       m_Result.ExitStatus = exitcode;
-       m_Result.Output = output;
-
-       return false;
+       NotifyWorker();
 }
index c3c661401c3d97cb1fd6b0bdea9731766d03788f..f2805bce0458297c919db73d87b970ed8cff17dd 100644 (file)
@@ -54,17 +54,15 @@ public:
 
        static vector<String> ParseCommand(const String& command);
 private:
-       static bool m_ThreadCreated;
+       static bool m_WorkersCreated;
 
-       char **m_Arguments;
-       char **m_Environment;
+       vector<String> m_Arguments;
+       Dictionary::Ptr m_ExtraEnvironment;
 
-#ifndef _MSC_VER
+#ifndef _WIN32
        pid_t m_Pid;
        int m_FD;
-#else /* _MSC_VER */
-       FILE *m_FP;
-#endif /* _MSC_VER */
+#endif /* _WIN32 */
 
        stringstream m_OutputStream;
 
@@ -74,11 +72,20 @@ private:
 
        static boost::mutex m_Mutex;
        static deque<Process::Ptr> m_Tasks;
-#ifndef _MSC_VER
+#ifndef _WIN32
        static int m_TaskFd;
-#endif /* _MSC_VER */
+#endif /* _WIN32 */
 
+       static void CreateWorkers(void);
+       static void NotifyWorker(void);
+
+       void SpawnTask(void);
+
+#ifdef _WIN32
+       static void WorkerThreadProc(void);
+#else /* _WIN32 */
        static void WorkerThreadProc(int taskFd);
+#endif /* _WIN32 */
 
        void InitTask(void);
        bool RunTask(void);