diff --git a/lib/base/Makefile.am b/lib/base/Makefile.am
index 537884c17..eb6b036ef 100644
--- a/lib/base/Makefile.am
+++ b/lib/base/Makefile.am
@@ -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 \
diff --git a/lib/base/base.vcxproj b/lib/base/base.vcxproj
index 754254405..7f136821c 100644
--- a/lib/base/base.vcxproj
+++ b/lib/base/base.vcxproj
@@ -39,6 +39,8 @@
+
+
@@ -249,4 +251,4 @@
-
\ No newline at end of file
+
diff --git a/lib/base/process-unix.cpp b/lib/base/process-unix.cpp
new file mode 100644
index 000000000..17eb7e8f8
--- /dev/null
+++ b/lib/base/process-unix.cpp
@@ -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
+#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 tasks;
+ pollfd *pfds = NULL;
+
+ for (;;) {
+ map::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
index 000000000..954644b71
--- /dev/null
+++ b/lib/base/process-windows.cpp
@@ -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
+#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 */
diff --git a/lib/base/process.cpp b/lib/base/process.cpp
index 8c1aa0239..3ac71fb53 100644
--- a/lib/base/process.cpp
+++ b/lib/base/process.cpp
@@ -25,102 +25,33 @@
using namespace icinga;
-bool Process::m_ThreadCreated = false;
+bool Process::m_WorkersCreated = false;
boost::mutex Process::m_Mutex;
deque Process::m_Tasks;
-#ifndef _MSC_VER
-int Process::m_TaskFd;
-extern char **environ;
-#endif /* _MSC_VER */
Process::Process(const vector& arguments, const Dictionary::Ptr& extraEnvironment)
- : AsyncTask(),
-#ifndef _MSC_VER
- m_FD(-1)
-#else /* _MSC_VER */
- m_FP(NULL)
-#endif /* _MSC_VER */
+ : AsyncTask(), m_Arguments(arguments), m_ExtraEnvironment(extraEnvironment)
{
assert(Application::IsMainThread());
- if (!m_ThreadCreated) {
-#ifndef _MSC_VER
- int fds[2];
+ if (!m_WorkersCreated) {
+ CreateWorkers();
- 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;
-
-#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 Process::ParseCommand(const String& command)
{
// TODO: implement
vector 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 tasks;
- pollfd *pfds = NULL;
-
- for (;;) {
- map::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();
}
diff --git a/lib/base/process.h b/lib/base/process.h
index c3c661401..f2805bce0 100644
--- a/lib/base/process.h
+++ b/lib/base/process.h
@@ -54,17 +54,15 @@ public:
static vector ParseCommand(const String& command);
private:
- static bool m_ThreadCreated;
+ static bool m_WorkersCreated;
- char **m_Arguments;
- char **m_Environment;
+ vector 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 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);