summaryrefslogtreecommitdiff
path: root/cpp/src/IcePack/ActivatorI.cpp
diff options
context:
space:
mode:
authorBernard Normier <bernard@zeroc.com>2003-12-27 20:36:41 +0000
committerBernard Normier <bernard@zeroc.com>2003-12-27 20:36:41 +0000
commit3f954aab0eab59e99bad75f9b1d98a7f7603a46b (patch)
tree9dfc1df4d61de79e8c453ab5ff789bd5fa516977 /cpp/src/IcePack/ActivatorI.cpp
parentfixing all, minimal dependencies (diff)
downloadice-3f954aab0eab59e99bad75f9b1d98a7f7603a46b.tar.bz2
ice-3f954aab0eab59e99bad75f9b1d98a7f7603a46b.tar.xz
ice-3f954aab0eab59e99bad75f9b1d98a7f7603a46b.zip
Added new icepackadmin commands: signal, stdout, stderr
Diffstat (limited to 'cpp/src/IcePack/ActivatorI.cpp')
-rw-r--r--cpp/src/IcePack/ActivatorI.cpp634
1 files changed, 518 insertions, 116 deletions
diff --git a/cpp/src/IcePack/ActivatorI.cpp b/cpp/src/IcePack/ActivatorI.cpp
index adaf43ab328..517c0261a90 100644
--- a/cpp/src/IcePack/ActivatorI.cpp
+++ b/cpp/src/IcePack/ActivatorI.cpp
@@ -19,9 +19,11 @@
#include <IcePack/TraceLevels.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>
+
using namespace std;
using namespace Ice;
using namespace IcePack;
@@ -51,6 +53,192 @@ private:
}
+#define ICE_STRING(X) #X
+
+namespace
+{
+
+#ifndef _WIN32
+//
+// Helper function for async-signal safe error reporting
+//
+void
+reportChildError(int err, int fd, const char* cannot, const char* name)
+{
+ //
+ // Send any errors to the parent process, using the write
+ // end of the pipe.
+ //
+ char msg[500];
+ strcpy(msg, cannot);
+ strcat(msg, " `");
+ strcat(msg, name);
+ strcat(msg, "': ");
+ strcat(msg, strerror(err));
+ write(fd, msg, strlen(msg));
+ close(fd);
+ _exit(EXIT_FAILURE);
+}
+
+#endif
+
+#ifndef _WIN32
+string
+signalToString(int signal)
+{
+ switch(signal)
+ {
+ case SIGHUP:
+ {
+ return ICE_STRING(SIGHUP);
+ }
+ case SIGINT:
+ {
+ return ICE_STRING(SIGINT);
+ }
+ case SIGQUIT:
+ {
+ return ICE_STRING(SIGQUIT);
+ }
+ case SIGILL:
+ {
+ return ICE_STRING(SIGILL);
+ }
+ case SIGTRAP:
+ {
+ return ICE_STRING(SIGTRAP);
+ }
+ case SIGABRT:
+ {
+ return ICE_STRING(SIGABRT);
+ }
+ case SIGBUS:
+ {
+ return ICE_STRING(SIGBUS);
+ }
+ case SIGFPE:
+ {
+ return ICE_STRING(SIGFPE);
+ }
+ case SIGKILL:
+ {
+ return ICE_STRING(SIGKILL);
+ }
+ case SIGUSR1:
+ {
+ return ICE_STRING(SIGUSR1);
+ }
+ case SIGSEGV:
+ {
+ return ICE_STRING(SIGSEGV);
+ }
+ case SIGPIPE:
+ {
+ return ICE_STRING(SIGPIPE);
+ }
+ case SIGALRM:
+ {
+ return ICE_STRING(SIGALRM);
+ }
+ case SIGTERM:
+ {
+ return ICE_STRING(SIGTERM);
+ }
+ default:
+ {
+ ostringstream os;
+ os << "signal " << signal;
+ return os.str();
+ }
+ }
+#endif
+}
+
+int
+stringToSignal(const string& str)
+{
+#ifdef _WIN32
+ throw BadSignalException();
+#else
+
+ if(str == ICE_STRING(SIGHUP))
+ {
+ return SIGHUP;
+ }
+ else if(str == ICE_STRING(SIGINT))
+ {
+ return SIGINT;
+ }
+ else if(str == ICE_STRING(SIGQUIT))
+ {
+ return SIGQUIT;
+ }
+ else if(str == ICE_STRING(SIGILL))
+ {
+ return SIGILL;
+ }
+ else if(str == ICE_STRING(SIGTRAP))
+ {
+ return SIGTRAP;
+ }
+ else if(str == ICE_STRING(SIGABRT))
+ {
+ return SIGABRT;
+ }
+ else if(str == ICE_STRING(SIGBUS))
+ {
+ return SIGBUS;
+ }
+ else if(str == ICE_STRING(SIGFPE))
+ {
+ return SIGFPE;
+ }
+ else if(str == ICE_STRING(SIGKILL))
+ {
+ return SIGKILL;
+ }
+ else if(str == ICE_STRING(SIGUSR1))
+ {
+ return SIGUSR1;
+ }
+ else if(str == ICE_STRING(SIGSEGV))
+ {
+ return SIGSEGV;
+ }
+ else if(str == ICE_STRING(SIGUSR2))
+ {
+ return SIGUSR2;
+ }
+ else if(str == ICE_STRING(SIGPIPE))
+ {
+ return SIGPIPE;
+ }
+ else if(str == ICE_STRING(SIGALRM))
+ {
+ return SIGALRM;
+ }
+ else if(str == ICE_STRING(SIGTERM))
+ {
+ return SIGTERM;
+ }
+ else
+ {
+ if(str != "")
+ {
+ char* end;
+ long int signal = strtol(str.c_str(), &end, 10);
+ if(*end == '\0' && signal > 0 && signal < 64)
+ {
+ return static_cast<int>(signal);
+ }
+ }
+ throw BadSignalException();
+ }
+}
+#endif
+
+}
+
IcePack::ActivatorI::ActivatorI(const TraceLevelsPtr& traceLevels, const PropertiesPtr& properties) :
_traceLevels(traceLevels),
_properties(properties),
@@ -85,6 +273,9 @@ IcePack::ActivatorI::ActivatorI(const TraceLevelsPtr& traceLevels, const Propert
fcntl(_fdIntrRead, F_SETFL, flags);
#endif
+ _outputDir = _properties->getProperty("IcePack.Node.Output");
+ _redirectErrToOut = (_properties->getPropertyAsInt("IcePack.Node.RedirectErrToOut") > 0);
+
//
// Parse the properties override property.
//
@@ -342,9 +533,107 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
env = envbuf.c_str();
}
+ Process process;
+
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
+ if(_outputDir.size() > 0)
+ {
+ string outFile = _outputDir + "/" + server->description.name + ".out";
+
+ SECURITY_ATTRIBUTES sec = { 0 };
+ sec.nLength = sizeof(sec);
+ sec.bInheritHandle = true;
+
+ process.outHandle = CreateFile(outFile.c_str(),
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ &sec,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if(process.outHandle == INVALID_HANDLE_VALUE)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ if(SetFilePointer(process.outHandle, 0, NULL, FILE_END)
+ == INVALID_SET_FILE_POINTER)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+
+ if(_redirectErrToOut)
+ {
+ process.errHandle = process.outHandle;
+ }
+ else
+ {
+ string errFile = _outputDir + "/" + server->description.name + ".err";
+
+ process.errHandle = CreateFile(errFile.c_str(),
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ &sec,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if(process.errHandle == INVALID_HANDLE_VALUE)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ if(SetFilePointer(process.errHandle, 0, NULL, FILE_END)
+ == INVALID_SET_FILE_POINTER)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+
+ }
+
+ si.hStdInput = GetStdHandle(STD_OUTPUT_HANDLE);
+ if(si.hStdInput == INVALID_HANDLE_VALUE)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ si.hStdOutput = process.outHandle;
+ si.hStdError = process.errHandle;
+ si.dwFlags = STARTF_USESTDHANDLES;
+ }
+ else
+ {
+ process.outHandle = GetStdHandle(STD_OUTPUT_HANDLE);
+ if(process.outHandle == INVALID_HANDLE_VALUE)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ if(_redirectErrToOut)
+ {
+ process.errHandle = process.outHandle;
+ }
+ else
+ {
+ process.errHandle = GetStdHandle(STD_ERROR_HANDLE);
+ if(process.errHandle == INVALID_HANDLE_VALUE)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ }
+ }
+
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
@@ -353,7 +642,7 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
cmdbuf, // Command line
NULL, // Process attributes
NULL, // Thread attributes
- FALSE, // Inherit handles
+ TRUE, // Inherit handles
CREATE_NEW_PROCESS_GROUP, // Process creation flags
(LPVOID)env, // Process environment
dir, // Current directory
@@ -376,7 +665,7 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
//
CloseHandle(pi.hThread);
- Process process;
+
process.pid = pi.dwProcessId;
process.hnd = pi.hProcess;
process.server = server;
@@ -397,6 +686,84 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
ex.error = getSystemErrno();
throw ex;
}
+
+ //
+ // Convert to standard argc/argv.
+ //
+ int argc = static_cast<int>(args.size());
+ char** argv = static_cast<char**>(malloc((argc + 1) * sizeof(char*)));
+ int i = 0;
+ for(StringSeq::const_iterator p = args.begin(); p != args.end(); ++p, ++i)
+ {
+ assert(i < argc);
+ argv[i] = strdup(p->c_str());
+ }
+ assert(i == argc);
+ argv[argc] = 0;
+
+ int envCount = server->description.envs.size();
+ char** envs = new char*[envCount];
+ i = 0;
+ for(StringSeq::const_iterator q = server->description.envs.begin(); q != server->description.envs.end(); ++q)
+ {
+ envs[i++] = strdup(q->c_str());
+ }
+
+ //
+ // stdout and stderr redirection
+ //
+ int flags = O_WRONLY | O_APPEND | O_CREAT;
+ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+
+ int outFd;;
+ string outFile;
+ int errFd;
+ string errFile;
+
+ if(_outputDir.size() == 0)
+ {
+ outFd = STDOUT_FILENO;
+ errFd = _redirectErrToOut ? outFd : STDERR_FILENO;
+ }
+ else
+ {
+ outFile = _outputDir + "/" + server->description.name + ".out";
+ outFd = open(outFile.c_str(), flags, mode);
+ if(outFd < 0)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+
+ if(_redirectErrToOut)
+ {
+ errFile = outFile;
+ errFd = outFd;
+ }
+ else
+ {
+ errFile = _outputDir + "/" + server->description.name + ".err";
+ errFd = open(errFile.c_str(), flags, mode);
+
+ if(errFd < 0)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ }
+ }
+
+ const char* outFileCStr = outFile.c_str();
+ const char* errFileCStr = errFile.c_str();
+
+ //
+ // Current directory
+ //
+ const char* pwdCStr = pwd.c_str();
+
+
pid_t pid = fork();
if(pid == -1)
{
@@ -408,11 +775,9 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
if(pid == 0) // Child process.
{
//
- // TODO: eliminate all non-async-signal-safe calls, in particular anything
- // that may allocate dynamic memory.
+ // Until exec, we can only use async-signal safe functions
//
-
#ifdef __linux
//
// Create a process group for this child, to be able to send
@@ -422,6 +787,22 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
#endif
//
+ // stdout and stderr redirection
+ //
+ if(_outputDir.size() > 0)
+ {
+ if(dup2(outFd, STDOUT_FILENO) != STDOUT_FILENO)
+ {
+ reportChildError(errno, fds[1], "cannot associate stdout with opened file", outFileCStr);
+ }
+
+ if(dup2(errFd, STDERR_FILENO) != STDERR_FILENO)
+ {
+ reportChildError(errno, fds[1], "cannot associate stderr with opened file", errFileCStr);
+ }
+ }
+
+ //
// Close all file descriptors, except for standard input,
// standard output, standard error, and the write side
// of the newly created pipe.
@@ -435,115 +816,55 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
}
}
- //
- // Convert to standard argc/argv.
- //
- int argc = static_cast<int>(args.size());
- char** argv = static_cast<char**>(malloc((argc + 1) * sizeof(char*)));
- int i = 0;
- for(StringSeq::const_iterator p = args.begin(); p != args.end(); ++p, ++i)
- {
- assert(i < argc);
- argv[i] = strdup(p->c_str());
- }
- assert(i == argc);
- argv[argc] = 0;
-
- for(StringSeq::const_iterator q = server->description.envs.begin(); q != server->description.envs.end(); ++q)
+ for(i = 0; i < envCount; i++)
{
- if(putenv(strdup(q->c_str())) != 0)
+ if(putenv(envs[i]) != 0)
{
- SyscallException ex(__FILE__, __LINE__);
- ex.error = getSystemErrno();
- ostringstream s;
- s << "can't set environment variable: " << *q << "':\n" << ex;
- write(fds[1], s.str().c_str(), s.str().length());
- close(fds[1]);
- _exit(EXIT_FAILURE);
+ reportChildError(errno, fds[1], "cannot set environment variable", envs[i]);
}
}
-
//
- // Redirect the standard error output to the write side of the
- // pipe.
+ // Each env is leaked on purpose ... see man putenv().
//
- // TODO: This doesn't work well if the server doesn't control
- // when and how the output is flushed. For example, we could
- // receive one character after the other over the pipe which
- // is problematic since we don't know when to log message. For
- // sure we don't want to log each character one after the
- // other. We want to log the message. One solution would be to
- // put the received information in a buffer and log it only
- // when we receive a '\n'.
- //
-
-// if(fds[1] != STDERR_FILENO)
-// {
-// if(dup2(fds[1], STDERR_FILENO) != STDERR_FILENO)
-// {
-// //
-// // Send any errors to the parent process, using the write
-// // end of the pipe.
-// //
-// SyscallException ex(__FILE__, __LINE__);
-// ex.error = getSystemErrno();
-// ostringstream s;
-// s << "can't redirect stderr to the pipe output";
-// write(fds[1], s.str().c_str(), s.str().length());
-// close(fds[1]);
-// _exit(EXIT_FAILURE);
-// }
-// }
+ delete[] envs;
//
// Change working directory.
//
- if(!pwd.empty())
+ if(strlen(pwdCStr) != 0)
{
- if(chdir(pwd.c_str()) == -1)
+ if(chdir(pwdCStr) == -1)
{
- //
- // Send any errors to the parent process, using the write
- // end of the pipe.
- //
- SyscallException ex(__FILE__, __LINE__);
- ex.error = getSystemErrno();
- ostringstream s;
- s << "can't change working directory to `" << pwd << "':\n" << ex;
- write(fds[1], s.str().c_str(), s.str().length());
- close(fds[1]);
- _exit(EXIT_FAILURE);
+ reportChildError(errno, fds[1], "cannot change working directory to", pwdCStr);
}
}
if(execvp(argv[0], argv) == -1)
{
- //
- // Send any errors to the parent process, using the write
- // end of the pipe.
- //
- SyscallException ex(__FILE__, __LINE__);
- ex.error = getSystemErrno();
- ostringstream s;
- s << "can't execute `" << path << "':\n" << ex;
- write(fds[1], s.str().c_str(), s.str().length());
- close(fds[1]);
- _exit(EXIT_FAILURE);
+ reportChildError(errno, fds[1], "cannot execute", argv[0]);
}
}
else // Parent process.
{
close(fds[1]);
+ for(i = 0; i < envCount; ++i)
+ {
+ free(envs[i]);
+ }
+ delete[] envs;
+
Process process;
process.pid = pid;
- process.fd = fds[0];
+ process.pipeFd = fds[0];
+ process.outFd = outFd;
+ process.errFd = errFd;
process.server = server;
_processes.push_back(process);
- int flags = fcntl(process.fd, F_GETFL);
+ int flags = fcntl(process.pipeFd, F_GETFL);
flags |= O_NONBLOCK;
- fcntl(process.fd, F_SETFL, flags);
+ fcntl(process.pipeFd, F_SETFL, flags);
setInterrupt();
@@ -561,6 +882,7 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
void
IcePack::ActivatorI::deactivate(const ServerPtr& server)
{
+#ifdef _WIN32
Ice::Int pid = server->getPid();
if(pid == 0)
@@ -571,7 +893,6 @@ IcePack::ActivatorI::deactivate(const ServerPtr& server)
return;
}
-#ifdef _WIN32
//
// Generate a Ctrl+Break event on the child.
//
@@ -593,33 +914,15 @@ IcePack::ActivatorI::deactivate(const ServerPtr& server)
//
// Send a SIGTERM to the process.
//
-
-#ifdef __linux
- //
- // Use process groups on Linux instead of processes
- //
- int ret = ::killpg(static_cast<pid_t>(pid), SIGTERM);
-#else
- int ret = ::kill(static_cast<pid_t>(pid), SIGTERM);
-#endif
- if(ret != 0 && getSystemErrno() != ESRCH)
- {
- SyscallException ex(__FILE__, __LINE__);
- ex.error = getSystemErrno();
- throw ex;
- }
-
- if(_traceLevels->activator > 1)
- {
- Ice::Trace out(_traceLevels->logger, _traceLevels->activatorCat);
- out << "sent SIGTERM to server `" << server->description.name << "' (pid = " << pid << ")";
- }
+ sendSignal(server, SIGTERM);
+
#endif
}
void
IcePack::ActivatorI::kill(const ServerPtr& server)
{
+#ifdef _WIN32
Ice::Int pid = server->getPid();
if(pid == 0)
@@ -630,7 +933,6 @@ IcePack::ActivatorI::kill(const ServerPtr& server)
return;
}
-#ifdef _WIN32
HANDLE hnd = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
if(hnd == NULL)
{
@@ -655,15 +957,43 @@ IcePack::ActivatorI::kill(const ServerPtr& server)
Ice::Trace out(_traceLevels->logger, _traceLevels->activatorCat);
out << "terminating server `" << server->description.name << "' (pid = " << pid << ")";
}
+
#else
+ sendSignal(server, SIGKILL);
+#endif
+}
+
+
+void
+IcePack::ActivatorI::sendSignal(const ServerPtr& server, const string& signal)
+{
+ sendSignal(server, stringToSignal(signal));
+}
+void
+IcePack::ActivatorI::sendSignal(const ServerPtr& server, int signal)
+{
+#ifdef _WIN32
//
- // Send a SIGKILL to the process.
+ // TODO: Win32 implementation?
//
+ throw BadSignalException();
+
+#else
+ Ice::Int pid = server->getPid();
+
+ if(pid == 0)
+ {
+ //
+ // Server is already deactivated.
+ //
+ return;
+ }
+
#ifdef __linux
// Use process groups on Linux instead of processes
- int ret = ::killpg(static_cast<pid_t>(pid), SIGKILL);
+ int ret = ::killpg(static_cast<pid_t>(pid), signal);
#else
- int ret = ::kill(static_cast<pid_t>(pid), SIGKILL);
+ int ret = ::kill(static_cast<pid_t>(pid), signal);
#endif
if(ret != 0 && getSystemErrno() != ESRCH)
{
@@ -675,11 +1005,69 @@ IcePack::ActivatorI::kill(const ServerPtr& server)
if(_traceLevels->activator > 1)
{
Ice::Trace out(_traceLevels->logger, _traceLevels->activatorCat);
- out << "sent SIGKILL to server `" << server->description.name << "' (pid = " << pid << ")";
+ out << "sent " << signalToString(signal) << " to server `"
+ << server->description.name << "' (pid = " << pid << ")";
}
#endif
}
+void
+IcePack::ActivatorI::writeMessage(const ServerPtr& server, const string& message, Ice::Int fd)
+{
+ assert(fd == 1 || fd == 2);
+
+ string msg = message + "\n";
+
+#ifdef _WIN32
+ HANDLE handle = 0;
+#else
+ int actualFd = -1;
+#endif
+ {
+ IceUtil::Monitor< IceUtil::Mutex>::Lock sync(*this);
+
+ for(vector<Process>::iterator p = _processes.begin(); p != _processes.end(); ++p)
+ {
+ if(p->server == server)
+ {
+#ifdef _WIN32
+ handle = (fd == 1 ? p->outHandle : p->errHandle);
+#else
+ actualFd = (fd == 1 ? p->outFd : p->errFd);
+#endif
+ break; // for
+ }
+ }
+ }
+
+#ifdef _WIN32
+ if(handle != 0)
+ {
+ DWORD written = 0;
+ if(!WriteFile(handle, msg.c_str(), msg.size(), &written, NULL))
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ assert(written == msg.size());
+ }
+#else
+ if(actualFd > 0)
+ {
+ ssize_t written = write(actualFd, msg.c_str(), msg.size());
+ if(written == -1)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ assert(written == static_cast<ssize_t>(msg.size()));
+ }
+#endif
+}
+
+
Ice::Int
IcePack::ActivatorI::getServerPid(const ServerPtr& server)
{
@@ -870,11 +1258,17 @@ IcePack::ActivatorI::terminationListener()
<< "' termination:\n" << ex;
}
+ CloseHandle(hnd);
+ CloseHandle(p->outHandle);
+ if(!_redirectErrToOut)
+ {
+ CloseHandle(p->errHandle);
+ }
_processes.erase(p);
break;
}
}
- CloseHandle(hnd);
+
}
if(_deactivating && _processes.empty())
@@ -895,7 +1289,7 @@ IcePack::ActivatorI::terminationListener()
for(vector<Process>::iterator p = _processes.begin(); p != _processes.end(); ++p)
{
- int fd = p->fd;
+ int fd = p->pipeFd;
FD_SET(fd, &fdSet);
if(maxFd < fd)
{
@@ -943,7 +1337,7 @@ IcePack::ActivatorI::terminationListener()
vector<Process>::iterator p = _processes.begin();
while(p != _processes.end())
{
- int fd = p->fd;
+ int fd = p->pipeFd;
if(!FD_ISSET(fd, &fdSet))
{
++p;
@@ -996,8 +1390,16 @@ IcePack::ActivatorI::terminationListener()
<< "' termination:\n" << ex;
}
+ if(p->errFd != p->outFd && p->errFd != STDERR_FILENO)
+ {
+ close(p->errFd);
+ }
+ if(p->outFd != STDOUT_FILENO)
+ {
+ close(p->outFd);
+ }
+ close(p->pipeFd);
p = _processes.erase(p);
- close(fd);
//
// We are deactivating and there's no more active processes. We can now