diff options
author | Håvard Pettersen <havardpe@oath.com> | 2022-03-04 13:38:36 +0000 |
---|---|---|
committer | Håvard Pettersen <havardpe@oath.com> | 2022-03-05 15:00:58 +0000 |
commit | 2681bcd99a024d0e94c2cddd08b7636818773a73 (patch) | |
tree | fe8466205ba79ea6b7ab89008247070f88cd918f /fastos | |
parent | beed3becc8ec1abe88aea8aa88e6e703fb67dc3c (diff) |
gc old process code
also added read_line function to new Process code
Diffstat (limited to 'fastos')
-rw-r--r-- | fastos/src/tests/CMakeLists.txt | 6 | ||||
-rw-r--r-- | fastos/src/tests/filetest.cpp | 2 | ||||
-rw-r--r-- | fastos/src/tests/processtest.cpp | 292 | ||||
-rw-r--r-- | fastos/src/vespa/fastos/CMakeLists.txt | 3 | ||||
-rw-r--r-- | fastos/src/vespa/fastos/app.cpp | 54 | ||||
-rw-r--r-- | fastos/src/vespa/fastos/app.h | 17 | ||||
-rw-r--r-- | fastos/src/vespa/fastos/process.cpp | 16 | ||||
-rw-r--r-- | fastos/src/vespa/fastos/process.h | 180 | ||||
-rw-r--r-- | fastos/src/vespa/fastos/unix_app.cpp | 53 | ||||
-rw-r--r-- | fastos/src/vespa/fastos/unix_app.h | 12 | ||||
-rw-r--r-- | fastos/src/vespa/fastos/unix_ipc.cpp | 547 | ||||
-rw-r--r-- | fastos/src/vespa/fastos/unix_ipc.h | 41 | ||||
-rw-r--r-- | fastos/src/vespa/fastos/unix_process.cpp | 985 | ||||
-rw-r--r-- | fastos/src/vespa/fastos/unix_process.h | 172 |
14 files changed, 1 insertions, 2379 deletions
diff --git a/fastos/src/tests/CMakeLists.txt b/fastos/src/tests/CMakeLists.txt index dce59650973..54341ff8e9a 100644 --- a/fastos/src/tests/CMakeLists.txt +++ b/fastos/src/tests/CMakeLists.txt @@ -1,10 +1,4 @@ # Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -vespa_add_executable(fastos_processtest_app TEST - SOURCES - processtest.cpp - DEPENDS - fastos -) vespa_add_executable(fastos_filetest_app TEST SOURCES filetest.cpp diff --git a/fastos/src/tests/filetest.cpp b/fastos/src/tests/filetest.cpp index 80045269c9e..a3470810e2e 100644 --- a/fastos/src/tests/filetest.cpp +++ b/fastos/src/tests/filetest.cpp @@ -40,8 +40,6 @@ bool createFile(const char* fileName, class FileTest : public BaseTest { -private: - virtual bool useProcessStarter() const override { return true; } public: const std::string srcDir = getenv("SOURCE_DIRECTORY") ? getenv("SOURCE_DIRECTORY") : "."; const std::string roFilename = srcDir + "/hello.txt"; diff --git a/fastos/src/tests/processtest.cpp b/fastos/src/tests/processtest.cpp deleted file mode 100644 index 204b87938de..00000000000 --- a/fastos/src/tests/processtest.cpp +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include "tests.h" -#include <vespa/fastos/process.h> -#include <thread> - -using namespace std::chrono_literals; -using namespace std::chrono; - -class MyListener : public FastOS_ProcessRedirectListener -{ -private: - MyListener(const MyListener&); - MyListener& operator=(const MyListener&); - - const char *_title; - int _receivedBytes; - -public: - static int _allocCount; - static int _successCount; - static int _failCount; - static std::mutex *_counterLock; - - MyListener (const char *title) - : _title(title), - _receivedBytes(0) - { - std::lock_guard<std::mutex> guard(*_counterLock); - _allocCount++; - } - - virtual ~MyListener () - { - bool isStdout = (strcmp(_title, "STDOUT") == 0); - - const int correctByteCount = 16; - - std::lock_guard<std::mutex> guard(*_counterLock); - if(_receivedBytes == (isStdout ? correctByteCount : 0)) - _successCount++; - else - _failCount++; - - _allocCount--; - } - - void OnReceiveData (const void *data, size_t length) override - { - _receivedBytes += length; - if(data != nullptr) - { - } - else - delete(this); - } -}; - -int MyListener::_allocCount = 0; -int MyListener::_successCount = 0; -int MyListener::_failCount = 0; -std::mutex *MyListener::_counterLock = nullptr; - -class ProcessTest : public BaseTest -{ -private: - bool useProcessStarter() const override { return true; } - bool useIPCHelper() const override { return true; } - ProcessTest(const ProcessTest&); - ProcessTest& operator=(const ProcessTest&); - int GetLastError () const { return errno; } - - // Flag which indicates whether an IPC message is received - // or not. - bool _gotMessage; - int _receivedMessages; - std::mutex *_counterLock; - bool _isChild; -public: - ProcessTest () - : _gotMessage(false), - _receivedMessages(0), - _counterLock(nullptr), - _isChild(true) - { - } - - void PollWaitTest () - { - TestHeader("PollWait Test"); - - FastOS_Process *xproc = new FastOS_Process("sort"); - - if(xproc->Create()) - { - int i; - for(i=0; i<10; i++) - { - bool stillRunning; - int returnCode; - - if(!xproc->PollWait(&returnCode, &stillRunning)) - { - Progress(false, "PollWait failure: %d", - GetLastError()); - break; - } - - if(i <= 5) - Progress(stillRunning, "StillRunning = %s", - stillRunning ? "true" : "false"); - - if(!stillRunning) - { - Progress(returnCode == 0, "Process exit code: %d", - returnCode); - break; - } - - if(i == 5) - { - // Make sort quit - xproc->WriteStdin(nullptr, 0); - } - - std::this_thread::sleep_for(1s); - } - - if(i == 10) - { - Progress(false, "Timeout"); - xproc->Kill(); - } - } - delete xproc; - - PrintSeparator(); - } - - void ProcessTests (bool doKill, bool stdinPre, bool waitKill) - { - const int numLoops = 100; - const int numEachTime = 40; - - MyListener::_counterLock = new std::mutex; - - char testHeader[200]; - strcpy(testHeader, "Process Test"); - if(doKill) - strcat(testHeader, " w/Kill"); - if(!stdinPre) - strcat(testHeader, " w/open stdin"); - if(waitKill) - strcat(testHeader, " w/Wait timeout"); - - TestHeader(testHeader); - - MyListener::_allocCount = 0; - MyListener::_successCount = 0; - MyListener::_failCount = 0; - - Progress(true, "Starting processes..."); - - for(int i=0; i<numLoops; i++) - { - FastOS_ProcessInterface *procs[numEachTime]; - - int j; - for(j=0; j<numEachTime; j++) - { - FastOS_ProcessInterface *xproc = - new FastOS_Process("sort", - new MyListener("STDOUT"), - new MyListener("STDERR")); - - if(xproc->Create()) - { - const char *str = "Peter\nPaul\nMary\n"; - - if(!waitKill && stdinPre) - { - xproc->WriteStdin(str, strlen(str)); - xproc->WriteStdin(nullptr, 0); - } - - if(doKill) - { - if(!xproc->Kill()) - Progress(false, "Kill failure %d", GetLastError()); - } - - if(!waitKill && !stdinPre) - { - xproc->WriteStdin(str, strlen(str)); - xproc->WriteStdin(nullptr, 0); - } - } - else - { - Progress(false, "Process.CreateWithShell failure %d", - GetLastError()); - delete xproc; - xproc = nullptr; - } - procs[j] = xproc; - } - - for(j=0; j<numEachTime; j++) - { - FastOS_ProcessInterface *xproc = procs[j]; - if(xproc == nullptr) - continue; - - int timeOut = -1; - if(waitKill) - timeOut = 1; - - steady_clock::time_point start = steady_clock::now(); - - int returnCode; - if(!xproc->Wait(&returnCode, timeOut)) - Progress(false, "Process.Wait failure %d", GetLastError()); - else - { - int checkReturnCode = 0; - if(doKill || waitKill) - checkReturnCode = FastOS_Process::KILL_EXITCODE; - if(returnCode != checkReturnCode) - Progress(false, "returnCode = %d", returnCode); - } - - if (waitKill) { - nanoseconds elapsed = steady_clock::now() - start; - if((elapsed < 900ms) || - (elapsed > 3500ms)) - { - Progress(false, "WaitKill time = %d", duration_cast<milliseconds>(elapsed).count()); - } - } - - delete xproc; - - if(waitKill) - Progress(true, "Started %d processes", i * numEachTime + j + 1); - } - - if(!waitKill && ((i % 10) == 9)) - Progress(true, "Started %d processes", (i+1) * numEachTime); - - if(waitKill && (((i+1) * numEachTime) > 50)) - break; - } - - Progress(MyListener::_allocCount == 0, "MyListener alloc count = %d", MyListener::_allocCount); - - if (!doKill && !waitKill) { - Progress(MyListener::_successCount == (2 * numLoops * numEachTime), - "MyListener _successCount = %d", MyListener::_successCount); - - Progress(MyListener::_failCount == 0, - "MyListener _failCount = %d", MyListener::_failCount); - } - - delete MyListener::_counterLock; - MyListener::_counterLock = nullptr; - - PrintSeparator(); - } - - int Main () override - { - _isChild = false; - - printf("grep for the string '%s' to detect failures.\n\n", failString); - - PollWaitTest(); - ProcessTests(false, true, false); - ProcessTests(true, true, false); - ProcessTests(true, false, false); - ProcessTests(false, true, true); - - printf("END OF TEST (%s)\n", _argv[0]); - - return allWasOk() ? 0 : 1; - } -}; - -int main (int argc, char **argv) -{ - ProcessTest app; - setvbuf(stdout, nullptr, _IOLBF, 8192); - return app.Entry(argc, argv); -} diff --git a/fastos/src/vespa/fastos/CMakeLists.txt b/fastos/src/vespa/fastos/CMakeLists.txt index 466c4f775a4..623d931e999 100644 --- a/fastos/src/vespa/fastos/CMakeLists.txt +++ b/fastos/src/vespa/fastos/CMakeLists.txt @@ -6,13 +6,10 @@ vespa_add_library(fastos_objects OBJECT file.cpp file_rw_ops.cpp linux_file.cpp - process.cpp thread.cpp unix_app.cpp unix_dynamiclibrary.cpp unix_file.cpp - unix_ipc.cpp - unix_process.cpp unix_thread.cpp ) diff --git a/fastos/src/vespa/fastos/app.cpp b/fastos/src/vespa/fastos/app.cpp index 0482cfea616..94e467d341d 100644 --- a/fastos/src/vespa/fastos/app.cpp +++ b/fastos/src/vespa/fastos/app.cpp @@ -8,13 +8,10 @@ #include "app.h" #include "file.h" -#include "process.h" #include "thread.h" #include <cstring> #include <fcntl.h> -FastOS_ApplicationInterface *FastOS_ProcessInterface::_app = nullptr; - FastOS_ThreadPool *FastOS_ApplicationInterface::GetThreadPool () { return _threadPool; @@ -22,12 +19,9 @@ FastOS_ThreadPool *FastOS_ApplicationInterface::GetThreadPool () FastOS_ApplicationInterface::FastOS_ApplicationInterface() : _threadPool(nullptr), - _processList(nullptr), - _processListMutex(nullptr), _argc(0), _argv(nullptr) { - FastOS_ProcessInterface::_app = this; #ifdef __linux__ char * fadvise = getenv("VESPA_FADVISE_OPTIONS"); if (fadvise != nullptr) { @@ -51,7 +45,6 @@ bool FastOS_ApplicationInterface::Init () if (PreThreadInit()) { if (FastOS_Thread::InitializeClass()) { if (FastOS_File::InitializeClass()) { - _processListMutex = new std::mutex; _threadPool = new FastOS_ThreadPool(128 * 1024); rc = true; } else @@ -72,12 +65,6 @@ void FastOS_ApplicationInterface::Cleanup () delete _threadPool; _threadPool = nullptr; } - - if(_processListMutex != nullptr) { - delete _processListMutex; - _processListMutex = nullptr; - } - FastOS_File::CleanupClass(); FastOS_Thread::CleanupClass(); } @@ -97,44 +84,3 @@ int FastOS_ApplicationInterface::Entry (int argc, char **argv) return rc; } - -void -FastOS_ApplicationInterface::AddChildProcess (FastOS_ProcessInterface *node) -{ - node->_prev = nullptr; - node->_next = _processList; - - if(_processList != nullptr) - _processList->_prev = node; - - _processList = node; -} - -void -FastOS_ApplicationInterface::RemoveChildProcess (FastOS_ProcessInterface *node) -{ - if(node->_prev) - node->_prev->_next = node->_next; - else - _processList = node->_next; - - if(node->_next) - { - node->_next->_prev = node->_prev; - node->_next = nullptr; - } - - if(node->_prev != nullptr) - node->_prev = nullptr; -} - -bool -FastOS_ApplicationInterface::useProcessStarter() const -{ - return false; -} -bool -FastOS_ApplicationInterface::useIPCHelper() const -{ - return useProcessStarter(); -} diff --git a/fastos/src/vespa/fastos/app.h b/fastos/src/vespa/fastos/app.h index 8d6a0b5ecbb..6aa7a9346ed 100644 --- a/fastos/src/vespa/fastos/app.h +++ b/fastos/src/vespa/fastos/app.h @@ -12,7 +12,6 @@ #include <vespa/fastos/types.h> -class FastOS_ProcessInterface; class FastOS_ThreadPool; #include <mutex> @@ -132,18 +131,7 @@ private: FastOS_ApplicationInterface& operator=(const FastOS_ApplicationInterface&); protected: - /** - * - * Indicate if a process starter is going to be used. - * Only override this one if you are going to start other processes. - * @return true if you are going to use a process starter. - */ - virtual bool useProcessStarter() const; - virtual bool useIPCHelper() const; - FastOS_ThreadPool *_threadPool; - FastOS_ProcessInterface *_processList; - std::mutex *_processListMutex; virtual bool PreThreadInit () { return true; } @@ -195,11 +183,6 @@ public: */ virtual void Cleanup (); - void AddChildProcess (FastOS_ProcessInterface *node); - void RemoveChildProcess (FastOS_ProcessInterface *node); - std::unique_lock<std::mutex> getProcessGuard() { return std::unique_lock<std::mutex>(*_processListMutex); } - FastOS_ProcessInterface *GetProcessList () { return _processList; } - FastOS_ThreadPool *GetThreadPool (); }; diff --git a/fastos/src/vespa/fastos/process.cpp b/fastos/src/vespa/fastos/process.cpp deleted file mode 100644 index 8e4f4afdc98..00000000000 --- a/fastos/src/vespa/fastos/process.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include "process.h" - -FastOS_ProcessInterface::FastOS_ProcessInterface (const char *cmdLine, - FastOS_ProcessRedirectListener *stdoutListener, - FastOS_ProcessRedirectListener *stderrListener) : - _cmdLine(cmdLine), - _stdoutListener(stdoutListener), - _stderrListener(stderrListener), - _next(nullptr), - _prev(nullptr) -{ -} - -FastOS_ProcessInterface::~FastOS_ProcessInterface () = default; diff --git a/fastos/src/vespa/fastos/process.h b/fastos/src/vespa/fastos/process.h deleted file mode 100644 index f520fcd30f8..00000000000 --- a/fastos/src/vespa/fastos/process.h +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -//************************************************************************ -/** - * @file - * Class definitions for FastOS_ProcessInterface and - * FastOS_ProcessRedirectListener. - * - * @author Oivind H. Danielsen - */ - -#pragma once - -#include "types.h" -#include <cstddef> -#include <string> - -/** - * This class serves as a sink for redirected (piped) output from - * subclasses of @ref FastOS_ProcessInterface. - */ -class FastOS_ProcessRedirectListener -{ -public: - /** - * This method is called when new data is available from the - * process. Subclass this method to process the data. - * You should assume that any thread can invoke this method. - * For convenience the data buffer is always zero- terminated - * (static_cast<uint8_t>(data[length]) = '\\0'). - * When the pipe closes, the method is invoked with data = nullptr - * and length = 0. - * @param data Pointer to data - * @param length Length of data block in bytes - */ - virtual void OnReceiveData (const void *data, size_t length) = 0; - - virtual ~FastOS_ProcessRedirectListener () {} -}; - -class FastOS_ThreadPool; -class FastOS_ApplicationInterface; - -/** - * This class can start a process, redirect standard input, output - * and error streams, kill process, wait for process to exit - * and send IPC messages to the process. - */ -class FastOS_ProcessInterface -{ -protected: - - std::string _cmdLine; - FastOS_ProcessRedirectListener *_stdoutListener; - FastOS_ProcessRedirectListener *_stderrListener; - -public: - FastOS_ProcessInterface *_next, *_prev; - static FastOS_ApplicationInterface *_app; - - enum Constants - { - KILL_EXITCODE = 65535, /* Process killed or failed */ - CONSTEND - }; - - /** - * Constructor. Does not start the process, use @ref Create or - * @ref CreateWithShell to actually start the process. - * @param cmdLine Command line - * @param stdoutListener non-nullptr to redirect stdout - * @param stderrListener non-nullptr to redirect stderr - * @param bufferSize Size of redirect buffers - */ - FastOS_ProcessInterface (const char *cmdLine, - FastOS_ProcessRedirectListener *stdoutListener = nullptr, - FastOS_ProcessRedirectListener *stderrListener = nullptr); - - FastOS_ProcessInterface(const FastOS_ProcessInterface&) = delete; - FastOS_ProcessInterface &operator=(const FastOS_ProcessInterface &) = delete; - /** - * Destructor. - * If @ref Wait has not been called yet, it is called here. - */ - virtual ~FastOS_ProcessInterface (); - - /** - * Create and start the process. If your command line includes - * commands specific to the shell use @ref CreateWithShell instead. - * - * IPC communication currently only supports direct parent/child - * relationships. If you launch a FastOS application through - * the shell or some other script/process, the FastOS application - * might not be a direct child of your process and IPC communication - * will not work (the rest will work ok, though). - * - * This limitation might be removed in the future. - * @return Boolean success / failure - */ - virtual bool Create() = 0; - - /** - * Create and start the process using the default OS shell - * (UNIX: /bin/sh). - * - * IPC communication currently only supports direct parent/child - * relationships. If you launch a FastOS application through - * the shell or some other script/process, the FastOS application - * might not be a direct child of your process and IPC communication - * will not work (the rest will work ok, though). - * - * This limitation might be removed in the future. - * @return Boolean success / failure - */ - virtual bool CreateWithShell() = 0; - - /** - * If you are redirecting the standard input stream of the process, - * use this method to write data. To close the input stream, - * invoke @ref WriteStdin with data=nullptr. If the input stream - * is not redirected, @ref WriteStdin will fail. - * @param data Pointer to data - * @param length Length of data block in bytes - * @return Boolean success / failure - */ - virtual bool WriteStdin (const void *data, size_t length) = 0; - - /** - * Terminate the process. !!IMPORTANT LIMITATION!!: There is no guarantee - * that child processes (of the process to be killed) will be killed - * as well. - * @return Boolean success / failure - */ - virtual bool Kill () = 0; - - /** - * Wait for the process to finish / terminate. This is called - * automatically by the destructor, but it is recommended that - * it is called as early as possible to free up resources. - * @param returnCode Pointer to int which will receive - * the process return code. - * @param timeOutSeconds Number of seconds to wait before - * the process is violently killed. - * -1 = infinite wait / no timeout - * @return Boolean success / failure - */ - virtual bool Wait (int *returnCode, int timeOutSeconds = -1) = 0; - - /** - * Poll version of @ref Wait. - * This is basically @ref Wait with a timeout of 0 seconds. - * The process is not killed if the "timeout" expires. - * A boolean value, stillRunning, is set to indicate whether - * the process is still running or not. - * There is no need to invoke @ref Wait if @ref PollWait - * indicates that the process is finished. - * @param returnCode Pointer to int which will receive - * the process return code. - * @param stillRunning Pointer to boolean value which will - * be set to indicate whether the - * process is still running or not. - * @return Boolean success / failure - */ - virtual bool PollWait (int *returnCode, bool *stillRunning) = 0; - - /** - * Get process identification number. - * @return Process id - */ - virtual unsigned int GetProcessId() = 0; - - /** - * Get command line string. - * @return Command line string - */ - const char *GetCommandLine () const { return _cmdLine.c_str(); } -}; - -#include <vespa/fastos/unix_process.h> -typedef FastOS_UNIX_Process FASTOS_PREFIX(Process); - diff --git a/fastos/src/vespa/fastos/unix_app.cpp b/fastos/src/vespa/fastos/unix_app.cpp index b0baf3990ad..e94525fff22 100644 --- a/fastos/src/vespa/fastos/unix_app.cpp +++ b/fastos/src/vespa/fastos/unix_app.cpp @@ -9,19 +9,12 @@ #include "app.h" #include "time.h" -#include "process.h" -#include "unix_ipc.h" #include <unistd.h> #include <csignal> #include <getopt.h> -FastOS_UNIX_Application::FastOS_UNIX_Application () - : _processStarter(), - _ipcHelper(nullptr) -{ -} - +FastOS_UNIX_Application::FastOS_UNIX_Application() = default; FastOS_UNIX_Application::~FastOS_UNIX_Application() = default; extern "C" @@ -72,10 +65,6 @@ bool FastOS_UNIX_Application::PreThreadInit () sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGPIPE, &act, nullptr); - - if (useProcessStarter()) { - _processStarter = std::make_unique<FastOS_UNIX_ProcessStarter>(this); - } } else { rc = false; fprintf(stderr, "FastOS_ApplicationInterface::PreThreadInit failed\n"); @@ -89,13 +78,6 @@ bool FastOS_UNIX_Application::Init () if(FastOS_ApplicationInterface::Init()) { - int ipcDescriptor = -1; - - if (useIPCHelper()) { - _ipcHelper = new FastOS_UNIX_IPCHelper(this, ipcDescriptor); - GetThreadPool()->NewThread(_ipcHelper); - } - rc = true; } @@ -104,38 +86,5 @@ bool FastOS_UNIX_Application::Init () void FastOS_UNIX_Application::Cleanup () { - if(_ipcHelper != nullptr) - _ipcHelper->Exit(); - - if (_processStarter) { - { - std::unique_lock<std::mutex> guard; - if (_processListMutex) { - guard = getProcessGuard(); - } - } - _processStarter.reset(); - } - FastOS_ApplicationInterface::Cleanup(); } - -FastOS_UNIX_ProcessStarter * -FastOS_UNIX_Application::GetProcessStarter () -{ - return _processStarter.get(); -} - -void FastOS_UNIX_Application:: -AddToIPCComm (FastOS_UNIX_Process *process) -{ - if(_ipcHelper != nullptr) - _ipcHelper->AddProcess(process); -} - -void FastOS_UNIX_Application:: -RemoveFromIPCComm (FastOS_UNIX_Process *process) -{ - if(_ipcHelper != nullptr) - _ipcHelper->RemoveProcess(process); -} diff --git a/fastos/src/vespa/fastos/unix_app.h b/fastos/src/vespa/fastos/unix_app.h index 5bb6f14ad26..5e076f4482b 100644 --- a/fastos/src/vespa/fastos/unix_app.h +++ b/fastos/src/vespa/fastos/unix_app.h @@ -13,10 +13,6 @@ #include "app.h" #include <memory> -class FastOS_UNIX_ProcessStarter; -class FastOS_UNIX_IPCHelper; -class FastOS_UNIX_Process; - /** * This is the generic UNIX implementation of @ref FastOS_ApplicationInterface */ @@ -26,9 +22,6 @@ private: FastOS_UNIX_Application(const FastOS_UNIX_Application&); FastOS_UNIX_Application& operator=(const FastOS_UNIX_Application&); - std::unique_ptr<FastOS_UNIX_ProcessStarter> _processStarter; - FastOS_UNIX_IPCHelper *_ipcHelper; - protected: bool PreThreadInit () override; public: @@ -71,11 +64,6 @@ public: */ static void resetOptIndex(int OptionIndex); - FastOS_UNIX_ProcessStarter *GetProcessStarter (); bool Init () override; void Cleanup () override; - void AddToIPCComm (FastOS_UNIX_Process *process); - void RemoveFromIPCComm (FastOS_UNIX_Process *process); }; - - diff --git a/fastos/src/vespa/fastos/unix_ipc.cpp b/fastos/src/vespa/fastos/unix_ipc.cpp deleted file mode 100644 index b75d07751fa..00000000000 --- a/fastos/src/vespa/fastos/unix_ipc.cpp +++ /dev/null @@ -1,547 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include "unix_ipc.h" -#include "ringbuffer.h" -#include <cassert> -#include <cstring> -#include <cstdlib> -#include <unistd.h> -#include <fcntl.h> -#include <memory> -#include <future> - -FastOS_UNIX_IPCHelper:: -FastOS_UNIX_IPCHelper (FastOS_ApplicationInterface *app, int) - : _lock(), - _exitFlag(false), - _app(app) -{ - _wakeupPipe[0] = -1; - _wakeupPipe[1] = -1; - - if(pipe(_wakeupPipe) != 0) { - perror("pipe wakeuppipe"); - std::_Exit(1); - } else { - SetBlocking(_wakeupPipe[0], false); - SetBlocking(_wakeupPipe[1], true); - } -} - -FastOS_UNIX_IPCHelper::~FastOS_UNIX_IPCHelper () -{ - if(_wakeupPipe[0] != -1) { - close(_wakeupPipe[0]); - } - if(_wakeupPipe[1] != -1) { - close(_wakeupPipe[1]); - } -} - - -bool FastOS_UNIX_IPCHelper:: -DoWrite(FastOS_UNIX_Process::DescriptorHandle &desc) -{ - bool rc = true; - FastOS_RingBuffer *buffer = desc._writeBuffer.get(); - - auto bufferGuard = buffer->getGuard(); - int writeBytes = buffer->GetReadSpace(); - if(writeBytes > 0) - { - int bytesWritten; - do - { - bytesWritten = write(desc._fd, - buffer->GetReadPtr(), - writeBytes); - } while(bytesWritten < 0 && errno == EINTR); - - if(bytesWritten > 0) - buffer->Consume(bytesWritten); - else if(bytesWritten < 0) - { - desc.CloseHandle(); - perror("FastOS_UNIX_IPCHelper::DoWrite"); - rc = false; - } - else if(bytesWritten == 0) - desc.CloseHandle(); - } - return rc; -} - -bool FastOS_UNIX_IPCHelper:: -DoRead (FastOS_UNIX_Process::DescriptorHandle &desc) -{ - bool rc = true; - - FastOS_RingBuffer *buffer = desc._readBuffer.get(); - - auto bufferGuard = buffer->getGuard(); - int readBytes = buffer->GetWriteSpace(); - if(readBytes > 0) { - int bytesRead; - do { - bytesRead = read(desc._fd, buffer->GetWritePtr(), readBytes); - } while(bytesRead < 0 && errno == EINTR); - - if (bytesRead > 0) { - buffer->Produce(bytesRead); - } else if(bytesRead < 0) { - desc.CloseHandle(); - perror("FastOS_UNIX_IPCHelper::DoRead"); - rc = false; - } else if(bytesRead == 0) { - desc.CloseHandle(); - } - } - - return rc; -} - -bool FastOS_UNIX_IPCHelper:: -SetBlocking (int fileDescriptor, bool doBlock) -{ - bool rc=false; - - int flags = fcntl(fileDescriptor, F_GETFL, nullptr); - if (flags != -1) - { - if(doBlock) - flags &= ~O_NONBLOCK; - else - flags |= O_NONBLOCK; - rc = (fcntl(fileDescriptor, F_SETFL, flags) != -1); - } - return rc; -} - -void FastOS_UNIX_IPCHelper:: -BuildPollCheck(bool isRead, int filedes, - FastOS_RingBuffer *buffer, bool *check) -{ - if(buffer == nullptr || - filedes < 0 || - buffer->GetCloseFlag()) { - *check = false; - return; - } - - bool setIt = false; - if(isRead) - setIt = (buffer->GetWriteSpace() > 0); - else - setIt = (buffer->GetReadSpace() > 0); - *check = setIt; -} - - -void FastOS_UNIX_IPCHelper:: -PerformAsyncIO() -{ - FastOS_ProcessInterface *node; - for(node = _app->GetProcessList(); node != nullptr; node = node->_next) - { - FastOS_UNIX_Process *xproc = static_cast<FastOS_UNIX_Process *>(node); - - for(int type=0; type < int(FastOS_UNIX_Process::TYPE_READCOUNT); type++) - { - FastOS_UNIX_Process::DescriptorType type_ = - FastOS_UNIX_Process::DescriptorType(type); - FastOS_UNIX_Process::DescriptorHandle &desc = - xproc->GetDescriptorHandle(type_); - if (desc._canRead) - (void) DoRead(desc); - if (desc._canWrite) - (void) DoWrite(desc); - } - } -} - - -void FastOS_UNIX_IPCHelper:: -BuildPollChecks() -{ - FastOS_ProcessInterface *node; - for(node = _app->GetProcessList(); node != nullptr; node = node->_next) - { - FastOS_UNIX_Process *xproc = static_cast<FastOS_UNIX_Process *>(node); - - for(int type=0; type < int(FastOS_UNIX_Process::TYPE_READCOUNT); type++) - { - FastOS_UNIX_Process::DescriptorType type_ = - FastOS_UNIX_Process::DescriptorType(type); - FastOS_UNIX_Process::DescriptorHandle &desc = - xproc->GetDescriptorHandle(type_); - BuildPollCheck(false, desc._fd, desc._writeBuffer.get(), &desc._wantWrite); - BuildPollCheck(true, desc._fd, desc._readBuffer.get(), &desc._wantRead); - } - } -} - - -static pollfd * -__attribute__((__noinline__)) -ResizePollArray(pollfd **fds, unsigned int *allocnfds) -{ - pollfd *newfds; - unsigned int newallocnfds; - - if (*allocnfds == 0) - newallocnfds = 16; - else - newallocnfds = *allocnfds * 2; - newfds = static_cast<pollfd *>(malloc(newallocnfds * sizeof(pollfd))); - assert(newfds != nullptr); - - if (*allocnfds > 0) - memcpy(newfds, *fds, sizeof(pollfd) * *allocnfds); - - if (*fds != nullptr) - free(*fds); - - *fds = newfds; - newfds += *allocnfds; - *allocnfds = newallocnfds; - return newfds; -} - -void -FastOS_UNIX_IPCHelper:: -BuildPollArray(pollfd **fds, unsigned int *nfds, unsigned int *allocnfds) -{ - FastOS_ProcessInterface *node; - pollfd *rfds; - const pollfd *rfdsEnd; - int pollIdx; - - rfds = *fds; - rfdsEnd = *fds + *allocnfds; - - if (rfds >= rfdsEnd) { - rfds = ResizePollArray(fds, - allocnfds); - rfdsEnd = *fds + *allocnfds; - } - rfds->fd = _wakeupPipe[0]; - rfds->events = POLLIN; - rfds->revents = 0; - rfds++; - pollIdx = 1; - for(node = _app->GetProcessList(); node != nullptr; node = node->_next) - { - FastOS_UNIX_Process *xproc = static_cast<FastOS_UNIX_Process *>(node); - - for(int type=0; type < int(FastOS_UNIX_Process::TYPE_READCOUNT); type++) - { - FastOS_UNIX_Process::DescriptorType type_ = - FastOS_UNIX_Process::DescriptorType(type); - FastOS_UNIX_Process::DescriptorHandle &desc = - xproc->GetDescriptorHandle(type_); - - if (desc._fd >= 0 && - (desc._wantRead || desc._wantWrite)) { - if (rfds >= rfdsEnd) { - rfds = ResizePollArray(fds, - allocnfds); - rfdsEnd = *fds + *allocnfds; - } - rfds->fd = desc._fd; - rfds->events = 0; - if (desc._wantRead) - rfds->events |= POLLRDNORM; - if (desc._wantWrite) - rfds->events |= POLLWRNORM; - rfds->revents = 0; - desc._pollIdx = pollIdx; - rfds++; - pollIdx++; - } else { - desc._pollIdx = -1; - desc._canRead = false; - desc._canWrite = false; - } - } - } - - *nfds = rfds - *fds; -} - - -bool -FastOS_UNIX_IPCHelper:: -SavePollArray(pollfd *fds, unsigned int nfds) -{ - FastOS_ProcessInterface *node; - - for(node = _app->GetProcessList(); node != nullptr; node = node->_next) - { - FastOS_UNIX_Process *xproc = static_cast<FastOS_UNIX_Process *>(node); - - for(int type=0; type < int(FastOS_UNIX_Process::TYPE_READCOUNT); type++) - { - FastOS_UNIX_Process::DescriptorType type_ = - FastOS_UNIX_Process::DescriptorType(type); - FastOS_UNIX_Process::DescriptorHandle &desc = - xproc->GetDescriptorHandle(type_); - - if (desc._fd >= 0 && - static_cast<unsigned int>(desc._pollIdx) < nfds) { - int revents = fds[desc._pollIdx].revents; - - if (desc._wantRead && - (revents & - (POLLIN | POLLRDNORM | POLLERR | POLLHUP | POLLNVAL)) != 0) - desc._canRead = true; - else - desc._canRead = false; - if (desc._wantWrite && - (revents & - (POLLOUT | POLLWRNORM | POLLWRBAND | POLLERR | POLLHUP | - POLLNVAL)) != 0) - desc._canWrite = true; - else - desc._canWrite = false; - } - } - } - - if ((fds[0].revents & (POLLIN | POLLERR | POLLHUP)) != 0) - return true; - else - return false; -} - - -void FastOS_UNIX_IPCHelper:: -RemoveClosingProcesses() -{ - // We assume that not updating maxFD isn't harmless. - - FastOS_ProcessInterface *node, *next; - - for(node = _app->GetProcessList(); node != nullptr; node = next) - { - int type; - - next = node->_next; - FastOS_UNIX_Process *xproc = static_cast<FastOS_UNIX_Process *>(node); - - bool stillBusy = false; - if(!xproc->GetKillFlag()) - for(type=0; type < FastOS_UNIX_Process::TYPE_READCOUNT; type++) - { - FastOS_UNIX_Process::DescriptorType type_; - - type_ = static_cast<FastOS_UNIX_Process::DescriptorType>(type); - - FastOS_UNIX_Process::DescriptorHandle &desc = - xproc->GetDescriptorHandle(type_); - - if (desc._fd != -1) - { - if((type_ == FastOS_UNIX_Process::TYPE_STDOUT) || - (type_ == FastOS_UNIX_Process::TYPE_STDERR) || - desc._wantWrite) - { - // We still want to use this socket. - // Make sure we don't close the socket yet. - stillBusy = true; - break; - } - } - } - - if(!stillBusy) - { - if (xproc->_closing) { - // We already have the process lock at this point, - // so modifying the list is safe. - _app->RemoveChildProcess(node); - - for(type=0; type < FastOS_UNIX_Process::TYPE_READCOUNT; type++) - { - FastOS_UNIX_Process::DescriptorHandle &desc = - xproc->GetDescriptorHandle(FastOS_UNIX_Process::DescriptorType(type)); - if(desc._fd != -1) - { - // No more select on this one. - // We already know wantWrite is not set - if (desc._wantRead) - desc._wantRead = false; - } - } - - // The process destructor can now proceed - auto closingPromise(std::move(xproc->_closing)); - closingPromise->set_value(); - } - } - } -} - - -void FastOS_UNIX_IPCHelper:: -Run(FastOS_ThreadInterface *thisThread, void *arg) -{ - (void)arg; - (void)thisThread; - - FastOS_ProcessInterface *node; - pollfd *fds; - unsigned int nfds; - unsigned int allocnfds; - - fds = nullptr; - nfds = 0; - allocnfds = 0; - for(;;) - { - // Deliver messages to from child processes and parent. - { - auto guard = _app->getProcessGuard(); - for(node = _app->GetProcessList(); node != nullptr; node = node->_next) - { - FastOS_UNIX_Process *xproc = static_cast<FastOS_UNIX_Process *>(node); - PipeData(xproc, FastOS_UNIX_Process::TYPE_STDOUT); - PipeData(xproc, FastOS_UNIX_Process::TYPE_STDERR); - } - - // Setup file descriptor sets for the next select() call - BuildPollChecks(); - - // Close and signal closing processes - RemoveClosingProcesses(); - - BuildPollArray(&fds, &nfds, &allocnfds); - } - bool exitFlag = false; - { - std::lock_guard<std::mutex> guard(_lock); - exitFlag = _exitFlag; - } - if (exitFlag) - { - break; - } - - for (;;) - { - int pollRc = - poll(fds, nfds, -1); - - if(pollRc == -1) - { - int wasErrno = errno; - - if(wasErrno == EINTR) - { - continue; - } - - perror("FastOS_UNIX_IPCHelper::RunAsync select failure"); - printf("errno = %d\n", wasErrno); - for(unsigned int i = 0; i < nfds; i++) - { - if ((fds[i].events & POLLIN) != 0) - printf("Read %d\n", fds[i].fd); - if ((fds[i].events & POLLOUT) != 0) - printf("Write %d\n", fds[i].fd); - } - std::_Exit(1); - } else { - break; - } - } - - bool woken = false; - { - auto guard = _app->getProcessGuard(); - woken = SavePollArray(fds, nfds); - // Do actual IO (based on file descriptor sets and buffer contents) - PerformAsyncIO(); - } - - // Did someone want to wake us up from the poll() call? - if (woken) { - char dummy; - ssize_t nbrfp = read(_wakeupPipe[0], &dummy, 1); - if (nbrfp != 1) { - perror("FastOS_UNIX_IPCHelper wakeupPipe read failed"); - } - } - } - free(fds); - - delete this; -} - -void -FastOS_UNIX_IPCHelper::NotifyProcessListChange () -{ - char dummy = 'x'; - ssize_t nbwtp = write(_wakeupPipe[1], &dummy, 1); - if (nbwtp != 1) { - perror("FastOS_UNIX_IPCHelper: write to wakeupPipe failed"); - } -} - -void -FastOS_UNIX_IPCHelper::Exit () -{ - std::lock_guard<std::mutex> guard(_lock); - _exitFlag = true; - NotifyProcessListChange(); -} - -void -FastOS_UNIX_IPCHelper::AddProcess (FastOS_UNIX_Process *xproc) -{ - bool newStream = false; - for(int type=0; type < int(FastOS_UNIX_Process::TYPE_READCOUNT); type++) - { - FastOS_UNIX_Process::DescriptorType type_ = FastOS_UNIX_Process::DescriptorType(type); - FastOS_UNIX_Process::DescriptorHandle &desc = xproc->GetDescriptorHandle(type_); - - if (desc._fd != -1) { - newStream = true; - SetBlocking(desc._fd, false); - } - } - if(newStream) - NotifyProcessListChange(); -} - -void -FastOS_UNIX_IPCHelper::RemoveProcess (FastOS_UNIX_Process *xproc) -{ - auto closePromise = std::make_unique<std::promise<void>>(); - auto closeFuture = closePromise->get_future(); - xproc->_closing = std::move(closePromise); - NotifyProcessListChange(); - closeFuture.wait(); -} - -void -FastOS_UNIX_IPCHelper::PipeData(FastOS_UNIX_Process *process, FastOS_UNIX_Process::DescriptorType type) -{ - FastOS_UNIX_Process::DescriptorHandle &desc = process->GetDescriptorHandle(type); - FastOS_RingBuffer *buffer = desc._readBuffer.get(); - if(buffer == nullptr) - return; - - FastOS_ProcessRedirectListener *listener = process->GetListener(type); - if(listener == nullptr) - return; - - auto bufferGuard = buffer->getGuard(); - - unsigned int readSpace; - while((readSpace = buffer->GetReadSpace()) > 0) { - listener->OnReceiveData(buffer->GetReadPtr(), size_t(readSpace)); - buffer->Consume(readSpace); - } - - if(buffer->GetCloseFlag()) - process->CloseListener(type); -} diff --git a/fastos/src/vespa/fastos/unix_ipc.h b/fastos/src/vespa/fastos/unix_ipc.h deleted file mode 100644 index 13e92411011..00000000000 --- a/fastos/src/vespa/fastos/unix_ipc.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include "app.h" -#include "process.h" -#include "thread.h" -#include <poll.h> - -class FastOS_RingBuffer; - -class FastOS_UNIX_IPCHelper : public FastOS_Runnable -{ -private: - FastOS_UNIX_IPCHelper(const FastOS_UNIX_IPCHelper&); - FastOS_UNIX_IPCHelper& operator=(const FastOS_UNIX_IPCHelper&); - -protected: - std::mutex _lock; - volatile bool _exitFlag; - FastOS_ApplicationInterface *_app; - - int _wakeupPipe[2]; - - bool DoWrite (FastOS_UNIX_Process::DescriptorHandle &desc); - bool DoRead (FastOS_UNIX_Process::DescriptorHandle &desc); - bool SetBlocking (int fileDescriptor, bool doBlock); - void BuildPollCheck (bool isRead, int filedes, FastOS_RingBuffer *buffer, bool *check); - void BuildPollArray(pollfd **fds, unsigned int *nfds, unsigned int *allocnfds); - bool SavePollArray(pollfd *fds, unsigned int nfds); - void PerformAsyncIO (); - void BuildPollChecks(); - void PipeData (FastOS_UNIX_Process *process, FastOS_UNIX_Process::DescriptorType type); - void RemoveClosingProcesses(); - -public: - FastOS_UNIX_IPCHelper (FastOS_ApplicationInterface *app, int appDescriptor); - ~FastOS_UNIX_IPCHelper (); - void Run (FastOS_ThreadInterface *thisThread, void *arg) override; - void NotifyProcessListChange (); - void AddProcess (FastOS_UNIX_Process *xproc); - void RemoveProcess (FastOS_UNIX_Process *xproc); - void Exit (); -}; diff --git a/fastos/src/vespa/fastos/unix_process.cpp b/fastos/src/vespa/fastos/unix_process.cpp deleted file mode 100644 index cd29108c3d6..00000000000 --- a/fastos/src/vespa/fastos/unix_process.cpp +++ /dev/null @@ -1,985 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include "process.h" -#include "unix_ipc.h" -#include "ringbuffer.h" -#include <vector> -#include <cstring> -#include <cstdlib> -#include <unistd.h> -#include <fcntl.h> -#include <sys/wait.h> -#ifndef __linux__ -#include <signal.h> -#endif -#include <thread> - - -extern "C" -{ -extern char **environ; -} - - -using namespace std::chrono_literals; -using namespace std::chrono; - -static pid_t safe_fork () -{ - pid_t pid; - int retry = 1; - while((pid = fork()) == -1 && errno == EAGAIN) { - sleep(retry); - if (retry < 4) retry *= 2; - } - return pid; -} - -static int -normalizedWaitStatus(int status) -{ - if (WIFEXITED(status)) - return WEXITSTATUS(status); - else - return (0x80000000 | status); -} - - -// The actual process launched in the proxy process -class FastOS_UNIX_RealProcess -{ -private: - FastOS_UNIX_RealProcess(const FastOS_UNIX_RealProcess&); - FastOS_UNIX_RealProcess& operator=(const FastOS_UNIX_RealProcess&); - -public: - enum - { - STREAM_STDIN = (1 << 0), - STREAM_STDOUT = (1 << 1), - STREAM_STDERR = (1 << 2), - EXEC_SHELL = (1 << 3) - }; - -private: - pid_t _pid; - bool _terse; // Set if using direct fork (bypassing proxy process) - int _streamMask; - - int _stdinDes[2]; - int _stdoutDes[2]; - int _stderrDes[2]; - int _handshakeDes[2]; - std::string _runDir; - std::string _stdoutRedirName; - std::string _stderrRedirName; - const char *_path; - std::vector<char> _pathProgBuf; - - void CloseDescriptor(int fd); - void CloseAndResetDescriptor(int *fd); - void CloseDescriptors(); - -public: - void SetRunDir(const char * runDir) { _runDir = runDir; } - - int HandoverStdinDescriptor() { - int ret = _stdinDes[1]; - _stdinDes[1] = -1; - return ret; - } - - int HandoverStdoutDescriptor() { - int ret = _stdoutDes[0]; - _stdoutDes[0] = -1; - return ret; - } - - int HandoverStderrDescriptor() { - int ret = _stderrDes[0]; - _stderrDes[0] = -1; - return ret; - } - - FastOS_UNIX_RealProcess *_prev, *_next; - - FastOS_UNIX_RealProcess (int streamMask); - ~FastOS_UNIX_RealProcess(); - pid_t GetProcessID() const { return _pid; } - - bool IsStdinPiped() const { - return (_streamMask & STREAM_STDIN ) != 0; - } - - bool IsStdoutPiped() const { - return (_streamMask & STREAM_STDOUT) != 0; - } - - bool IsStderrPiped() const { - return (_streamMask & STREAM_STDERR) != 0; - } - - bool IsUsingShell() const { - return (_streamMask & EXEC_SHELL) != 0; - } - - void SetStdoutRedirName(const char *stdoutRedirName) { - _stdoutRedirName = stdoutRedirName; - } - - void SetStderrRedirName(const char *stderrRedirName) { - _stderrRedirName = stderrRedirName; - } - - void PrepareExecVPE (const char *prog); - - void - ExecVPE (const char *prog, - char *const args[], - char *const env[]); - - static bool IsWhiteSpace (char c); - - static const char * - NextArgument (const char *p, - const char **endArg, - int *length = nullptr); - - static int CountArguments (const char *commandLine); - - void - RedirOut(const std::string & filename, - int targetfd, - int exitCodeOnFailure); - - bool - ForkAndExec(const char *command, - char **environmentVariables, - FastOS_UNIX_Process *process); - - bool Setup(); - void SetTerse() { _terse = true; } - ssize_t HandshakeRead(void *buf, size_t len); - void HandshakeWrite(int val); -}; - - -void -FastOS_UNIX_RealProcess::CloseDescriptor(int fd) -{ - close(fd); -} - - -void -FastOS_UNIX_RealProcess::CloseAndResetDescriptor(int *fd) -{ - if (*fd == -1) - return; - CloseDescriptor(*fd); - *fd = -1; -} - - -void -FastOS_UNIX_RealProcess::CloseDescriptors() -{ - CloseAndResetDescriptor(&_stdinDes[0]); - CloseAndResetDescriptor(&_stdinDes[1]); - CloseAndResetDescriptor(&_stdoutDes[0]); - CloseAndResetDescriptor(&_stdoutDes[1]); - CloseAndResetDescriptor(&_stderrDes[0]); - CloseAndResetDescriptor(&_stderrDes[1]); - CloseAndResetDescriptor(&_handshakeDes[0]); - CloseAndResetDescriptor(&_handshakeDes[1]); -} - - -FastOS_UNIX_RealProcess::FastOS_UNIX_RealProcess(int streamMask) - : _pid(-1), - _terse(false), - _streamMask(streamMask), - _runDir(), - _stdoutRedirName(), - _stderrRedirName(), - _path(nullptr), - _pathProgBuf(), - _prev(nullptr), - _next(nullptr) -{ - _stdinDes[0] = _stdinDes[1] = -1; - _stdoutDes[0] = _stdoutDes[1] = -1; - _stderrDes[0] = _stderrDes[1] = -1; - _handshakeDes[0] = _handshakeDes[1] = -1; -} - - -FastOS_UNIX_RealProcess::~FastOS_UNIX_RealProcess() -{ - CloseDescriptors(); -} - - -void -FastOS_UNIX_RealProcess::PrepareExecVPE(const char *prog) -{ - const char *path = nullptr; - - char defaultPath[] = ":/usr/ucb:/bin:/usr/bin"; - - if (strchr(prog, '/') != nullptr) { - path = ""; - } else { - path = getenv("PATH"); - if (path == nullptr) path = defaultPath; - } - _path = path; - _pathProgBuf.resize(strlen(prog) + 1 + strlen(path) + 1); -} - - -void -FastOS_UNIX_RealProcess::ExecVPE (const char *prog, - char *const args[], - char *const env[]) -{ - - char *fullPath = &_pathProgBuf[0]; - const char *path = _path; - - for(;;) - { - char *p; - for (p = fullPath; (*path != '\0') && (*path != ':'); path++) - *p++ = *path; - - if (p > fullPath) *p++ = '/'; - - strcpy(p, prog); - // fprintf(stdout, "Attempting execve [%s]\n", fullPath); - // fflush(stdout); - execve(fullPath, args, env); - - if ((errno == ENOEXEC) || - (errno == ENOMEM) || - (errno == E2BIG) || - (errno == ETXTBSY)) - break; - - if (*path == '\0') break; - path++; - } -} - - -bool -FastOS_UNIX_RealProcess::IsWhiteSpace (char c) -{ - return (c == ' ' || c == '\t'); -} - - -const char * -FastOS_UNIX_RealProcess::NextArgument (const char *p, - const char **endArg, - int *length) -{ - while(*p != '\0') - { - if (!IsWhiteSpace(*p)) { - char quoteChar = '\0'; - if ((*p == '\'') || (*p == '"')) { - quoteChar = *p; - p++; - } - - const char *nextArg = p; - - // Find the end of the argument. - for(;;) - { - if (*p == '\0') { - if (length != nullptr) - *length = p - nextArg; - break; - } - - if (quoteChar != '\0') { - if (*p == quoteChar) { - if (length != nullptr) - *length = p - nextArg; - p++; - break; - } - } - else - { - if (IsWhiteSpace(*p)) { - if (length != nullptr) - *length = p - nextArg; - break; - } - } - p++; - } - - *endArg = p; - return nextArg; - } - p++; - } - return nullptr; -} - - -int -FastOS_UNIX_RealProcess::CountArguments (const char *commandLine) -{ - int numArgs = 0; - const char *nextArg = commandLine; - while(NextArgument(nextArg, &nextArg)) - numArgs++; - - return numArgs; -} - - -void -FastOS_UNIX_RealProcess::RedirOut(const std::string & filename, - int targetfd, - int exitCodeOnFailure) -{ - if (filename.empty() || filename[0] != '>') - return; - - int newfd; - if (filename[1] == '>') { - newfd = open(&filename[2], - O_WRONLY | O_CREAT | O_APPEND, - 0666); - if (newfd < 0) { - if (!_terse) { - fprintf(stderr, - "ERROR: Could not open %s for append: %s\n", - &filename[2], - strerror(errno)); - fflush(stderr); - } - _exit(exitCodeOnFailure); - } - } else { - newfd = open(&filename[1], - O_WRONLY | O_CREAT | O_TRUNC, - 0666); - if (newfd < 0) { - if (!_terse) { - fprintf(stderr, - "ERROR: Could not open %s for write: %s\n", - &filename[1], - strerror(errno)); - fflush(stderr); - } - _exit(exitCodeOnFailure); - } - } - if (newfd != targetfd) { - dup2(newfd, targetfd); - CloseDescriptor(newfd); - } -} - - -bool -FastOS_UNIX_RealProcess:: -ForkAndExec(const char *command, - char **environmentVariables, - FastOS_UNIX_Process *process) -{ - bool rc = false; - int numArguments = 0; - char **execArgs = nullptr; - - if (!IsUsingShell()) { - numArguments = CountArguments(command); - if (numArguments > 0) { - execArgs = new char *[numArguments + 1]; - const char *nextArg = command; - - for(int i=0; ; i++) { - int length; - const char *arg = NextArgument(nextArg, &nextArg, &length); - - if (arg == nullptr) { - // printf("ARG nullptr\n"); - execArgs[i] = nullptr; - break; - } - // printf("argLen = %d\n", length); - execArgs[i] = new char[length + 1]; - memcpy(execArgs[i], arg, length); - execArgs[i][length] = '\0'; - // printf("arg %d: [%s]\n", i, execArgs[i]); - } - PrepareExecVPE(execArgs[0]); - } - } - - _pid = safe_fork(); - if (_pid == static_cast<pid_t>(0)) { - // Fork success, child side. - if (IsStdinPiped() && _stdinDes[0] != STDIN_FILENO) { - dup2(_stdinDes[0], STDIN_FILENO); - CloseDescriptor(_stdinDes[0]); - } - _stdinDes[0] = -1; - if (IsStdoutPiped() && _stdoutDes[1] != STDOUT_FILENO) { - dup2(_stdoutDes[1], STDOUT_FILENO); - CloseDescriptor(_stdoutDes[1]); - } - _stdoutDes[1] = -1; - if (IsStderrPiped() && _stderrDes[1] != STDERR_FILENO) { - dup2(_stderrDes[1], STDERR_FILENO); - CloseDescriptor(_stderrDes[1]); - } - _stderrDes[1] = -1; - // FIX! Check error codes for dup2, and do _exit(127) if trouble - - if ( ! _runDir.empty()) { - if (chdir(_runDir.c_str())) { - if (!_terse) { - fprintf(stderr, - "ERROR: Could not chdir to %s: %s\n", - _runDir.c_str(), - strerror(errno)); - fflush(stderr); - } - _exit(126); - } - } - RedirOut(_stdoutRedirName.c_str(), STDOUT_FILENO, 124); - RedirOut(_stderrRedirName.c_str(), STDERR_FILENO, 125); - - CloseDescriptor(_handshakeDes[0]); - _handshakeDes[0] = -1; - if (process != nullptr) { - int fdlimit = sysconf(_SC_OPEN_MAX); - // Close everything else - // printf("fdlimit = %d\n", fdlimit); - for(int fd = STDERR_FILENO + 1; fd < fdlimit; fd++) - { - if (fd != _handshakeDes[1]) - CloseDescriptor(fd); - } - } - if (fcntl(_handshakeDes[1], F_SETFD, FD_CLOEXEC) != 0) _exit(127); - - HandshakeWrite(0); - - // printf("exev(p)e [%s]\n", command); - if (IsUsingShell()) { - const char *shExecArgs[4]; - - shExecArgs[0] = "sh"; - shExecArgs[1] = "-c"; - shExecArgs[2] = command; - shExecArgs[3] = nullptr; - execve("/bin/sh", - const_cast<char *const *> - (reinterpret_cast<const char *const *> - (shExecArgs)), - environmentVariables); - int error = errno; - if (!_terse) { - fprintf(stderr, - "ERROR: Could not execv /bin/sh -c '%s': %s\n", - command, - strerror(error)); - fflush(stderr); - } - HandshakeWrite(error); - } - else - { - if (numArguments > 0) { - // printf("Command: [%s]\n", execArgs[0]); - ExecVPE(execArgs[0], - static_cast<char *const *>(execArgs), - environmentVariables); - int error = errno; - if (!_terse) { - fprintf(stderr, - "ERROR: Could not execve %s with " - "path search: %s\n", - execArgs[0], - strerror(error)); - fflush(stderr); - } - HandshakeWrite(error); - } - } - _exit(127); // If execve fails, we'll get it here - } - else if(_pid != static_cast<pid_t>(-1)) - { - /* Fork success, parent side */ - - // Close unused file descriptors - if (IsStdinPiped()) { - CloseAndResetDescriptor(&_stdinDes[0]); - } - if (IsStdoutPiped()) { - CloseAndResetDescriptor(&_stdoutDes[1]); - } - if (IsStderrPiped()) { - CloseAndResetDescriptor(&_stderrDes[1]); - } - - CloseAndResetDescriptor(&_handshakeDes[1]); - - int flags = fcntl(_handshakeDes[0], F_GETFL, 0); - if (flags != -1) { - flags &= ~O_NONBLOCK; - fcntl(_handshakeDes[0], F_SETFL, flags); - } - int phase1res = 0; - ssize_t rgot = HandshakeRead(&phase1res, sizeof(int)); - bool wasError = false; - int error = 0; - if (static_cast<size_t>(rgot) != sizeof(int)) wasError = true; - else if (phase1res != 0) { - wasError = true; - error = phase1res; - } else { - int phase2res = 0; - rgot = HandshakeRead(&phase2res, sizeof(int)); - if (rgot >= 1) { - if (static_cast<size_t>(rgot) >= sizeof(int)) - error = phase2res; - wasError = true; - } - } - - if (wasError) { - int status = 0; - CloseDescriptors(); - pid_t wpid = waitpid(_pid, &status, 0); - if (wpid <= 0) { - fprintf(stderr, "ERROR: Could not start process %s\n", command); - } else if (WIFEXITED(status)) { - status = WEXITSTATUS(status); - switch (status) { - case 124: - if ( ! _stdoutRedirName.empty() && - _stdoutRedirName[0] == '>') { - if (_stdoutRedirName[1] == '>') - fprintf(stderr, "ERROR: Could not open %s for append", &_stdoutRedirName[2]); - else - fprintf(stderr, "ERROR: Could not open %s for write", &_stdoutRedirName[1]); - } - break; - case 125: - if ( ! _stderrRedirName.empty() && - _stderrRedirName[0] == '>') { - if (_stderrRedirName[1] == '>') - fprintf(stderr, "ERROR: Could not open %s for append", &_stderrRedirName[2]); - else - fprintf(stderr, "ERROR: Could not open %s for write", &_stderrRedirName[1]); - } - break; - case 126: - if ( ! _runDir.empty()) { - fprintf(stderr, "ERROR: Could not chdir to %s\n", _runDir.c_str()); - } - break; - case 127: - if (error != 0) { - std::error_code ec(error, std::system_category()); - fprintf(stderr, "ERROR: Could not execve %s: %s\n", command, ec.message().c_str()); - } else - fprintf(stderr, "ERROR: Could not execve %s\n", command); - break; - default: - fprintf(stderr, "ERROR: Could not start process %s\n", command); - break; - } - } else { - fprintf(stderr, "ERROR: Could not start process %s\n", command); - } - fflush(stderr); - } else { - rc = true; - } - } - if (execArgs != nullptr) { - char **arg = execArgs; - while (*arg != nullptr) { - delete [] *arg; - arg++; - } - delete [] execArgs; - } - - return rc; -} - - -void -FastOS_UNIX_RealProcess::HandshakeWrite(int val) -{ - if (_handshakeDes[1] == -1) - return; - const void *wbuf = &val; - size_t residue = sizeof(val); - for (;;) { - /* - * XXX: Might need to use syscall(SYS_write....) to avoid - * thread library interference. - */ - ssize_t wgot = write(_handshakeDes[1], wbuf, residue); - if (wgot < 0 && errno == EINTR) - continue; - if (wgot <= 0) - break; - wbuf = static_cast<const char *>(wbuf) + wgot; - residue -= wgot; - if (residue == 0) - break; - } -} - - -ssize_t -FastOS_UNIX_RealProcess::HandshakeRead(void *buf, size_t len) -{ - if (_handshakeDes[0] == -1) - return 0; - size_t residue = len; - ssize_t rgot = 0; - void *rbuf = buf; - for (;;) { - rgot = read(_handshakeDes[0], rbuf, residue); - if (rgot < 0 && errno == EINTR) - continue; - if (rgot <= 0) - break; - rbuf = static_cast<char *>(rbuf) + rgot; - residue -= rgot; - if (residue == 0) - break; - } - return (residue == len) ? rgot : len - residue; -} - - -bool -FastOS_UNIX_RealProcess::Setup() -{ - bool rc = true; - - if (IsStdinPiped()) rc = rc && (pipe(_stdinDes) == 0); - if (IsStdoutPiped()) rc = rc && (pipe(_stdoutDes) == 0); - if (IsStderrPiped()) rc = rc && (pipe(_stderrDes) == 0); - rc = rc && (pipe(_handshakeDes) == 0); - return rc; -} - - -FastOS_UNIX_Process:: -FastOS_UNIX_Process (const char *cmdLine, - FastOS_ProcessRedirectListener *stdoutListener, - FastOS_ProcessRedirectListener *stderrListener) : - FastOS_ProcessInterface(cmdLine, stdoutListener, stderrListener), - _pid(0), - _died(false), - _returnCode(-1), - _descriptor(), - _runDir(), - _stdoutRedirName(), - _stderrRedirName(), - _killed(false), - _closing(nullptr) -{ - constexpr uint32_t RING_BUFFER_SIZE = 0x10000; - if (stdoutListener != nullptr) - _descriptor[TYPE_STDOUT]._readBuffer = std::make_unique<FastOS_RingBuffer>(RING_BUFFER_SIZE); - if (stderrListener != nullptr) - _descriptor[TYPE_STDERR]._readBuffer = std::make_unique<FastOS_RingBuffer>(RING_BUFFER_SIZE); - - { - auto guard = _app->getProcessGuard(); - _app->AddChildProcess(this); - } - - // App::AddToIPCComm() is performed when the process is started -} - -FastOS_UNIX_Process::~FastOS_UNIX_Process () -{ - Kill(); // Kill if not dead or detached. - - if ((GetDescriptorHandle(TYPE_STDOUT)._fd != -1) || - (GetDescriptorHandle(TYPE_STDERR)._fd != -1)) - { - // Let the IPC helper flush write queues and remove us from the - // process list before we disappear. - static_cast<FastOS_UNIX_Application *>(_app)->RemoveFromIPCComm(this); - } else { - // No IPC descriptor, do it ourselves - auto guard = _app->getProcessGuard(); - _app->RemoveChildProcess(this); - } - - for(int i=0; i<int(TYPE_COUNT); i++) { - _descriptor[i]._readBuffer.reset(); - _descriptor[i]._writeBuffer.reset(); - CloseDescriptor(DescriptorType(i)); - } - - CloseListener(TYPE_STDOUT); - CloseListener(TYPE_STDERR); -} - -bool FastOS_UNIX_Process::CreateInternal (bool useShell) -{ - return GetProcessStarter()->CreateProcess(this, useShell, - _stdoutListener != nullptr, - _stderrListener != nullptr); -} - -bool FastOS_UNIX_Process::WriteStdin (const void *data, size_t length) -{ - bool rc = false; - DescriptorHandle &desc = GetDescriptorHandle(TYPE_STDIN); - - if (desc._fd != -1) { - if (data == nullptr) { - CloseDescriptor(TYPE_STDIN); - rc = true; - } - else - { - int writerc = write(desc._fd, data, length); - if (writerc < int(length)) - CloseDescriptor(TYPE_STDIN); - else - rc = true; - } - } - - return rc; -} - -bool FastOS_UNIX_Process::Signal(int sig) -{ - bool rc = false; - pid_t pid; - - auto guard = _app->getProcessGuard(); - pid = GetProcessId(); - if (pid == 0) { - /* Do nothing */ - } else if (GetDeathFlag()) { - rc = true; // The process is no longer around. - } else if (kill(pid, sig) == 0) { - if (sig == SIGKILL) - _killed = true; - rc = true; - } - return rc; -} - -bool FastOS_UNIX_Process::Kill () -{ - return Signal(SIGKILL); -} - -bool FastOS_UNIX_Process::InternalWait (int *returnCode, - int timeOutSeconds, - bool *pollStillRunning) -{ - bool rc = GetProcessStarter()->Wait(this, timeOutSeconds, - pollStillRunning); - if (rc) { - if (_killed) - *returnCode = KILL_EXITCODE; - else - *returnCode = _returnCode; - } - - return rc; -} - -bool FastOS_UNIX_Process::Wait (int *returnCode, int timeOutSeconds) -{ - return InternalWait(returnCode, timeOutSeconds, nullptr); -} - -bool FastOS_UNIX_Process::PollWait (int *returnCode, bool *stillRunning) -{ - return InternalWait(returnCode, -1, stillRunning); -} - -int FastOS_UNIX_Process::BuildStreamMask (bool useShell) -{ - int streamMask = FastOS_UNIX_RealProcess::STREAM_STDIN; - if (_stdoutListener) streamMask |= FastOS_UNIX_RealProcess::STREAM_STDOUT; - if (_stderrListener) streamMask |= FastOS_UNIX_RealProcess::STREAM_STDERR; - if (useShell) streamMask |= FastOS_UNIX_RealProcess::EXEC_SHELL; - - return streamMask; -} - - -FastOS_UNIX_ProcessStarter::FastOS_UNIX_ProcessStarter (FastOS_ApplicationInterface *app) - : _app(app), - _hasDirectChildren(false) -{ -} - -FastOS_UNIX_ProcessStarter::~FastOS_UNIX_ProcessStarter () = default; - -bool -FastOS_UNIX_ProcessStarter:: -CreateProcess (FastOS_UNIX_Process *process, bool useShell, bool pipeStdout, bool pipeStderr) -{ - bool rc = false; - - const char *cmdLine = process->GetCommandLine(); - - auto guard = _app->getProcessGuard(); - - _hasDirectChildren = true; - FastOS_UNIX_RealProcess *rprocess = new FastOS_UNIX_RealProcess(process->BuildStreamMask(useShell)); - const char *runDir = process->GetRunDir(); - if (runDir != nullptr) { - rprocess->SetRunDir(runDir); // Handover - } - const char *stdoutRedirName = process->GetStdoutRedirName(); - if (stdoutRedirName != nullptr) { - rprocess->SetStdoutRedirName(stdoutRedirName); - } - const char *stderrRedirName = process->GetStderrRedirName(); - if (stderrRedirName != nullptr) { - rprocess->SetStderrRedirName(stderrRedirName); - } - rprocess->SetTerse(); - rprocess->Setup(); - process->SetDescriptor(FastOS_UNIX_Process::TYPE_STDIN, rprocess->HandoverStdinDescriptor()); - if (pipeStdout) - process->SetDescriptor(FastOS_UNIX_Process::TYPE_STDOUT, rprocess->HandoverStdoutDescriptor()); - if (pipeStderr) - process->SetDescriptor(FastOS_UNIX_Process::TYPE_STDERR, rprocess->HandoverStderrDescriptor()); - pid_t processId = -1; - if (rprocess->ForkAndExec(cmdLine, environ, process)) { - processId = rprocess->GetProcessID(); - } - if (processId != -1) { - process->SetProcessId(static_cast<unsigned int>(processId)); - if (!useShell || pipeStdout || pipeStderr) - static_cast<FastOS_UNIX_Application *>(_app)->AddToIPCComm(process); - rc = true; - } else { - fprintf(stderr, "Forkandexec %s failed\n", cmdLine); - } - guard.unlock(); - delete rprocess; - return rc; -} - - -void -FastOS_UNIX_ProcessStarter::PollReapDirectChildren() -{ - int status; - pid_t pid; - - for (;;) { - pid = waitpid(-1, &status, WNOHANG); - if (pid <= 0) - break; - - FastOS_ProcessInterface *node; - for(node = _app->GetProcessList(); - node != nullptr; node = node->_next) - { - FastOS_UNIX_Process *xproc = static_cast<FastOS_UNIX_Process *>(node); - - if (xproc->GetProcessId() == static_cast<unsigned int>(pid)) - xproc->DeathNotification(normalizedWaitStatus(status)); - } - } -} - - -bool -FastOS_UNIX_ProcessStarter::Wait(FastOS_UNIX_Process *process, - int timeOutSeconds, - bool *pollStillRunning) -{ - bool rc = true; - - bool timeOutKillAttempted = false; - - steady_clock::time_point start = steady_clock::now(); - - if (pollStillRunning != nullptr) - *pollStillRunning = true; - - for (;;) { - { - auto guard = process->_app->getProcessGuard(); - - if (_hasDirectChildren) PollReapDirectChildren(); - } - - if (process->GetDeathFlag()) { - if (pollStillRunning != nullptr) - *pollStillRunning = false; - break; - } - - if (pollStillRunning != nullptr) - break; - - if ((timeOutSeconds != -1) && !timeOutKillAttempted) { - - if ((steady_clock::now() - start) >= seconds(timeOutSeconds)) { - process->Kill(); - timeOutKillAttempted = true; - } - } - - std::this_thread::sleep_for(100ms); - } - - return rc; -} - -FastOS_UNIX_Process::DescriptorHandle::DescriptorHandle() - : _fd(-1), - _wantRead(false), - _wantWrite(false), - _canRead(false), - _canWrite(false), - _pollIdx(-1), - _readBuffer(), - _writeBuffer() -{ -} -FastOS_UNIX_Process::DescriptorHandle::~DescriptorHandle() = default; -void -FastOS_UNIX_Process::DescriptorHandle::CloseHandle() -{ - _wantRead = false; - _wantWrite = false; - _canRead = false; - _canWrite = false; - _pollIdx = -1; - if (_fd != -1) { - close(_fd); - _fd = -1; - } - if (_readBuffer) - _readBuffer->Close(); - if (_writeBuffer) - _writeBuffer->Close(); -} diff --git a/fastos/src/vespa/fastos/unix_process.h b/fastos/src/vespa/fastos/unix_process.h deleted file mode 100644 index 43b4388e0c3..00000000000 --- a/fastos/src/vespa/fastos/unix_process.h +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -//************************************************************************ -/** - * Class definitions for FastOS_UNIX_Process. - * - * @author Div, Oivind H. Danielsen - */ - -#pragma once - -#include "process.h" -#include "app.h" -#include <string> -#include <memory> -#include <future> - -class FastOS_UNIX_RealProcess; -class FastOS_RingBuffer; - -class FastOS_UNIX_Process : public FastOS_ProcessInterface -{ -private: - FastOS_UNIX_Process(const FastOS_UNIX_Process&); - FastOS_UNIX_Process& operator=(const FastOS_UNIX_Process&); - - unsigned int _pid; - bool _died; - int _returnCode; -public: - class DescriptorHandle - { - private: - DescriptorHandle(const DescriptorHandle &); - DescriptorHandle& operator=(const DescriptorHandle &); - - public: - int _fd; - bool _wantRead; - bool _wantWrite; - bool _canRead; - bool _canWrite; - int _pollIdx; - std::unique_ptr<FastOS_RingBuffer> _readBuffer; - std::unique_ptr<FastOS_RingBuffer> _writeBuffer; - DescriptorHandle(); - ~DescriptorHandle(); - void CloseHandle(); - }; -private: - DescriptorHandle _descriptor[4]; - - std::string _runDir; - std::string _stdoutRedirName; - std::string _stderrRedirName; - bool _killed; - - FastOS_UNIX_ProcessStarter *GetProcessStarter () { - return static_cast<FastOS_UNIX_Application *>(_app)->GetProcessStarter(); - } - - bool InternalWait (int *returnCode, int timeOutSeconds, bool *pollStillRunning); -public: - enum DescriptorType - { - TYPE_STDOUT, - TYPE_STDERR, - TYPE_STDIN, - TYPE_COUNT - }; - - enum Constants - { - TYPE_READCOUNT = 3 - }; - std::unique_ptr<std::promise<void>> _closing; - FastOS_ProcessRedirectListener *GetListener (DescriptorType type) - { - if(type == TYPE_STDOUT) - return _stdoutListener; - else if(type == TYPE_STDERR) - return _stderrListener; - - return nullptr; - } - - void CloseListener (DescriptorType type) - { - if(type == TYPE_STDOUT) - { - if(_stdoutListener != nullptr) - { - _stdoutListener->OnReceiveData(nullptr, 0); - _stdoutListener = nullptr; - } - } - else if(type == TYPE_STDERR) - { - if(_stderrListener != nullptr) - { - _stderrListener->OnReceiveData(nullptr, 0); - _stderrListener = nullptr; - } - } - } - - FastOS_UNIX_Process (const char *cmdLine, - FastOS_ProcessRedirectListener *stdoutListener = nullptr, - FastOS_ProcessRedirectListener *stderrListener = nullptr); - ~FastOS_UNIX_Process (); - bool CreateInternal (bool useShell); - bool Create () override { return CreateInternal(false); } - bool CreateWithShell () override { return CreateInternal(true); } - bool WriteStdin (const void *data, size_t length) override; - bool Signal(int sig); - bool Kill () override; - bool Wait (int *returnCode, int timeOutSeconds = -1) override; - bool PollWait (int *returnCode, bool *stillRunning) override; - void SetProcessId (unsigned int pid) { _pid = pid; } - unsigned int GetProcessId() override { return _pid; } - void DeathNotification (int returnCode) { - _returnCode = returnCode; - _died = true; - } - bool GetDeathFlag () { return _died; } - int BuildStreamMask (bool useShell); - - void CloseDescriptor (DescriptorType type) - { - _descriptor[type].CloseHandle(); - } - - void SetDescriptor (DescriptorType type, int descriptor) - { - _descriptor[type]._fd = descriptor; - } - - DescriptorHandle &GetDescriptorHandle(DescriptorType type) - { - return _descriptor[type]; - } - - bool GetKillFlag () { return _killed; } - - const char *GetRunDir() const { return _runDir.c_str(); } - const char *GetStdoutRedirName() const { return _stdoutRedirName.c_str(); } - const char *GetStderrRedirName() const { return _stderrRedirName.c_str(); } -}; - - -class FastOS_UNIX_RealProcess; -class FastOS_UNIX_ProcessStarter -{ -private: - FastOS_UNIX_ProcessStarter(const FastOS_UNIX_ProcessStarter&); - FastOS_UNIX_ProcessStarter& operator=(const FastOS_UNIX_ProcessStarter&); - -protected: - FastOS_ApplicationInterface *_app; - bool _hasDirectChildren; - - void PollReapDirectChildren(); - -public: - FastOS_UNIX_ProcessStarter (FastOS_ApplicationInterface *app); - ~FastOS_UNIX_ProcessStarter (); - - bool CreateProcess (FastOS_UNIX_Process *process, bool useShell, - bool pipeStdout, bool pipeStderr); - bool Wait (FastOS_UNIX_Process *process, int timeOutSeconds, bool *pollStillRunning); -}; - - |