summaryrefslogtreecommitdiff
path: root/cpp/src/IceGrid/Activator.cpp
diff options
context:
space:
mode:
authorBernard Normier <bernard@zeroc.com>2009-01-23 17:07:21 -0500
committerBernard Normier <bernard@zeroc.com>2009-01-23 17:07:21 -0500
commit2380e089401d048490da23bc6d71e5687bafbe47 (patch)
tree6d97052d1f93bc2bafcd7fd1a9ebe103544b6cad /cpp/src/IceGrid/Activator.cpp
parentFixed permissions (diff)
parent3.3.1 third-party updates (diff)
downloadice-2380e089401d048490da23bc6d71e5687bafbe47.tar.bz2
ice-2380e089401d048490da23bc6d71e5687bafbe47.tar.xz
ice-2380e089401d048490da23bc6d71e5687bafbe47.zip
Merge branch 'R3_3_branch' of cvs:/home/git/ice into R3_3_branch
Conflicts: java/resources/IceGridAdmin/icegridadmin_content_dyn.html java/resources/IceGridAdmin/icegridadmin_content_static.html
Diffstat (limited to 'cpp/src/IceGrid/Activator.cpp')
-rw-r--r--cpp/src/IceGrid/Activator.cpp169
1 files changed, 119 insertions, 50 deletions
diff --git a/cpp/src/IceGrid/Activator.cpp b/cpp/src/IceGrid/Activator.cpp
index d585a11eb15..0b99b68a417 100644
--- a/cpp/src/IceGrid/Activator.cpp
+++ b/cpp/src/IceGrid/Activator.cpp
@@ -1,6 +1,6 @@
// **********************************************************************
//
-// Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved.
+// Copyright (c) 2003-2009 ZeroC, Inc. All rights reserved.
//
// This copy of Ice is licensed to you under the terms described in the
// ICE_LICENSE file included in this distribution.
@@ -514,8 +514,7 @@ Activator::activate(const string& name,
string::size_type pos = s.find('=');
if(pos != string::npos)
{
- string key = s.substr(0, pos);
- std::transform(key.begin(), key.end(), key.begin(), toupper);
+ string key = IceUtilInternal::toUpper(s.substr(0, pos));
envMap.insert(map<string, string>::value_type(key, s.substr(pos + 1)));
}
var += s.size();
@@ -528,8 +527,7 @@ Activator::activate(const string& name,
string::size_type pos = s.find('=');
if(pos != string::npos)
{
- string key = s.substr(0, pos);
- std::transform(key.begin(), key.end(), key.begin(), toupper);
+ string key = IceUtilInternal::toUpper(s.substr(0, pos));
envMap.erase(key);
envMap.insert(map<string, string>::value_type(key, s.substr(pos + 1)));
}
@@ -610,6 +608,15 @@ Activator::activate(const string& name,
throw ex;
}
+ int errorFds[2];
+ if(pipe(errorFds) != 0)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+
+
//
// Convert to standard argc/argv.
//
@@ -652,14 +659,14 @@ Activator::activate(const string& name,
{
ostringstream os;
os << gid;
- reportChildError(getSystemErrno(), fds[1], "cannot set process group id", os.str().c_str());
+ reportChildError(getSystemErrno(), errorFds[1], "cannot set process group id", os.str().c_str());
}
if(setuid(uid) == -1)
{
ostringstream os;
os << uid;
- reportChildError(getSystemErrno(), fds[1], "cannot set process user id", os.str().c_str());
+ reportChildError(getSystemErrno(), errorFds[1], "cannot set process user id", os.str().c_str());
}
//
@@ -675,7 +682,7 @@ Activator::activate(const string& name,
int maxFd = static_cast<int>(sysconf(_SC_OPEN_MAX));
for(int fd = 3; fd < maxFd; ++fd)
{
- if(fd != fds[1])
+ if(fd != fds[1] && fd != errorFds[1])
{
close(fd);
}
@@ -688,7 +695,7 @@ Activator::activate(const string& name,
//
if(putenv(strdup(env.argv[i])) != 0)
{
- reportChildError(errno, fds[1], "cannot set environment variable", env.argv[i]);
+ reportChildError(errno, errorFds[1], "cannot set environment variable", env.argv[i]);
}
}
@@ -699,18 +706,65 @@ Activator::activate(const string& name,
{
if(chdir(pwdCStr) == -1)
{
- reportChildError(errno, fds[1], "cannot change working directory to", pwdCStr);
+ reportChildError(errno, errorFds[1], "cannot change working directory to", pwdCStr);
}
}
+ //
+ // Close on exec the error message file descriptor.
+ //
+ int flags = fcntl(errorFds[1], F_GETFD);
+ flags |= 1; // FD_CLOEXEC
+ if(fcntl(errorFds[1], F_SETFD, flags) == -1)
+ {
+ close(errorFds[1]);
+ errorFds[1] = -1;
+ }
+
if(execvp(av.argv[0], av.argv) == -1)
{
- reportChildError(errno, fds[1], "cannot execute", av.argv[0]);
+ if(errorFds[1] != -1)
+ {
+ reportChildError(errno, errorFds[1], "cannot execute", av.argv[0]);
+ }
+ else
+ {
+ reportChildError(errno, fds[1], "cannot execute", av.argv[0]);
+ }
}
}
else // Parent process.
{
close(fds[1]);
+ close(errorFds[1]);
+
+ //
+ // Read a potential error message over the error message pipe.
+ //
+ char s[16];
+ ssize_t rs;
+ string message;
+ while((rs = read(errorFds[0], &s, 16)) > 0)
+ {
+ message.append(s, rs);
+ }
+
+ //
+ // If an error occured before the exec() we do some cleanup and throw.
+ //
+ if(!message.empty())
+ {
+ close(fds[0]);
+ close(errorFds[0]);
+ waitPid(pid);
+ throw message;
+ }
+
+ //
+ // Otherwise, the exec() was successfull and we don't need the error message
+ // pipe anymore.
+ //
+ close(errorFds[0]);
Process process;
process.pid = pid;
@@ -1005,6 +1059,13 @@ Activator::destroy()
assert(_processes.empty());
}
+bool
+Activator::isActive()
+{
+ IceUtil::Monitor< IceUtil::Mutex>::Lock sync(*this);
+ return !_deactivating;
+}
+
void
Activator::runTerminationListener()
{
@@ -1245,45 +1306,7 @@ Activator::terminationListener()
for(vector<Process>::const_iterator p = terminated.begin(); p != terminated.end(); ++p)
{
- int status;
-#if defined(__linux)
- int nRetry = 0;
- while(true) // The while loop is necessary for the linux workaround.
- {
- pid_t pid = waitpid(p->pid, &status, 0);
- if(pid < 0)
- {
- //
- // Some Linux distribution have a bogus waitpid() (e.g.: CentOS 4.x). It doesn't
- // block and reports an incorrect ECHILD error on the first call. We sleep a
- // little and retry to work around this issue (it appears from testing that a
- // single retry is enough but to make sure we retry up to 10 times before to throw.)
- //
- if(errno == ECHILD && nRetry < 10)
- {
- // Wait 1ms, 11ms, 21ms, etc.
- IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(nRetry * 10 + 1));
- ++nRetry;
- continue;
- }
- SyscallException ex(__FILE__, __LINE__);
- ex.error = getSystemErrno();
- throw ex;
- }
- assert(pid == p->pid);
- break;
- }
-#else
- pid_t pid = waitpid(p->pid, &status, 0);
- if(pid < 0)
- {
- SyscallException ex(__FILE__, __LINE__);
- ex.error = getSystemErrno();
- throw ex;
- }
- assert(pid == p->pid);
-#endif
-
+ int status = waitPid(p->pid);
if(_traceLevels->activator > 0)
{
Ice::Trace out(_traceLevels->logger, _traceLevels->activatorCat);
@@ -1343,3 +1366,49 @@ Activator::setInterrupt()
write(_fdIntrWrite, &c, 1);
#endif
}
+
+#ifndef _WIN32
+int
+Activator::waitPid(pid_t processPid)
+{
+ int status;
+#if defined(__linux)
+ int nRetry = 0;
+ while(true) // The while loop is necessary for the linux workaround.
+ {
+ pid_t pid = waitpid(processPid, &status, 0);
+ if(pid < 0)
+ {
+ //
+ // Some Linux distribution have a bogus waitpid() (e.g.: CentOS 4.x). It doesn't
+ // block and reports an incorrect ECHILD error on the first call. We sleep a
+ // little and retry to work around this issue (it appears from testing that a
+ // single retry is enough but to make sure we retry up to 10 times before to throw.)
+ //
+ if(errno == ECHILD && nRetry < 10)
+ {
+ // Wait 1ms, 11ms, 21ms, etc.
+ IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(nRetry * 10 + 1));
+ ++nRetry;
+ continue;
+ }
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ assert(pid == processPid);
+ break;
+ }
+#else
+ pid_t pid = waitpid(processPid, &status, 0);
+ if(pid < 0)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ assert(pid == processPid);
+#endif
+ return status;
+}
+#endif