Ejemplo n.º 1
0
ProcessManagerImpl::ProcessManagerImpl(Application& app)
    : mApp(app)
    , mSigChild(app.getClock().getIOService(), SIGCHLD)
    , mImplsSize(app.getMetrics().NewCounter({"process", "memory", "handles"}))
{
    std::lock_guard<std::recursive_mutex> guard(gImplsMutex);
    startSignalWait();
}
Ejemplo n.º 2
0
    void processRequest()
    {
        std::cout << "Incoming request message: " << message_ << std::endl;
        signal_.reset();

        std::cout << "Setting the signal set" << std::endl;
        signal_ = boost::shared_ptr<boost::asio::signal_set>(new boost::asio::signal_set(requestService_, SIGCHLD));

        std::cout << "Informing the io_services of the pending fork" << std::endl;
        requestService_.notify_fork(boost::asio::io_service::fork_prepare);
        responseService_.notify_fork(boost::asio::io_service::fork_prepare);

        pid_t pid = fork();
        if (pid == 0)
        {
            // this is the child process
            std::cout << "[child] Informing the child io_services of the completed fork" << std::endl;
            requestService_.notify_fork(boost::asio::io_service::fork_child);
            responseService_.notify_fork(boost::asio::io_service::fork_child);

            std::cout << "[child] Canceling the signal on the child" << std::endl;
            signal_->cancel();

            std::cout << "[child] Exec-ing the new process" << std::endl;
            const char* cmd = "/bin/sleep";
            const char* arg1 = "5";
            execl(cmd, cmd, arg1, NULL);

            // the execl call only returns if an error has occurred,
            // so exit immediately
            exit(-1);
        }
        else
        {
            // we are the parent (or there was an error in fork)
            std::cout << "[parent] Informing the parent io_services of the completed fork" << std::endl;
            requestService_.notify_fork(boost::asio::io_service::fork_parent);
            responseService_.notify_fork(boost::asio::io_service::fork_parent);

            if (pid > 0)
            {
                std::cout << "[parent] Capturing the child pid (" << pid << ")" << std::endl;
                childPid_ = pid;

                startSignalWait();
            }
        }
    }
Ejemplo n.º 3
0
    void handleSignal(const boost::system::error_code& ec)
    {
        std::cout << "handling the SIGCHLD signal" << std::endl;
        int status;
        if (waitpid(childPid_, &status, 0) > 0)
        {
        	std::cout << "got a signal on the child" << std::endl;
            int exitCode = -1;
            if (WIFEXITED(status))
            {
                exitCode = WEXITSTATUS(status);
            }

            std::cout << "posting the response back" << std::endl;
            boost::shared_ptr<Response> response(boost::shared_ptr<Response>(new Response(exitCode)));
            responseService_.post(boost::bind(&Response::processResponse, response));
        }
        else
        {
        	startSignalWait();
        }
    }
Ejemplo n.º 4
0
void
ProcessManagerImpl::handleSignalWait()
{
    std::lock_guard<std::recursive_mutex> guard(gImplsMutex);
    for (;;)
    {
        int status = 0;
        int pid = waitpid(-1, &status, WNOHANG);
        if (pid > 0)
        {
            auto pair = gImpls.find(pid);
            assert(pair != gImpls.end());
            auto impl = pair->second;

            asio::error_code ec;
            if (WIFEXITED(status))
            {
                if (WEXITSTATUS(status) == 0)
                {
                    CLOG(DEBUG, "Process") << "process " << pid << " exited "
                                           << WEXITSTATUS(status) << ": "
                                           << impl->mCmdLine;
                }
                else
                {
                    CLOG(WARNING, "Process") << "process " << pid << " exited "
                                             << WEXITSTATUS(status) << ": "
                                             << impl->mCmdLine;
                }
#ifdef __linux__
                // Linux posix_spawnp does not fault on file-not-found in the
                // parent process at the point of invocation, as BSD does; so
                // rather than a fatal error / throw we get an ambiguous and
                // easily-overlooked shell-like 'exit 127' on waitpid.
                if (WEXITSTATUS(status) == 127)
                {
                    CLOG(WARNING, "Process") << "";
                    CLOG(WARNING, "Process") << "************";
                    CLOG(WARNING, "Process") << "";
                    CLOG(WARNING, "Process") << "  likely 'missing command':";
                    CLOG(WARNING, "Process") << "";
                    CLOG(WARNING, "Process") << "    " << impl->mCmdLine;
                    CLOG(WARNING, "Process") << "";
                    CLOG(WARNING, "Process") << "************";
                    CLOG(WARNING, "Process") << "";
                }
#endif
                // FIXME: this doesn't _quite_ do the right thing; it conveys
                // the exit status back to the caller but it puts it in "system
                // category" which on POSIX means if you call .message() on it
                // you'll get perror(value()), which is not correct. Errno has
                // nothing to do with process exit values. We could make a new
                // error_category to tighten this up, but it's a bunch of work
                // just to convey the meaningless string "exited" to the user.
                ec = asio::error_code(WEXITSTATUS(status),
                                      asio::system_category());
            }
            else
            {
                // FIXME: for now we also collapse all non-WIFEXITED exits on
                // posix into a single "exit 1" error_code. This is enough
                // for most callers; we can enrich it if anyone really wants
                // to differentiate various signals that might have killed
                // the child.
                ec = asio::error_code(1, asio::system_category());
            }

            --gNumProcessesActive;
            gImpls.erase(pair);
            *(impl->mOuterEc) = ec;
            impl->mOuterTimer->cancel();
        }
        else
        {
            break;
        }
    }
    mImplsSize.set_count(gImpls.size());
    maybeRunPendingProcesses();
    startSignalWait();
}