diff options
author | Benoit Foucher <benoit@zeroc.com> | 2002-06-28 19:20:18 +0000 |
---|---|---|
committer | Benoit Foucher <benoit@zeroc.com> | 2002-06-28 19:20:18 +0000 |
commit | 75ac12c02d537f38b03567e406cbeccf29226fe0 (patch) | |
tree | 4add4682e2aa8edd9c58f1a23ad3f0ccc8336d02 /cpp/src/IcePack/ActivatorI.cpp | |
parent | Replaced invalid struct name Struct with Structure. (diff) | |
download | ice-75ac12c02d537f38b03567e406cbeccf29226fe0.tar.bz2 ice-75ac12c02d537f38b03567e406cbeccf29226fe0.tar.xz ice-75ac12c02d537f38b03567e406cbeccf29226fe0.zip |
Merged location branch.
Diffstat (limited to 'cpp/src/IcePack/ActivatorI.cpp')
-rw-r--r-- | cpp/src/IcePack/ActivatorI.cpp | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/cpp/src/IcePack/ActivatorI.cpp b/cpp/src/IcePack/ActivatorI.cpp new file mode 100644 index 00000000000..1a522510090 --- /dev/null +++ b/cpp/src/IcePack/ActivatorI.cpp @@ -0,0 +1,382 @@ +// ********************************************************************** +// +// Copyright (c) 2001 +// MutableRealms, Inc. +// Huntsville, AL, USA +// +// All Rights Reserved +// +// ********************************************************************** + +#ifdef _WIN32 +# error Sorry, the IcePack Activator is not yet supported on WIN32. +#endif + +#include <Ice/Ice.h> +#include <IcePack/ActivatorI.h> +#include <IcePack/Admin.h> +#include <IcePack/ServerManager.h> +#include <fcntl.h> + +using namespace std; +using namespace Ice; +using namespace IcePack; + +IcePack::ActivatorI::ActivatorI(const CommunicatorPtr& communicator, const vector<string>& defaultArgs) : + _communicator(communicator), + _destroy(false), + _defaultArgs(defaultArgs) +{ + int fds[2]; + if(pipe(fds) != 0) + { + SystemException ex(__FILE__, __LINE__); + ex.error = getSystemErrno(); + throw ex; + } + _fdIntrRead = fds[0]; + _fdIntrWrite = fds[1]; + int flags = fcntl(_fdIntrRead, F_GETFL); + flags |= O_NONBLOCK; + fcntl(_fdIntrRead, F_SETFL, flags); +} + +IcePack::ActivatorI::~ActivatorI() +{ + assert(_destroy); + close(_fdIntrRead); + close(_fdIntrWrite); + for(vector<Process>::iterator p = _processes.begin(); p != _processes.end(); ++p) + { + close(p->fd); + } +} + +void +IcePack::ActivatorI::run() +{ + try + { + terminationListener(); + } + catch(const Exception& ex) + { + Error out(_communicator->getLogger()); + out << "exception in process termination listener:\n" << ex; + } + catch(...) + { + Error out(_communicator->getLogger()); + out << "unknown exception in process termination listener"; + } +} + +void +IcePack::ActivatorI::destroy() +{ + IceUtil::Mutex::Lock sync(*this); + + if(_destroy) // Don't destroy twice. + { + return; + } + + _destroy = true; + setInterrupt(); +} + +bool +IcePack::ActivatorI::activate(const ServerPrx& server, const ::Ice::Current&) +{ + IceUtil::Mutex::Lock sync(*this); + + if(_destroy) + { + return false; + } + + ServerDescription desc = server->getServerDescription(); + + string path = desc.path; + if(path.empty()) + { + return false; + } + + // + // Normalize the pathname a bit. + // + string::size_type pos; + while((pos = path.find("//")) != string::npos) + { + path.erase(pos, 1); + } + while((pos = path.find("/./")) != string::npos) + { + path.erase(pos, 2); + } + + // + // Process does not exist, activate and create. + // + int fds[2]; + if(pipe(fds) != 0) + { + SystemException ex(__FILE__, __LINE__); + ex.error = getSystemErrno(); + throw ex; + } + pid_t pid = fork(); + if(pid == -1) + { + SystemException ex(__FILE__, __LINE__); + ex.error = getSystemErrno(); + throw ex; + } + if(pid == 0) // Child process. + { + // + // Close all filedescriptors, except for standard input, + // standard output, standard error output, and the write side + // of the newly created pipe. + // + int maxFd = static_cast<int>(sysconf(_SC_OPEN_MAX)); + for(int fd = 3; fd < maxFd; ++fd) + { + if(fd != fds[1]) + { + close(fd); + } + } + + // + // Change working directory. + // + string pwd = desc.pwd; + if(!pwd.empty()) + { + string::size_type pos; + while((pos = pwd.find("//")) != string::npos) + { + pwd.erase(pos, 1); + } + while((pos = pwd.find("/./")) != string::npos) + { + pwd.erase(pos, 2); + } + + if(chdir(pwd.c_str()) == -1) + { + // + // Send any errors to the parent process, using the write + // end of the pipe. + // + SystemException 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); + } + } + + // + // Compute arguments. + // + int argc = desc.args.size() + _defaultArgs.size() + 2; + char** argv = static_cast<char**>(malloc(argc * sizeof(char*))); + argv[0] = strdup(path.c_str()); + unsigned int i = 0; + vector<string>::const_iterator q; + for(q = desc.args.begin(); q != desc.args.end(); ++q, ++i) + { + argv[i + 1] = strdup(q->c_str()); + } + for(q = _defaultArgs.begin(); q != _defaultArgs.end(); ++q, ++i) + { + argv[i + 1] = strdup(q->c_str()); + } + argv[argc - 1] = 0; + + if(execvp(argv[0], argv) == -1) + { + // + // Send any errors to the parent process, using the write + // end of the pipe. + // + SystemException 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); + } + } + else // Parent process. + { + close(fds[1]); + + Process process; + process.pid = pid; + process.fd = fds[0]; + process.server = server; + _processes.push_back(process); + + int flags = fcntl(process.fd, F_GETFL); + flags |= O_NONBLOCK; + fcntl(process.fd, F_SETFL, flags); + + setInterrupt(); + } + + return true; +} + +void +IcePack::ActivatorI::terminationListener() +{ + while(true) + { + fd_set fdSet; + int maxFd = _fdIntrRead; + FD_ZERO(&fdSet); + FD_SET(_fdIntrRead, &fdSet); + + { + IceUtil::Mutex::Lock sync(*this); + + if(_destroy) + { + return; + } + + for(vector<Process>::iterator p = _processes.begin(); p != _processes.end(); ++p) + { + int fd = p->fd; + FD_SET(fd, &fdSet); + if(maxFd < fd) + { + maxFd = fd; + } + } + } + + repeatSelect: + int ret = ::select(maxFd + 1, &fdSet, 0, 0, 0); + assert(ret != 0); + + if(ret == -1) + { + if(errno == EINTR || errno == EPROTO) + { + goto repeatSelect; + } + + SystemException ex(__FILE__, __LINE__); + ex.error = getSystemErrno(); + throw ex; + } + + { + IceUtil::Mutex::Lock sync(*this); + + if(FD_ISSET(_fdIntrRead, &fdSet)) + { + clearInterrupt(); + } + + if(_destroy) + { + return; + } + + vector<Process>::iterator p = _processes.begin(); + while(p != _processes.end()) + { + int fd = p->fd; + if(FD_ISSET(fd, &fdSet)) + { + char s[16]; + int ret; + string message; + + // + // Read the message over the pipe. + // + while((ret = read(fd, &s, 16)) > 0) + { + message.append(s, ret); + } + + if(ret == -1) + { + if(errno != EAGAIN || message.empty()) + { + SystemException ex(__FILE__, __LINE__); + ex.error = getSystemErrno(); + throw ex; + } + + ++p; + } + else if(ret == 0) + { + ServerPrx server = p->server; + + // + // If the pipe was closed, the process has + // terminated. + // + p = _processes.erase(p); + close(fd); + + // + // Notify the server it has terminated. + // + try + { + server->terminationCallback(); + } + catch(const Ice::ObjectAdapterDeactivatedException&) + { + // + // Expected when IcePack is shutdown. + // + } + } + + // + // Log the received message. + // + if(!message.empty()) + { + Error out(_communicator->getLogger()); + out << message; + } + } + else + { + ++p; + } + } + } + } +} + +void +IcePack::ActivatorI::clearInterrupt() +{ + char s[32]; // Clear up to 32 interrupts at once. + while(read(_fdIntrRead, s, 32) == 32) + { + } +} + +void +IcePack::ActivatorI::setInterrupt() +{ + char c = 0; + write(_fdIntrWrite, &c, 1); +} |