diff options
Diffstat (limited to 'logforwarder/src/apps/vespa-otelcol-start/child-handler.cpp')
-rw-r--r-- | logforwarder/src/apps/vespa-otelcol-start/child-handler.cpp | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/logforwarder/src/apps/vespa-otelcol-start/child-handler.cpp b/logforwarder/src/apps/vespa-otelcol-start/child-handler.cpp new file mode 100644 index 00000000000..46ac3bea60e --- /dev/null +++ b/logforwarder/src/apps/vespa-otelcol-start/child-handler.cpp @@ -0,0 +1,88 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "child-handler.h" + +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include <sys/wait.h> +#include <vector> +#include <string> +#include <cstdlib> + +#include <vespa/log/log.h> +LOG_SETUP(".child-handler"); + +ChildHandler::ChildHandler() : _childRunning(false), _childPid(0) {} + +ChildHandler::~ChildHandler() = default; + +bool ChildHandler::checkChild() { + if (! _childRunning) return true; + int waitStatus = 0; + int r = waitpid(_childPid, &waitStatus, WNOHANG); + if (r == 0) { + return false; + } + if (r < 0) { + perror("waitpid"); + // XXX how to handle? + return false; + } + _childRunning = false; + if (WIFEXITED(waitStatus) && WEXITSTATUS(waitStatus) == 0) { + // all OK + LOG(info, "child ran ok, exit status 0"); + } else if (WIFEXITED(waitStatus)) { + LOG(warning, "child failed (exit status %d)", WEXITSTATUS(waitStatus)); + } else if (WIFSIGNALED(waitStatus)) { + if (_terminating) { + LOG(info, "child terminated (using signal %d)", WTERMSIG(waitStatus)); + } else { + LOG(warning, "child failed (exit on signal %d)", WTERMSIG(waitStatus)); + } + } else { + LOG(warning, "child failed (abnormal exit status %d)", waitStatus); + } + return true; +} + +void ChildHandler::startChild(const std::string &progPath, const std::string &cfPath) { + _terminating = false; + LOG(info, "startChild '%s' '%s'", progPath.c_str(), cfPath.c_str()); + pid_t child = fork(); + if (child == -1) { + perror("fork()"); + return; + } + if (child == 0) { + std::string cfArg{"--config=file:" + cfPath}; + const char *cargv[] = { progPath.c_str(), cfArg.c_str(), nullptr }; + execv(progPath.c_str(), const_cast<char **>(cargv)); + // if execv fails: + perror(progPath.c_str()); + std::_Exit(1); + } + LOG(info, "child running with pid %d", (int)child); + _childRunning = true; + _childPid = child; +} + +void ChildHandler::stopChild() { + if (! _childRunning) return; + LOG(info, "stopChild"); + _terminating = true; + kill(_childPid, SIGTERM); + for (int retry = 0; retry < 10; ++retry) { + if (checkChild()) return; + usleep(12500 + retry * 20000); + } + kill(_childPid, SIGKILL); + for (int retry = 0; retry < 10; ++retry) { + if (checkChild()) return; + usleep(12500 + retry * 20000); + } + LOG(error, "Could not terminete child process %d", _childPid); +} |