summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval/src/tests/apps/analyze_onnx_model/analyze_onnx_model_test.cpp2
-rw-r--r--eval/src/tests/apps/eval_expr/eval_expr_test.cpp3
-rw-r--r--eval/src/vespa/eval/eval/test/test_io.cpp79
-rw-r--r--eval/src/vespa/eval/eval/test/test_io.h30
-rw-r--r--fastos/src/tests/CMakeLists.txt6
-rw-r--r--fastos/src/tests/filetest.cpp2
-rw-r--r--fastos/src/tests/processtest.cpp292
-rw-r--r--fastos/src/vespa/fastos/CMakeLists.txt3
-rw-r--r--fastos/src/vespa/fastos/app.cpp54
-rw-r--r--fastos/src/vespa/fastos/app.h17
-rw-r--r--fastos/src/vespa/fastos/process.cpp16
-rw-r--r--fastos/src/vespa/fastos/process.h180
-rw-r--r--fastos/src/vespa/fastos/unix_app.cpp53
-rw-r--r--fastos/src/vespa/fastos/unix_app.h12
-rw-r--r--fastos/src/vespa/fastos/unix_ipc.cpp547
-rw-r--r--fastos/src/vespa/fastos/unix_ipc.h41
-rw-r--r--fastos/src/vespa/fastos/unix_process.cpp985
-rw-r--r--fastos/src/vespa/fastos/unix_process.h172
-rw-r--r--fnet/src/tests/examples/examples_test.cpp249
-rw-r--r--searchcore/src/apps/vespa-dump-feed/vespa-dump-feed.cpp8
-rw-r--r--searchcore/src/tests/proton/verify_ranksetup/verify_ranksetup_test.cpp14
-rw-r--r--searchlib/src/apps/vespa-ranking-expression-analyzer/vespa-ranking-expression-analyzer.cpp1
-rw-r--r--staging_vespalib/src/tests/state_server/state_server_test.cpp8
-rw-r--r--vbench/src/tests/app_dumpurl/app_dumpurl_test.cpp16
-rw-r--r--vbench/src/tests/app_vbench/app_vbench_test.cpp22
-rw-r--r--vespalib/CMakeLists.txt1
-rw-r--r--vespalib/src/tests/assert/assert_test.cpp21
-rw-r--r--vespalib/src/tests/child_process/.gitignore4
-rw-r--r--vespalib/src/tests/child_process/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/child_process/child_process_test.cpp187
-rw-r--r--vespalib/src/tests/drop-file-from-cache/drop_file_from_cache_test.cpp21
-rw-r--r--vespalib/src/tests/exception_classes/silenceuncaught_test.cpp39
-rw-r--r--vespalib/src/tests/host_name/host_name_test.cpp3
-rw-r--r--vespalib/src/tests/make_fixture_macros/make_fixture_macros_test.cpp12
-rw-r--r--vespalib/src/tests/process/process_test.cpp40
-rw-r--r--vespalib/src/tests/tutorial/make_tutorial.cpp46
-rw-r--r--vespalib/src/vespa/vespalib/process/process.cpp17
-rw-r--r--vespalib/src/vespa/vespalib/process/process.h2
-rw-r--r--vespalib/src/vespa/vespalib/testkit/test_macros.h36
-rw-r--r--vespalib/src/vespa/vespalib/testkit/testapp.h8
-rw-r--r--vespalib/src/vespa/vespalib/util/CMakeLists.txt1
-rw-r--r--vespalib/src/vespa/vespalib/util/child_process.cpp346
-rw-r--r--vespalib/src/vespa/vespalib/util/child_process.h212
-rw-r--r--vespamalloc/src/tests/doubledelete/expectsignal.cpp14
-rw-r--r--vespamalloc/src/tests/overwrite/expectsignal.cpp13
-rw-r--r--vespamalloc/src/tests/thread/thread.cpp2
46 files changed, 316 insertions, 3529 deletions
diff --git a/eval/src/tests/apps/analyze_onnx_model/analyze_onnx_model_test.cpp b/eval/src/tests/apps/analyze_onnx_model/analyze_onnx_model_test.cpp
index 72ef0346ea3..dc4527dd5c8 100644
--- a/eval/src/tests/apps/analyze_onnx_model/analyze_onnx_model_test.cpp
+++ b/eval/src/tests/apps/analyze_onnx_model/analyze_onnx_model_test.cpp
@@ -97,4 +97,4 @@ TEST_F("test error: symbolic size mismatch", ServerCmd(probe_cmd, ServerCmd::cap
//-----------------------------------------------------------------------------
-TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); }
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/eval/src/tests/apps/eval_expr/eval_expr_test.cpp b/eval/src/tests/apps/eval_expr/eval_expr_test.cpp
index fd103829618..d7979c6dbea 100644
--- a/eval/src/tests/apps/eval_expr/eval_expr_test.cpp
+++ b/eval/src/tests/apps/eval_expr/eval_expr_test.cpp
@@ -4,7 +4,6 @@
#include <vespa/vespalib/testkit/time_bomb.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/data/slime/slime.h>
-#include <vespa/vespalib/util/child_process.h>
#include <vespa/vespalib/data/input.h>
#include <vespa/vespalib/data/output.h>
#include <vespa/vespalib/data/simple_buffer.h>
@@ -168,4 +167,4 @@ TEST_F("require that type issues produces error", Server()) {
//-----------------------------------------------------------------------------
-TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); }
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/eval/src/vespa/eval/eval/test/test_io.cpp b/eval/src/vespa/eval/eval/test/test_io.cpp
index 044b6779431..5512ecf0c1c 100644
--- a/eval/src/vespa/eval/eval/test/test_io.cpp
+++ b/eval/src/vespa/eval/eval/test/test_io.cpp
@@ -66,59 +66,6 @@ StdOut::commit(size_t bytes)
//-----------------------------------------------------------------------------
-ChildIn::ChildIn(ChildProcess &child)
- : _child(child),
- _output()
-{
-}
-
-WritableMemory
-ChildIn::reserve(size_t bytes)
-{
- return _output.reserve(bytes);
-}
-
-Output &
-ChildIn::commit(size_t bytes)
-{
- _output.commit(bytes);
- Memory buf = _output.obtain();
- REQUIRE(_child.write(buf.data, buf.size));
- _output.evict(buf.size);
- return *this;
-}
-
-//-----------------------------------------------------------------------------
-
-ChildOut::ChildOut(ChildProcess &child)
- : _child(child),
- _input()
-{
- REQUIRE(_child.running());
- REQUIRE(!_child.failed());
-}
-
-Memory
-ChildOut::obtain()
-{
- if ((_input.get().size == 0) && !_child.eof()) {
- WritableMemory buf = _input.reserve(4_Ki);
- uint32_t res = _child.read(buf.data, buf.size);
- REQUIRE((res > 0) || _child.eof());
- _input.commit(res);
- }
- return _input.obtain();
-}
-
-Input &
-ChildOut::evict(size_t bytes)
-{
- _input.evict(bytes);
- return *this;
-}
-
-//-----------------------------------------------------------------------------
-
void
ServerCmd::maybe_close()
{
@@ -132,10 +79,8 @@ void
ServerCmd::maybe_exit()
{
if (!_exited) {
- read_until_eof(_child_stdout);
- assert(_child.wait());
- assert(!_child.running());
- _exit_code = _child.getExitCode();
+ read_until_eof(_child);
+ _exit_code = _child.join();
_exited = true;
}
}
@@ -156,9 +101,7 @@ ServerCmd::dump_message(const char *prefix, const Slime &slime)
}
ServerCmd::ServerCmd(vespalib::string cmd)
- : _child(cmd.c_str()),
- _child_stdin(_child),
- _child_stdout(_child),
+ : _child(cmd),
_basename(fs::path(cmd).filename()),
_closed(false),
_exited(false),
@@ -167,9 +110,7 @@ ServerCmd::ServerCmd(vespalib::string cmd)
}
ServerCmd::ServerCmd(vespalib::string cmd, capture_stderr_tag)
- : _child(cmd.c_str(), ChildProcess::capture_stderr_tag()),
- _child_stdin(_child),
- _child_stdout(_child),
+ : _child(cmd, true),
_basename(fs::path(cmd).filename()),
_closed(false),
_exited(false),
@@ -187,9 +128,9 @@ Slime
ServerCmd::invoke(const Slime &req)
{
dump_message("request --> ", req);
- write_compact(req, _child_stdin);
+ write_compact(req, _child);
Slime reply;
- REQUIRE(JsonFormat::decode(_child_stdout, reply));
+ REQUIRE(JsonFormat::decode(_child, reply));
dump_message("reply <-- ", reply);
return reply;
}
@@ -199,12 +140,12 @@ ServerCmd::write_then_read_all(const vespalib::string &input)
{
vespalib::string result;
dump_string("input --> ", input);
- memcpy(_child_stdin.reserve(input.size()).data, input.data(), input.size());
- _child_stdin.commit(input.size());
+ memcpy(_child.reserve(input.size()).data, input.data(), input.size());
+ _child.commit(input.size());
maybe_close();
- for (auto mem = _child_stdout.obtain(); mem.size > 0; mem = _child_stdout.obtain()) {
+ for (auto mem = _child.obtain(); mem.size > 0; mem = _child.obtain()) {
result.append(mem.data, mem.size);
- _child_stdout.evict(mem.size);
+ _child.evict(mem.size);
}
dump_string("output <-- ", result);
return result;
diff --git a/eval/src/vespa/eval/eval/test/test_io.h b/eval/src/vespa/eval/eval/test/test_io.h
index 62fd6588780..26fe260c857 100644
--- a/eval/src/vespa/eval/eval/test/test_io.h
+++ b/eval/src/vespa/eval/eval/test/test_io.h
@@ -9,7 +9,7 @@
#include <vespa/vespalib/data/simple_buffer.h>
#include <vespa/vespalib/data/slime/slime.h>
#include <vespa/vespalib/util/size_literals.h>
-#include <vespa/vespalib/util/child_process.h>
+#include <vespa/vespalib/process/process.h>
#include <functional>
namespace vespalib::eval::test {
@@ -40,38 +40,12 @@ public:
};
/**
- * Output adapter used to write to stdin of a child process.
- **/
-class ChildIn : public Output {
- ChildProcess &_child;
- SimpleBuffer _output;
-public:
- ChildIn(ChildProcess &child);
- WritableMemory reserve(size_t bytes) override;
- Output &commit(size_t bytes) override;
-};
-
-/**
- * Input adapter used to read from stdout of a child process.
- **/
-class ChildOut : public Input {
- ChildProcess &_child;
- SimpleBuffer _input;
-public:
- ChildOut(ChildProcess &child);
- Memory obtain() override;
- Input &evict(size_t bytes) override;
-};
-
-/**
* A command run as a child process that acts as a server reading json
* from stdin and writing json to stdout.
**/
class ServerCmd {
private:
- ChildProcess _child;
- ChildIn _child_stdin;
- ChildOut _child_stdout;
+ Process _child;
vespalib::string _basename;
bool _closed;
bool _exited;
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);
-};
-
-
diff --git a/fnet/src/tests/examples/examples_test.cpp b/fnet/src/tests/examples/examples_test.cpp
index dc7b051bd80..b6476311adb 100644
--- a/fnet/src/tests/examples/examples_test.cpp
+++ b/fnet/src/tests/examples/examples_test.cpp
@@ -1,6 +1,6 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/vespalib/util/child_process.h>
+#include <vespa/vespalib/process/process.h>
#include <vespa/vespalib/util/size_literals.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/thread.h>
@@ -11,209 +11,200 @@
static const int PORT0 = 18570;
static const int PORT1 = 18571;
-using vespalib::ChildProcess;
+using vespalib::Process;
+using vespalib::make_string_short::fmt;
-bool runProc(ChildProcess &proc, std::atomic<bool> &done) {
- char buf[4_Ki];
- proc.close(); // close stdin
- while (proc.running() && !done) {
- if (!proc.eof()) {
- uint32_t res = proc.read(buf, sizeof(buf), 10);
- std::string tmp(buf, res);
- fprintf(stderr, "%s", tmp.c_str());
- }
- vespalib::Thread::sleep(10);
+int run_proc(Process &proc, vespalib::string &output) {
+ proc.close();
+ for (auto mem = proc.obtain(); mem.size > 0; mem = proc.obtain()) {
+ output.append(mem.data, mem.size);
+ proc.evict(mem.size);
}
- if (done && proc.running()) {
- kill(proc.getPid(), SIGTERM);
- return proc.wait(60000);
+ return proc.join();
+}
+
+void consume_result(Process &proc) {
+ vespalib::string output;
+ int status = run_proc(proc, output);
+ fprintf(stderr, "child output(server): >>>%s<<<\n", output.c_str());
+ if (status != 0) {
+ // Allow 'killed by SIGTERM' result status. This is needed as
+ // some clients will exit with success status even when the
+ // server is not yet running, resulting in the server being
+ // killed before it has installed any signal handlers.
+ EXPECT_TRUE(status & 0x80000000);
+ status &= 0x7fffffff;
+ EXPECT_TRUE(WIFSIGNALED(status));
+ EXPECT_EQUAL(WTERMSIG(status), SIGTERM);
}
- return !proc.failed();
}
-bool runProc(const std::string &cmd) {
- bool ok = false;
- for (size_t retry = 0; !ok && retry < 60; ++retry) {
+bool run_with_retry(const vespalib::string &cmd) {
+ for (size_t retry = 0; retry < 60; ++retry) {
if (retry > 0) {
fprintf(stderr, "retrying command in 500ms...\n");
vespalib::Thread::sleep(500);
}
- std::atomic<bool> done(false);
- ChildProcess proc(cmd.c_str());
- ok = runProc(proc, done);
+ vespalib::string output;
+ Process proc(cmd, true);
+ int status = run_proc(proc, output);
+ fprintf(stderr, "child output(client): >>>%s<<<\n", output.c_str());
+ if (status == 0) {
+ return true;
+ }
}
- return ok;
+ fprintf(stderr, "giving up...\n");
+ return false;
}
TEST("usage") {
- std::atomic<bool> done(false);
- {
- ChildProcess proc("exec ../../examples/proxy/fnet_proxy_app");
- EXPECT_FALSE(runProc(proc, done));
- }
- {
- ChildProcess proc("exec ../../examples/ping/fnet_pingserver_app");
- EXPECT_FALSE(runProc(proc, done));
- }
- {
- ChildProcess proc("exec ../../examples/ping/fnet_pingclient_app");
- EXPECT_FALSE(runProc(proc, done));
- }
- {
- ChildProcess proc("exec ../../examples/frt/rpc/fnet_rpc_client_app");
- EXPECT_FALSE(runProc(proc, done));
- }
- {
- ChildProcess proc("exec ../../examples/frt/rpc/fnet_rpc_server_app");
- EXPECT_FALSE(runProc(proc, done));
- }
- {
- ChildProcess proc("exec ../../examples/frt/rpc/fnet_echo_client_app");
- EXPECT_FALSE(runProc(proc, done));
- }
- {
- ChildProcess proc("exec ../../examples/frt/rpc/vespa-rpc-info");
- EXPECT_FALSE(runProc(proc, done));
- }
- {
- ChildProcess proc("exec ../../examples/frt/rpc/vespa-rpc-invoke-bin");
- EXPECT_FALSE(runProc(proc, done));
- }
- {
- ChildProcess proc("exec ../../examples/frt/rpc/fnet_rpc_callback_server_app");
- EXPECT_FALSE(runProc(proc, done));
- }
- {
- ChildProcess proc("exec ../../examples/frt/rpc/fnet_rpc_callback_client_app");
- EXPECT_FALSE(runProc(proc, done));
- }
+ EXPECT_FALSE(Process::run("exec ../../examples/proxy/fnet_proxy_app"));
+ EXPECT_FALSE(Process::run("exec ../../examples/ping/fnet_pingserver_app"));
+ EXPECT_FALSE(Process::run("exec ../../examples/ping/fnet_pingclient_app"));
+ EXPECT_FALSE(Process::run("exec ../../examples/frt/rpc/fnet_rpc_client_app"));
+ EXPECT_FALSE(Process::run("exec ../../examples/frt/rpc/fnet_rpc_server_app"));
+ EXPECT_FALSE(Process::run("exec ../../examples/frt/rpc/fnet_echo_client_app"));
+ EXPECT_FALSE(Process::run("exec ../../examples/frt/rpc/vespa-rpc-info"));
+ EXPECT_FALSE(Process::run("exec ../../examples/frt/rpc/vespa-rpc-invoke-bin"));
+ EXPECT_FALSE(Process::run("exec ../../examples/frt/rpc/fnet_rpc_callback_server_app"));
+ EXPECT_FALSE(Process::run("exec ../../examples/frt/rpc/fnet_rpc_callback_client_app"));
}
TEST("timeout") {
- std::string out;
- EXPECT_TRUE(ChildProcess::run("exec ../../examples/timeout/fnet_timeout_app", out));
+ vespalib::string out;
+ EXPECT_TRUE(Process::run("exec ../../examples/timeout/fnet_timeout_app", out));
fprintf(stderr, "%s\n", out.c_str());
}
-TEST_MT_F("ping", 2, std::atomic<bool>()) {
+TEST_MT_F("ping", 2, pid_t(-1)) {
if (thread_id == 0) {
- ChildProcess proc(vespalib::make_string("exec ../../examples/ping/fnet_pingserver_app tcp/%d",
- PORT0).c_str());
+ Process proc(fmt("exec ../../examples/ping/fnet_pingserver_app tcp/%d",
+ PORT0), true);
+ f1 = proc.pid();
TEST_BARRIER();
- EXPECT_TRUE(runProc(proc, f1));
+ TEST_DO(consume_result(proc));
} else {
TEST_BARRIER();
- EXPECT_TRUE(runProc(vespalib::make_string("exec ../../examples/ping/fnet_pingclient_app tcp/localhost:%d",
- PORT0).c_str()));
- f1 = true;
+ EXPECT_TRUE(run_with_retry(fmt("exec ../../examples/ping/fnet_pingclient_app tcp/localhost:%d",
+ PORT0)));
+ kill(f1, SIGTERM);
}
}
-TEST_MT_F("ping times out", 2, std::atomic<bool>()) {
+TEST_MT_F("ping times out", 2, pid_t(-1)) {
if (thread_id == 0) {
- ChildProcess proc(vespalib::make_string("exec ../../examples/frt/rpc/fnet_rpc_server_app tcp/%d",
- PORT0).c_str());
+ Process proc(fmt("exec ../../examples/frt/rpc/fnet_rpc_server_app tcp/%d",
+ PORT0), true);
+ f1 = proc.pid();
TEST_BARRIER();
- EXPECT_TRUE(runProc(proc, f1));
+ TEST_DO(consume_result(proc));
} else {
float timeout_s = 0.1;
TEST_BARRIER();
- EXPECT_TRUE(runProc(vespalib::make_string("exec ../../examples/ping/fnet_pingclient_app tcp/localhost:%d %f",
- PORT0, timeout_s).c_str()));
- f1 = true;
+ EXPECT_TRUE(run_with_retry(fmt("exec ../../examples/ping/fnet_pingclient_app tcp/localhost:%d %f",
+ PORT0, timeout_s)));
+ kill(f1, SIGTERM);
}
}
-TEST_MT_F("ping with proxy", 3, std::atomic<bool>()) {
+TEST_MT_FF("ping with proxy", 3, pid_t(-1), pid_t(-1)) {
if (thread_id == 0) {
- ChildProcess proc(vespalib::make_string("exec ../../examples/ping/fnet_pingserver_app tcp/%d",
- PORT0).c_str());
+ Process proc(fmt("exec ../../examples/ping/fnet_pingserver_app tcp/%d",
+ PORT0), true);
+ f1 = proc.pid();
TEST_BARRIER();
- EXPECT_TRUE(runProc(proc, f1));
+ TEST_DO(consume_result(proc));
} else if (thread_id == 1) {
- ChildProcess proc(vespalib::make_string("exec ../../examples/proxy/fnet_proxy_app tcp/%d tcp/localhost:%d",
- PORT1, PORT0).c_str());
+ Process proc(fmt("exec ../../examples/proxy/fnet_proxy_app tcp/%d tcp/localhost:%d",
+ PORT1, PORT0), true);
+ f2 = proc.pid();
TEST_BARRIER();
- EXPECT_TRUE(runProc(proc, f1));
+ TEST_DO(consume_result(proc));
} else {
TEST_BARRIER();
- EXPECT_TRUE(runProc(vespalib::make_string("exec ../../examples/ping/fnet_pingclient_app tcp/localhost:%d",
- PORT1).c_str()));
- f1 = true;
+ EXPECT_TRUE(run_with_retry(fmt("exec ../../examples/ping/fnet_pingclient_app tcp/localhost:%d",
+ PORT1)));
+ kill(f1, SIGTERM);
+ kill(f2, SIGTERM);
}
}
-TEST_MT_F("rpc client server", 2, std::atomic<bool>()) {
+TEST_MT_F("rpc client server", 2, pid_t(-1)) {
if (thread_id == 0) {
- ChildProcess proc(vespalib::make_string("exec ../../examples/frt/rpc/fnet_rpc_server_app tcp/%d",
- PORT0).c_str());
+ Process proc(fmt("exec ../../examples/frt/rpc/fnet_rpc_server_app tcp/%d",
+ PORT0), true);
+ f1 = proc.pid();
TEST_BARRIER();
- EXPECT_TRUE(runProc(proc, f1));
+ TEST_DO(consume_result(proc));
} else {
TEST_BARRIER();
- EXPECT_TRUE(runProc(vespalib::make_string("exec ../../examples/frt/rpc/fnet_rpc_client_app tcp/localhost:%d",
- PORT0).c_str()));
- f1 = true;
+ EXPECT_TRUE(run_with_retry(fmt("exec ../../examples/frt/rpc/fnet_rpc_client_app tcp/localhost:%d",
+ PORT0)));
+ kill(f1, SIGTERM);
}
}
-TEST_MT_F("rpc echo client", 2, std::atomic<bool>()) {
+TEST_MT_F("rpc echo client", 2, pid_t(-1)) {
if (thread_id == 0) {
- ChildProcess proc(vespalib::make_string("exec ../../examples/frt/rpc/fnet_rpc_server_app tcp/%d",
- PORT0).c_str());
+ Process proc(fmt("exec ../../examples/frt/rpc/fnet_rpc_server_app tcp/%d",
+ PORT0), true);
+ f1 = proc.pid();
TEST_BARRIER();
- EXPECT_TRUE(runProc(proc, f1));
+ TEST_DO(consume_result(proc));
} else {
TEST_BARRIER();
- EXPECT_TRUE(runProc(vespalib::make_string("exec ../../examples/frt/rpc/fnet_echo_client_app tcp/localhost:%d",
- PORT0).c_str()));
- f1 = true;
+ EXPECT_TRUE(run_with_retry(fmt("exec ../../examples/frt/rpc/fnet_echo_client_app tcp/localhost:%d",
+ PORT0)));
+ kill(f1, SIGTERM);
}
}
-TEST_MT_F("rpc info", 2, std::atomic<bool>()) {
+TEST_MT_F("rpc info", 2, pid_t(-1)) {
if (thread_id == 0) {
- ChildProcess proc(vespalib::make_string("exec ../../examples/frt/rpc/fnet_rpc_server_app tcp/%d",
- PORT0).c_str());
+ Process proc(fmt("exec ../../examples/frt/rpc/fnet_rpc_server_app tcp/%d",
+ PORT0), true);
+ f1 = proc.pid();
TEST_BARRIER();
- EXPECT_TRUE(runProc(proc, f1));
+ TEST_DO(consume_result(proc));
} else {
TEST_BARRIER();
- EXPECT_TRUE(runProc(vespalib::make_string("exec ../../examples/frt/rpc/vespa-rpc-info tcp/localhost:%d",
- PORT0).c_str()));
- EXPECT_TRUE(runProc(vespalib::make_string("exec ../../examples/frt/rpc/vespa-rpc-info tcp/localhost:%d verbose",
- PORT0).c_str()));
- f1 = true;
+ EXPECT_TRUE(run_with_retry(fmt("exec ../../examples/frt/rpc/vespa-rpc-info tcp/localhost:%d",
+ PORT0)));
+ EXPECT_TRUE(run_with_retry(fmt("exec ../../examples/frt/rpc/vespa-rpc-info tcp/localhost:%d verbose",
+ PORT0)));
+ kill(f1, SIGTERM);
}
}
-TEST_MT_F("rpc invoke", 2, std::atomic<bool>()) {
+TEST_MT_F("rpc invoke", 2, pid_t(-1)) {
if (thread_id == 0) {
- ChildProcess proc(vespalib::make_string("exec ../../examples/frt/rpc/fnet_rpc_server_app tcp/%d",
- PORT0).c_str());
+ Process proc(fmt("exec ../../examples/frt/rpc/fnet_rpc_server_app tcp/%d",
+ PORT0), true);
+ f1 = proc.pid();
TEST_BARRIER();
- EXPECT_TRUE(runProc(proc, f1));
+ TEST_DO(consume_result(proc));
} else {
TEST_BARRIER();
- EXPECT_TRUE(runProc(vespalib::make_string("exec ../../examples/frt/rpc/vespa-rpc-invoke-bin tcp/localhost:%d frt.rpc.echo "
- "b:1 h:2 i:4 l:8 f:0.5 d:0.25 s:foo",
- PORT0).c_str()));
- f1 = true;
+ EXPECT_TRUE(run_with_retry(fmt("exec ../../examples/frt/rpc/vespa-rpc-invoke-bin tcp/localhost:%d frt.rpc.echo "
+ "b:1 h:2 i:4 l:8 f:0.5 d:0.25 s:foo",
+ PORT0)));
+ kill(f1, SIGTERM);
}
}
-TEST_MT_F("rpc callback client server", 2, std::atomic<bool>()) {
+TEST_MT_F("rpc callback client server", 2, pid_t(-1)) {
if (thread_id == 0) {
- ChildProcess proc(vespalib::make_string("exec ../../examples/frt/rpc/fnet_rpc_callback_server_app tcp/%d",
- PORT0).c_str());
+ Process proc(fmt("exec ../../examples/frt/rpc/fnet_rpc_callback_server_app tcp/%d",
+ PORT0), true);
+ f1 = proc.pid();
TEST_BARRIER();
- EXPECT_TRUE(runProc(proc, f1));
+ TEST_DO(consume_result(proc));
} else {
TEST_BARRIER();
- EXPECT_TRUE(runProc(vespalib::make_string("exec ../../examples/frt/rpc/fnet_rpc_callback_client_app tcp/localhost:%d",
- PORT0).c_str()));
- f1 = true;
+ EXPECT_TRUE(run_with_retry(fmt("exec ../../examples/frt/rpc/fnet_rpc_callback_client_app tcp/localhost:%d",
+ PORT0)));
+ kill(f1, SIGTERM);
}
}
-TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); }
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/searchcore/src/apps/vespa-dump-feed/vespa-dump-feed.cpp b/searchcore/src/apps/vespa-dump-feed/vespa-dump-feed.cpp
index ddb41ae67a6..133912548b1 100644
--- a/searchcore/src/apps/vespa-dump-feed/vespa-dump-feed.cpp
+++ b/searchcore/src/apps/vespa-dump-feed/vespa-dump-feed.cpp
@@ -9,11 +9,12 @@
#include <vespa/messagebus/network/rpcnetworkparams.h>
#include <vespa/vespalib/io/fileutil.h>
#include <vespa/vespalib/util/signalhandler.h>
-#include <vespa/vespalib/util/child_process.h>
+#include <vespa/vespalib/process/process.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/config/common/exceptions.h>
#include <vespa/config/helper/configgetter.hpp>
+#include <vespa/fastos/app.h>
#include <iostream>
@@ -114,7 +115,6 @@ FeedHandler::~FeedHandler()
class App : public FastOS_Application
{
public:
- virtual bool useProcessStarter() const override { return true; }
virtual int Main() override;
};
@@ -200,8 +200,8 @@ App::Main()
std::string feedCmd(vespalib::make_string("vespa-feeder --route \"%s\" %s",
route.c_str(), feedFile.c_str()));
fprintf(stderr, "running feed command: %s\n", feedCmd.c_str());
- std::string feederOutput;
- bool feedingOk = vespalib::ChildProcess::run(feedCmd.c_str(), feederOutput);
+ vespalib::string feederOutput;
+ bool feedingOk = vespalib::Process::run(feedCmd, feederOutput);
if (!feedingOk) {
fprintf(stderr, "error: feed command failed\n");
fprintf(stderr, "feed command output:\n-----\n%s\n-----\n", feederOutput.c_str());
diff --git a/searchcore/src/tests/proton/verify_ranksetup/verify_ranksetup_test.cpp b/searchcore/src/tests/proton/verify_ranksetup/verify_ranksetup_test.cpp
index c6c65f45e4b..1feb46cfdb7 100644
--- a/searchcore/src/tests/proton/verify_ranksetup/verify_ranksetup_test.cpp
+++ b/searchcore/src/tests/proton/verify_ranksetup/verify_ranksetup_test.cpp
@@ -1,6 +1,6 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/vespalib/util/child_process.h>
+#include <vespa/vespalib/process/process.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/searchcommon/common/schema.h>
#include <vespa/searchlib/fef/indexproperties.h>
@@ -220,7 +220,7 @@ struct Setup {
}
bool verify() {
generate();
- return vespalib::ChildProcess::run(fmt("%s dir:%s", prog, gen_dir.c_str()).c_str());
+ return vespalib::Process::run(fmt("%s dir:%s", prog, gen_dir.c_str()));
}
void verify_valid(std::initializer_list<std::string> features) {
for (const std::string &f: features) {
@@ -288,12 +288,12 @@ struct ShadowSetup : Setup {
};
TEST_F("print usage", Setup()) {
- EXPECT_TRUE(!vespalib::ChildProcess::run(fmt("%s", prog).c_str()));
+ EXPECT_TRUE(!vespalib::Process::run(fmt("%s", prog)));
}
TEST_F("setup output directory", Setup()) {
- ASSERT_TRUE(vespalib::ChildProcess::run(fmt("rm -rf %s", gen_dir.c_str()).c_str()));
- ASSERT_TRUE(vespalib::ChildProcess::run(fmt("mkdir %s", gen_dir.c_str()).c_str()));
+ ASSERT_TRUE(vespalib::Process::run(fmt("rm -rf %s", gen_dir.c_str())));
+ ASSERT_TRUE(vespalib::Process::run(fmt("mkdir %s", gen_dir.c_str())));
}
//-----------------------------------------------------------------------------
@@ -458,7 +458,7 @@ TEST_F("require that broken fragile model without dry-run passes verification",
//-----------------------------------------------------------------------------
TEST_F("cleanup files", Setup()) {
- ASSERT_TRUE(vespalib::ChildProcess::run(fmt("rm -rf %s", gen_dir.c_str()).c_str()));
+ ASSERT_TRUE(vespalib::Process::run(fmt("rm -rf %s", gen_dir.c_str())));
}
-TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); }
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/searchlib/src/apps/vespa-ranking-expression-analyzer/vespa-ranking-expression-analyzer.cpp b/searchlib/src/apps/vespa-ranking-expression-analyzer/vespa-ranking-expression-analyzer.cpp
index 8db85559f49..d4c11d5ac2f 100644
--- a/searchlib/src/apps/vespa-ranking-expression-analyzer/vespa-ranking-expression-analyzer.cpp
+++ b/searchlib/src/apps/vespa-ranking-expression-analyzer/vespa-ranking-expression-analyzer.cpp
@@ -331,7 +331,6 @@ State::~State() {}
struct MyApp : public FastOS_Application {
int Main() override;
int usage();
- virtual bool useProcessStarter() const override { return false; }
};
int
diff --git a/staging_vespalib/src/tests/state_server/state_server_test.cpp b/staging_vespalib/src/tests/state_server/state_server_test.cpp
index 5903970b740..cb80a44a675 100644
--- a/staging_vespalib/src/tests/state_server/state_server_test.cpp
+++ b/staging_vespalib/src/tests/state_server/state_server_test.cpp
@@ -12,7 +12,7 @@
#include <vespa/vespalib/net/simple_metrics_producer.h>
#include <vespa/vespalib/net/simple_component_config_producer.h>
#include <vespa/vespalib/util/stringfmt.h>
-#include <vespa/vespalib/util/child_process.h>
+#include <vespa/vespalib/process/process.h>
#include <vespa/vespalib/net/state_explorer.h>
#include <vespa/vespalib/net/slime_explorer.h>
#include <vespa/vespalib/net/generic_state_handler.h>
@@ -39,8 +39,8 @@ std::map<vespalib::string,vespalib::string> empty_params;
//-----------------------------------------------------------------------------
vespalib::string run_cmd(const vespalib::string &cmd) {
- std::string out;
- ASSERT_TRUE(ChildProcess::run(cmd.c_str(), out));
+ vespalib::string out;
+ ASSERT_TRUE(Process::run(cmd.c_str(), out));
return out;
}
@@ -511,7 +511,7 @@ TEST("require that generic state can be explored") {
check_json(json_list_two, state_handler.get(host_tag, root_path + "list/two", empty_params));
}
-TEST_MAIN_WITH_PROCESS_PROXY() {
+TEST_MAIN() {
mkdir("var", S_IRWXU);
mkdir("var/run", S_IRWXU);
TEST_RUN_ALL();
diff --git a/vbench/src/tests/app_dumpurl/app_dumpurl_test.cpp b/vbench/src/tests/app_dumpurl/app_dumpurl_test.cpp
index 0d5ee1e507c..3dc01725a3e 100644
--- a/vbench/src/tests/app_dumpurl/app_dumpurl_test.cpp
+++ b/vbench/src/tests/app_dumpurl/app_dumpurl_test.cpp
@@ -1,11 +1,11 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/testapp.h>
#include <vbench/test/all.h>
-#include <vespa/vespalib/util/child_process.h>
+#include <vespa/vespalib/process/process.h>
#include <vespa/vespalib/net/crypto_engine.h>
using namespace vbench;
-using vespalib::ChildProcess;
+using vespalib::Process;
using InputReader = vespalib::InputReader;
using OutputWriter = vespalib::OutputWriter;
@@ -31,8 +31,8 @@ void readUntil(Input &input, SimpleBuffer &buffer, const string &end) {
}
TEST("dumpurl usage") {
- std::string out;
- EXPECT_FALSE(ChildProcess::run("../../apps/dumpurl/vbench_dumpurl_app", out));
+ vespalib::string out;
+ EXPECT_FALSE(Process::run("../../apps/dumpurl/vbench_dumpurl_app", out));
fprintf(stderr, "%s\n", out.c_str());
}
@@ -47,11 +47,11 @@ TEST_MT_F("run dumpurl", 2, ServerSocket()) {
out.write("\r\n");
out.write("data");
} else {
- std::string out;
- EXPECT_TRUE(ChildProcess::run(strfmt("../../apps/dumpurl/vbench_dumpurl_app localhost %d /foo",
- f1.port()).c_str(), out));
+ vespalib::string out;
+ EXPECT_TRUE(Process::run(strfmt("../../apps/dumpurl/vbench_dumpurl_app localhost %d /foo",
+ f1.port()).c_str(), out));
fprintf(stderr, "%s\n", out.c_str());
}
}
-TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); }
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vbench/src/tests/app_vbench/app_vbench_test.cpp b/vbench/src/tests/app_vbench/app_vbench_test.cpp
index f48c6fe0b05..f3223e84092 100644
--- a/vbench/src/tests/app_vbench/app_vbench_test.cpp
+++ b/vbench/src/tests/app_vbench/app_vbench_test.cpp
@@ -1,7 +1,7 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/testapp.h>
#include <vbench/test/all.h>
-#include <vespa/vespalib/util/child_process.h>
+#include <vespa/vespalib/process/process.h>
#include <vespa/vespalib/net/crypto_engine.h>
#include <vespa/vespalib/net/tls/tls_crypto_engine.h>
#include <vespa/vespalib/test/make_tls_options_for_testing.h>
@@ -11,7 +11,7 @@
#include <fcntl.h>
using namespace vbench;
-using vespalib::ChildProcess;
+using vespalib::Process;
using InputReader = vespalib::InputReader;
using OutputWriter = vespalib::OutputWriter;
@@ -31,8 +31,8 @@ void write_file(const vespalib::string &file_name, const vespalib::string &conte
}
TEST("vbench usage") {
- std::string out;
- EXPECT_FALSE(ChildProcess::run("../../apps/vbench/vbench_app", out));
+ vespalib::string out;
+ EXPECT_FALSE(Process::run("../../apps/vbench/vbench_app", out));
fprintf(stderr, "%s\n", out.c_str());
}
@@ -68,18 +68,18 @@ struct Servers {
TEST_MT_F("run vbench", 2, Servers()) {
if (thread_id == 0) {
- std::string out;
- EXPECT_TRUE(ChildProcess::run(strfmt("sed 's/_LOCAL_PORT_/%d/' vbench.cfg.template > vbench.cfg", f1.portal->listen_port()).c_str()));
- EXPECT_TRUE(ChildProcess::run("../../apps/vbench/vbench_app run vbench.cfg 2> vbench.out", out));
+ vespalib::string out;
+ EXPECT_TRUE(Process::run(strfmt("sed 's/_LOCAL_PORT_/%d/' vbench.cfg.template > vbench.cfg", f1.portal->listen_port()).c_str()));
+ EXPECT_TRUE(Process::run("../../apps/vbench/vbench_app run vbench.cfg 2> vbench.out", out));
fprintf(stderr, "null crypto: %s\n", out.c_str());
EXPECT_GREATER(f1.my_get.cnt, 10u);
} else {
- std::string tls_out;
- EXPECT_TRUE(ChildProcess::run(strfmt("sed 's/_LOCAL_PORT_/%d/' vbench.tls.cfg.template > vbench.tls.cfg", f1.tls_portal->listen_port()).c_str()));
- EXPECT_TRUE(ChildProcess::run("../../apps/vbench/vbench_app run vbench.tls.cfg 2> vbench.tls.out", tls_out));
+ vespalib::string tls_out;
+ EXPECT_TRUE(Process::run(strfmt("sed 's/_LOCAL_PORT_/%d/' vbench.tls.cfg.template > vbench.tls.cfg", f1.tls_portal->listen_port()).c_str()));
+ EXPECT_TRUE(Process::run("../../apps/vbench/vbench_app run vbench.tls.cfg 2> vbench.tls.out", tls_out));
fprintf(stderr, "tls crypto: %s\n", tls_out.c_str());
EXPECT_GREATER(f1.my_tls_get.cnt, 10u);
}
}
-TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); }
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/CMakeLists.txt b/vespalib/CMakeLists.txt
index 80308a75bd5..6fb832b21d3 100644
--- a/vespalib/CMakeLists.txt
+++ b/vespalib/CMakeLists.txt
@@ -29,7 +29,6 @@ vespa_define_module(
src/tests/btree/btree_store
src/tests/btree/btree-scan-speed
src/tests/btree/btree-stress
- src/tests/child_process
src/tests/component
src/tests/compress
src/tests/compression
diff --git a/vespalib/src/tests/assert/assert_test.cpp b/vespalib/src/tests/assert/assert_test.cpp
index 49f4d2194f4..e953fc439c3 100644
--- a/vespalib/src/tests/assert/assert_test.cpp
+++ b/vespalib/src/tests/assert/assert_test.cpp
@@ -1,6 +1,6 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/vespalib/util/child_process.h>
+#include <vespa/vespalib/process/process.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/assert.h>
#include <vespa/vespalib/io/fileutil.h>
@@ -16,24 +16,21 @@ TEST("that it borks the first time.") {
vespalib::rmdir("var", true);
ASSERT_TRUE(vespalib::mkdir(assertDir, true));
{
- ChildProcess proc("ulimit -c 0 && exec env VESPA_HOME=./ ./vespalib_asserter_app myassert 10000");
- proc.wait();
- ASSERT_EQUAL(proc.getExitCode() & 0x7f, 6);
+ Process proc("ulimit -c 0 && exec env VESPA_HOME=./ ./vespalib_asserter_app myassert 10000");
+ ASSERT_EQUAL(proc.join() & 0x7f, 6);
}
{
- ChildProcess proc("ulimit -c 0 && exec env VESPA_HOME=./ ./vespalib_asserter_app myassert 10000");
- proc.readLine(assertName);
- proc.wait();
- ASSERT_EQUAL(proc.getExitCode() & 0x7f, 0);
+ Process proc("ulimit -c 0 && exec env VESPA_HOME=./ ./vespalib_asserter_app myassert 10000");
+ assertName = proc.read_line();
+ ASSERT_EQUAL(proc.join() & 0x7f, 0);
}
ASSERT_EQUAL(0, unlink(assertName.c_str()));
{
- ChildProcess proc("ulimit -c 0 && exec env VESPA_HOME=./ ./vespalib_asserter_app myassert 10000");
- proc.wait();
- ASSERT_EQUAL(proc.getExitCode() & 0x7f, 6);
+ Process proc("ulimit -c 0 && exec env VESPA_HOME=./ ./vespalib_asserter_app myassert 10000");
+ ASSERT_EQUAL(proc.join() & 0x7f, 6);
}
ASSERT_EQUAL(0, unlink(assertName.c_str()));
ASSERT_TRUE(vespalib::rmdir("var", true));
}
-TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); }
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/child_process/.gitignore b/vespalib/src/tests/child_process/.gitignore
deleted file mode 100644
index 7e094c772a6..00000000000
--- a/vespalib/src/tests/child_process/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-.depend
-Makefile
-child_process_test
-vespalib_child_process_test_app
diff --git a/vespalib/src/tests/child_process/CMakeLists.txt b/vespalib/src/tests/child_process/CMakeLists.txt
deleted file mode 100644
index b0503f7b08c..00000000000
--- a/vespalib/src/tests/child_process/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(vespalib_child_process_test_app TEST
- SOURCES
- child_process_test.cpp
- DEPENDS
- vespalib
-)
-vespa_add_test(NAME vespalib_child_process_test_app COMMAND vespalib_child_process_test_app COST 30)
diff --git a/vespalib/src/tests/child_process/child_process_test.cpp b/vespalib/src/tests/child_process/child_process_test.cpp
deleted file mode 100644
index d8ed707c1bf..00000000000
--- a/vespalib/src/tests/child_process/child_process_test.cpp
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/vespalib/util/child_process.h>
-
-using vespalib::ChildProcess;
-
-TEST("simple run, ignore output") {
- EXPECT_TRUE(ChildProcess::run("echo foo"));
-}
-
-TEST("simple run, ignore output, failure") {
- EXPECT_TRUE(!ChildProcess::run("false"));
-}
-
-TEST("simple run, ignore output, timeout") {
- EXPECT_TRUE(!ChildProcess::run("exec sleep 60", 10));
-}
-
-TEST("simple run") {
- std::string out;
- EXPECT_TRUE(ChildProcess::run("/bin/echo -n foo", out));
- EXPECT_EQUAL(out, "foo");
-}
-
-TEST("simple run, strip single-line trailing newline") {
- std::string out;
- EXPECT_TRUE(ChildProcess::run("echo foo", out));
- EXPECT_EQUAL(out, "foo");
-}
-
-TEST("simple run, don't strip multi-line output") {
- std::string out;
- EXPECT_TRUE(ChildProcess::run("perl -e 'print \"foo\\n\\n\"'", out));
- EXPECT_EQUAL(out, "foo\n\n");
-}
-
-TEST("simple run with input") {
- std::string in = "bar";
- std::string out;
- EXPECT_TRUE(ChildProcess::run(in, "cat", out));
- EXPECT_EQUAL(out, "bar");
-}
-
-TEST("simple run with input, strip single-line trailing newline") {
- std::string in = "bar\n";
- std::string out;
- EXPECT_TRUE(ChildProcess::run(in, "cat", out));
- EXPECT_EQUAL(out, "bar");
-}
-
-TEST("simple run with input, don't strip multi-line output") {
- std::string in = "bar\n\n";
- std::string out;
- EXPECT_TRUE(ChildProcess::run(in, "cat", out));
- EXPECT_EQUAL("bar\n\n", out);
-}
-
-TEST_MT("simple run, partial output due to timeout", 2) {
- std::string out;
- std::vector<size_t> timeouts({150, 300, 3000, 6000, 60000});
- const char *my_cmd = "exec perl -e '$| = 1; print \"foo\\\n\"; sleep(600); print \"bar\\\n\"'";
- for (size_t timeout: timeouts) {
- fprintf(stderr, "... verifying partial output with%s input (timeout = %zu)\n",
- (thread_id == 0) ? "out" : "", timeout);
- if (thread_id == 0) {
- out.clear();
- EXPECT_TRUE(!ChildProcess::run(my_cmd, out, timeout));
- } else {
- out.clear();
- std::string in = "ignored\n";
- EXPECT_TRUE(!ChildProcess::run(in, my_cmd, out, timeout));
- }
- if (out == "foo") {
- break;
- }
- }
- EXPECT_EQUAL(out, "foo");
-}
-
-TEST("proc failure") {
- ChildProcess proc("false");
- // read with length 0 will wait for output
- EXPECT_TRUE(proc.read(NULL, 0) == 0);
- EXPECT_TRUE(proc.wait(60000));
- EXPECT_TRUE(!proc.running());
- EXPECT_TRUE(proc.failed());
-}
-
-TEST("basic read/write") {
- int x;
- int read;
- char buf[64];
- ChildProcess proc("cat");
-
- EXPECT_TRUE(proc.running());
- EXPECT_TRUE(!proc.failed());
- EXPECT_TRUE(proc.write("foo", 3));
- for (x = 0, read = 0; x < 10 && read < 3; ++x) {
- read += proc.read(buf + read, sizeof(buf) - read);
- }
- EXPECT_TRUE(read == 3 && memcmp(buf, "foo", 3) == 0);
- EXPECT_TRUE(proc.write("bar!", 4));
- for (x = 0, read = 0; x < 10 && read < 4; ++x) {
- read += proc.read(buf + read, sizeof(buf) - read);
- }
- EXPECT_TRUE(read == 4 && memcmp(buf, "bar!", 4) == 0);
- EXPECT_TRUE(!proc.eof()); // not eof yet
- EXPECT_TRUE(proc.close()); // close stdin
- EXPECT_TRUE(!proc.eof()); // eof not detected yet
- EXPECT_TRUE(proc.read(buf, sizeof(buf)) == 0);
- EXPECT_TRUE(proc.eof());
- EXPECT_TRUE(proc.read(buf, sizeof(buf)) == 0);
- EXPECT_TRUE(proc.wait(60000));
- EXPECT_TRUE(!proc.running());
- EXPECT_TRUE(!proc.failed());
-}
-
-TEST("continuos run, readLine") {
- std::string str;
- ChildProcess proc("cat");
-
- EXPECT_TRUE(proc.running());
- EXPECT_TRUE(!proc.failed());
- EXPECT_TRUE(proc.write("foo\n", 4));
- EXPECT_TRUE(proc.readLine(str));
- EXPECT_EQUAL(str, "foo");
- EXPECT_TRUE(proc.write("bar!\n", 5));
- EXPECT_TRUE(proc.readLine(str));
- EXPECT_EQUAL(str, "bar!");
- EXPECT_TRUE(!proc.eof()); // not eof yet
- EXPECT_TRUE(proc.close()); // close stdin
- EXPECT_TRUE(!proc.eof()); // eof not detected yet
- EXPECT_TRUE(!proc.readLine(str));
- EXPECT_EQUAL(str, "");
- EXPECT_TRUE(proc.eof());
- EXPECT_TRUE(!proc.readLine(str));
- EXPECT_EQUAL(str, "");
- EXPECT_TRUE(proc.wait(60000));
- EXPECT_TRUE(!proc.running());
- EXPECT_TRUE(!proc.failed());
-}
-
-TEST("readLine, eof flushes last line") {
- std::string str;
- ChildProcess proc("cat");
-
- EXPECT_TRUE(proc.running());
- EXPECT_TRUE(!proc.failed());
- EXPECT_TRUE(proc.write("foo\n", 4));
- EXPECT_TRUE(proc.readLine(str));
- EXPECT_EQUAL(str, "foo");
- EXPECT_TRUE(proc.write("bar!", 4));
- EXPECT_TRUE(!proc.eof()); // not eof yet
- EXPECT_TRUE(proc.close()); // close stdin
- EXPECT_TRUE(!proc.eof()); // eof not detected yet
- EXPECT_TRUE(proc.readLine(str));
- EXPECT_EQUAL(str, "bar!");
- EXPECT_TRUE(proc.eof());
- EXPECT_TRUE(!proc.readLine(str));
- EXPECT_EQUAL(str, "");
- EXPECT_TRUE(proc.wait(60000));
- EXPECT_TRUE(!proc.running());
- EXPECT_TRUE(!proc.failed());
-}
-
-TEST("long continuos run, readLine") {
- std::string in;
- std::string out;
- ChildProcess proc("cat");
-
- EXPECT_TRUE(proc.running());
- EXPECT_TRUE(!proc.failed());
- for (uint32_t i = 0; i < 10000; ++i) {
- char num[32];
- sprintf(num, "%d", i);
- in.assign("long continous run, line ");
- in.append(num).append("\n");
- EXPECT_TRUE(proc.write(in.data(), in.length()));
- in.erase(in.size() - 1, 1);
- EXPECT_TRUE(proc.readLine(out));
- EXPECT_EQUAL(in, out);
- }
- EXPECT_TRUE(proc.running());
- EXPECT_TRUE(!proc.failed());
-}
-
-TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/drop-file-from-cache/drop_file_from_cache_test.cpp b/vespalib/src/tests/drop-file-from-cache/drop_file_from_cache_test.cpp
index e3344fb4106..63cec1caee1 100644
--- a/vespalib/src/tests/drop-file-from-cache/drop_file_from_cache_test.cpp
+++ b/vespalib/src/tests/drop-file-from-cache/drop_file_from_cache_test.cpp
@@ -1,25 +1,22 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/vespalib/util/child_process.h>
+#include <vespa/vespalib/process/process.h>
-using vespalib::ChildProcess;
+using vespalib::Process;
TEST("no arguments") {
- ChildProcess drop("../../apps/vespa-drop-file-from-cache/vespa-drop-file-from-cache");
- drop.wait();
- EXPECT_EQUAL(1, drop.getExitCode());
+ Process drop("../../apps/vespa-drop-file-from-cache/vespa-drop-file-from-cache");
+ EXPECT_EQUAL(1, drop.join());
}
TEST("file does not exist") {
- ChildProcess drop("../../apps/vespa-drop-file-from-cache/vespa-drop-file-from-cache not_exist");
- drop.wait();
- EXPECT_EQUAL(2, drop.getExitCode());
+ Process drop("../../apps/vespa-drop-file-from-cache/vespa-drop-file-from-cache not_exist");
+ EXPECT_EQUAL(2, drop.join());
}
TEST("All is well") {
- ChildProcess drop("../../apps/vespa-drop-file-from-cache/vespa-drop-file-from-cache vespalib_drop_file_from_cache_test_app");
- drop.wait();
- EXPECT_EQUAL(0, drop.getExitCode());
+ Process drop("../../apps/vespa-drop-file-from-cache/vespa-drop-file-from-cache vespalib_drop_file_from_cache_test_app");
+ EXPECT_EQUAL(0, drop.join());
}
-TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); }
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/exception_classes/silenceuncaught_test.cpp b/vespalib/src/tests/exception_classes/silenceuncaught_test.cpp
index 6c757b00af6..a15e9327d16 100644
--- a/vespalib/src/tests/exception_classes/silenceuncaught_test.cpp
+++ b/vespalib/src/tests/exception_classes/silenceuncaught_test.cpp
@@ -1,7 +1,7 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/vespalib/util/exception.h>
-#include <vespa/vespalib/util/child_process.h>
+#include <vespa/vespalib/process/process.h>
using namespace vespalib;
@@ -14,27 +14,23 @@ using namespace vespalib;
#endif
TEST("that uncaught exception causes negative exitcode.") {
- ChildProcess proc("ulimit -c 0 && exec ./vespalib_caught_uncaught_app uncaught");
- proc.wait();
- EXPECT_LESS(proc.getExitCode(), 0);
+ Process proc("ulimit -c 0 && exec ./vespalib_caught_uncaught_app uncaught");
+ EXPECT_LESS(proc.join(), 0);
}
TEST("that uncaught silenced exception causes exitcode 66") {
- ChildProcess proc("exec ./vespalib_caught_uncaught_app silenced_and_uncaught");
- proc.wait();
- EXPECT_EQUAL(proc.getExitCode(), 66);
+ Process proc("exec ./vespalib_caught_uncaught_app silenced_and_uncaught");
+ EXPECT_EQUAL(proc.join(), 66);
}
TEST("that caught silenced exception followed by an uncaught causes negative exitcode.") {
- ChildProcess proc("ulimit -c 0 && exec ./vespalib_caught_uncaught_app uncaught_after_silenced_and_caught");
- proc.wait();
- EXPECT_LESS(proc.getExitCode(), 0);
+ Process proc("ulimit -c 0 && exec ./vespalib_caught_uncaught_app uncaught_after_silenced_and_caught");
+ EXPECT_LESS(proc.join(), 0);
}
TEST("that caught silenced exception causes exitcode 0") {
- ChildProcess proc("exec ./vespalib_caught_uncaught_app silenced_and_caught");
- proc.wait();
- EXPECT_EQUAL(proc.getExitCode(), 0);
+ Process proc("exec ./vespalib_caught_uncaught_app silenced_and_caught");
+ EXPECT_EQUAL(proc.join(), 0);
}
#ifndef __SANITIZE_ADDRESS__
@@ -42,23 +38,20 @@ TEST("that caught silenced exception causes exitcode 0") {
// setrlimit with RLIMIT_AS is broken on Darwin
#else
TEST("that mmap within limits are fine cause exitcode 0") {
- ChildProcess proc("exec ./vespalib_mmap_app 150000000 10485760 1");
- proc.wait();
- EXPECT_EQUAL(proc.getExitCode(), 0);
+ Process proc("exec ./vespalib_mmap_app 150000000 10485760 1");
+ EXPECT_EQUAL(proc.join(), 0);
}
TEST("that mmap beyond limits cause negative exitcode.") {
- ChildProcess proc("ulimit -c 0 && exec ./vespalib_mmap_app 100000000 10485760 10");
- proc.wait();
- EXPECT_LESS(proc.getExitCode(), 0);
+ Process proc("ulimit -c 0 && exec ./vespalib_mmap_app 100000000 10485760 10");
+ EXPECT_LESS(proc.join(), 0);
}
TEST("that mmap beyond limits with set VESPA_SILENCE_CORE_ON_OOM cause exitcode 66.") {
- ChildProcess proc("VESPA_SILENCE_CORE_ON_OOM=1 exec ./vespalib_mmap_app 100000000 10485760 10");
- proc.wait();
- EXPECT_EQUAL(proc.getExitCode(), 66);
+ Process proc("VESPA_SILENCE_CORE_ON_OOM=1 exec ./vespalib_mmap_app 100000000 10485760 10");
+ EXPECT_EQUAL(proc.join(), 66);
}
#endif
#endif
-TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); }
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/host_name/host_name_test.cpp b/vespalib/src/tests/host_name/host_name_test.cpp
index ca5aebe8c95..b68762cebb3 100644
--- a/vespalib/src/tests/host_name/host_name_test.cpp
+++ b/vespalib/src/tests/host_name/host_name_test.cpp
@@ -1,7 +1,6 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/vespalib/util/host_name.h>
-#include <vespa/vespalib/util/child_process.h>
using namespace vespalib;
@@ -9,4 +8,4 @@ TEST("require that host name can be obtained") {
EXPECT_NOT_EQUAL("", HostName::get());
}
-TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); }
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/make_fixture_macros/make_fixture_macros_test.cpp b/vespalib/src/tests/make_fixture_macros/make_fixture_macros_test.cpp
index 0264a5aad0e..1cddddf7edc 100644
--- a/vespalib/src/tests/make_fixture_macros/make_fixture_macros_test.cpp
+++ b/vespalib/src/tests/make_fixture_macros/make_fixture_macros_test.cpp
@@ -1,12 +1,12 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/vespalib/util/child_process.h>
+#include <vespa/vespalib/process/process.h>
using namespace vespalib;
-bool runPrint(const char *cmd) {
- std::string out;
- bool res = ChildProcess::run(cmd, out);
+bool runPrint(const vespalib::string &cmd) {
+ vespalib::string out;
+ bool res = Process::run(cmd, out);
fprintf(stderr, "%s", out.c_str());
return res;
}
@@ -15,9 +15,9 @@ TEST("make fixture macros") {
EXPECT_FALSE(runPrint("../../apps/make_fixture_macros/vespalib_make_fixture_macros_app"));
EXPECT_TRUE(runPrint("../../apps/make_fixture_macros/vespalib_make_fixture_macros_app 9 > macros.tmp"));
- std::string diffCmd("diff -u ");
+ vespalib::string diffCmd("diff -u ");
diffCmd += TEST_PATH("../../vespa/vespalib/testkit/generated_fixture_macros.h macros.tmp");
EXPECT_TRUE(runPrint(diffCmd.c_str()));
}
-TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); }
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/process/process_test.cpp b/vespalib/src/tests/process/process_test.cpp
index 5f22e74ae4d..ec91bad4369 100644
--- a/vespalib/src/tests/process/process_test.cpp
+++ b/vespalib/src/tests/process/process_test.cpp
@@ -66,6 +66,46 @@ TEST(ProcessTest, proc_kill) {
//-----------------------------------------------------------------------------
+vespalib::string line1 = "this is a line";
+vespalib::string line2 = "this is also a line";
+vespalib::string line3 = "this is last line";
+
+TEST(ProcessTest, read_line) {
+ Process proc("cat");
+ for (const vespalib::string &line: {std::cref(line1), std::cref(line2), std::cref(line3)}) {
+ auto mem = proc.reserve(line.size() + 1);
+ memcpy(mem.data, line.data(), line.size());
+ mem.data[line.size()] = '\n';
+ proc.commit(line.size() + 1);
+ fprintf(stderr, "write: %s\n", line.c_str());
+ auto res = proc.read_line();
+ fprintf(stderr, "read: %s\n", line.c_str());
+ EXPECT_EQ(res, line);
+ EXPECT_FALSE(proc.eof());
+ }
+ proc.close();
+ EXPECT_EQ(proc.read_line(), "");
+ EXPECT_TRUE(proc.eof());
+ EXPECT_EQ(proc.join(), 0);
+}
+
+TEST(ProcessTest, read_line_without_newline) {
+ Process proc("cat");
+ const auto &line = line3;
+ auto mem = proc.reserve(line.size());
+ memcpy(mem.data, line.data(), line.size());
+ proc.commit(line.size());
+ fprintf(stderr, "write: %s\n", line.c_str());
+ proc.close(); // need eof to flush line
+ auto res = proc.read_line();
+ fprintf(stderr, "read: %s\n", line.c_str());
+ EXPECT_EQ(res, line);
+ EXPECT_TRUE(proc.eof());
+ EXPECT_EQ(proc.join(), 0);
+}
+
+//-----------------------------------------------------------------------------
+
void write_slime(const Slime &slime, Output &out) {
JsonFormat::encode(slime, out, true);
out.reserve(1).data[0] = '\n';
diff --git a/vespalib/src/tests/tutorial/make_tutorial.cpp b/vespalib/src/tests/tutorial/make_tutorial.cpp
index 46292a81005..58e3f529405 100644
--- a/vespalib/src/tests/tutorial/make_tutorial.cpp
+++ b/vespalib/src/tests/tutorial/make_tutorial.cpp
@@ -1,6 +1,6 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/vespalib/util/child_process.h>
+#include <vespa/vespalib/process/process.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <sys/mman.h>
#include <sys/stat.h>
@@ -10,48 +10,48 @@
using namespace vespalib;
-std::string readFile(const std::string &filename) {
+vespalib::string readFile(const vespalib::string &filename) {
TEST_STATE(filename.c_str());
MappedFileInput file(filename);
ASSERT_TRUE(file.valid());
Memory data = file.get();
- return std::string(data.data, data.size);
+ return vespalib::string(data.data, data.size);
}
-std::string runCommand(const std::string &cmd) {
- std::string out;
- ASSERT_TRUE(ChildProcess::run(cmd.c_str(), out));
+vespalib::string runCommand(const vespalib::string &cmd) {
+ vespalib::string out;
+ ASSERT_TRUE(Process::run(cmd, out));
return out;
}
-void insertExample(const std::string &name, const std::string &src_dir) {
- std::string str = runCommand(make_string("%s/make_example.sh %s", src_dir.c_str(),
+void insertExample(const vespalib::string &name, const vespalib::string &src_dir) {
+ vespalib::string str = runCommand(make_string("%s/make_example.sh %s", src_dir.c_str(),
name.c_str()));
fprintf(stdout, "%s", str.c_str());
}
-void insertSource(const std::string &name, const std::string &src_dir) {
- std::string str = runCommand(make_string("%s/make_source.sh %s", src_dir.c_str(),
+void insertSource(const vespalib::string &name, const vespalib::string &src_dir) {
+ vespalib::string str = runCommand(make_string("%s/make_source.sh %s", src_dir.c_str(),
name.c_str()));
fprintf(stdout, "%s", str.c_str());
}
-void insertFile(const std::string &name, const std::string &src_dir) {
- std::string str = readFile(src_dir + "/" + name);
+void insertFile(const vespalib::string &name, const vespalib::string &src_dir) {
+ vespalib::string str = readFile(src_dir + "/" + name);
fprintf(stdout, "%s", str.c_str());
}
-TEST_MAIN_WITH_PROCESS_PROXY() {
- std::string pre("[insert:");
- std::string example("example:");
- std::string source("source:");
- std::string file("file:");
- std::string post("]\n");
+TEST_MAIN() {
+ vespalib::string pre("[insert:");
+ vespalib::string example("example:");
+ vespalib::string source("source:");
+ vespalib::string file("file:");
+ vespalib::string post("]\n");
size_t pos = 0;
size_t end = 0;
size_t cursor = 0;
- std::string input = readFile(TEST_PATH("tutorial_source.html"));
+ vespalib::string input = readFile(TEST_PATH("tutorial_source.html"));
while ((pos = input.find(pre, cursor)) < input.size() &&
(end = input.find(post, pos)) < input.size())
{
@@ -59,15 +59,15 @@ TEST_MAIN_WITH_PROCESS_PROXY() {
pos += pre.size();
if (input.find(example, pos) == pos) {
pos += example.size();
- insertExample(std::string((input.data() + pos), (end - pos)), TEST_PATH(""));
+ insertExample(vespalib::string((input.data() + pos), (end - pos)), TEST_PATH(""));
} else if (input.find(source, pos) == pos) {
pos += source.size();
- insertSource(std::string((input.data() + pos), (end - pos)), TEST_PATH(""));
+ insertSource(vespalib::string((input.data() + pos), (end - pos)), TEST_PATH(""));
} else if (input.find(file, pos) == pos) {
pos += file.size();
- insertFile(std::string((input.data() + pos), (end - pos)), TEST_PATH(""));
+ insertFile(vespalib::string((input.data() + pos), (end - pos)), TEST_PATH(""));
} else {
- std::string str((input.data() + pos), (end - pos));
+ vespalib::string str((input.data() + pos), (end - pos));
TEST_FATAL(make_string("invalid directive >%s<", str.c_str()).c_str());
}
cursor = end + post.size();
diff --git a/vespalib/src/vespa/vespalib/process/process.cpp b/vespalib/src/vespa/vespalib/process/process.cpp
index 3b202a830f5..7749ffdff65 100644
--- a/vespalib/src/vespa/vespalib/process/process.cpp
+++ b/vespalib/src/vespa/vespalib/process/process.cpp
@@ -104,6 +104,23 @@ Process::commit(size_t bytes)
return *this;
}
+vespalib::string
+Process::read_line() {
+ vespalib::string line;
+ for (auto mem = obtain(); (mem.size > 0); mem = obtain()) {
+ for (size_t i = 0; i < mem.size; ++i) {
+ if (mem.data[i] == '\n') {
+ evict(i + 1);
+ return line;
+ } else {
+ line.push_back(mem.data[i]);
+ }
+ }
+ evict(mem.size);
+ }
+ return line;
+}
+
int
Process::join()
{
diff --git a/vespalib/src/vespa/vespalib/process/process.h b/vespalib/src/vespa/vespalib/process/process.h
index 97771752faa..d15784f5d31 100644
--- a/vespalib/src/vespa/vespalib/process/process.h
+++ b/vespalib/src/vespa/vespalib/process/process.h
@@ -43,6 +43,8 @@ public:
Input &evict(size_t bytes) override; // Input (stdout)
WritableMemory reserve(size_t bytes) override; // Output (stdin)
Output &commit(size_t bytes) override; // Output (stdin)
+ vespalib::string read_line();
+ bool eof() const { return _eof; }
int join();
~Process();
diff --git a/vespalib/src/vespa/vespalib/testkit/test_macros.h b/vespalib/src/vespa/vespalib/testkit/test_macros.h
index 5ee8e170ef0..ebf3e06d283 100644
--- a/vespalib/src/vespa/vespalib/testkit/test_macros.h
+++ b/vespalib/src/vespa/vespalib/testkit/test_macros.h
@@ -18,28 +18,24 @@
#define TEST_TRACE() TEST_MASTER.trace(__FILE__, __LINE__)
#define TEST_THREAD(name) TEST_MASTER.setThreadName(name)
#define TEST_BARRIER() TEST_MASTER.awaitThreadBarrier(__FILE__, __LINE__)
-#define TEST_MAIN_IMPL(useProxy) \
- void test_kit_main(); \
- struct TestKitApp : FastOS_Application \
- { \
- bool useProcessStarter() const override { return useProxy; } \
- int Main() override; \
- }; \
- int main(int argc, char **argv) \
- { \
- TestKitApp app; \
- return app.Entry(argc, argv); \
- } \
- int TestKitApp::Main() { \
- TEST_MASTER.init(__FILE__); \
- test_kit_main(); \
- return (TEST_MASTER.fini() ? 0 : 1); \
- } \
+#define TEST_MAIN() \
+ void test_kit_main(); \
+ struct TestKitApp : FastOS_Application \
+ { \
+ int Main() override; \
+ }; \
+ int main(int argc, char **argv) \
+ { \
+ TestKitApp app; \
+ return app.Entry(argc, argv); \
+ } \
+ int TestKitApp::Main() { \
+ TEST_MASTER.init(__FILE__); \
+ test_kit_main(); \
+ return (TEST_MASTER.fini() ? 0 : 1); \
+ } \
void test_kit_main()
-#define TEST_MAIN() TEST_MAIN_IMPL(false)
-#define TEST_MAIN_WITH_PROCESS_PROXY() TEST_MAIN_IMPL(true)
-
//-----------------------------------------------------------------------------
#include "generated_fixture_macros.h"
//-----------------------------------------------------------------------------
diff --git a/vespalib/src/vespa/vespalib/testkit/testapp.h b/vespalib/src/vespa/vespalib/testkit/testapp.h
index facb0857e8c..8ffb9958555 100644
--- a/vespalib/src/vespa/vespalib/testkit/testapp.h
+++ b/vespalib/src/vespa/vespalib/testkit/testapp.h
@@ -22,14 +22,6 @@
public: int Main() override; \
}; \
TEST_APPHOOK(test)
-#define TEST_SETUP_WITHPROCESSPROXY(test) \
- class test : public vespalib::TestApp \
- { \
- public: \
- int Main(); \
- virtual bool useProcessStarter() const { return true; } \
- }; \
- TEST_APPHOOK(test)
namespace vespalib {
diff --git a/vespalib/src/vespa/vespalib/util/CMakeLists.txt b/vespalib/src/vespa/vespalib/util/CMakeLists.txt
index 747ed736aad..f7bdd4427e3 100644
--- a/vespalib/src/vespa/vespalib/util/CMakeLists.txt
+++ b/vespalib/src/vespa/vespalib/util/CMakeLists.txt
@@ -14,7 +14,6 @@ vespa_add_library(vespalib_vespalib_util OBJECT
binary_hamming_distance.cpp
blockingthreadstackexecutor.cpp
box.cpp
- child_process.cpp
classname.cpp
compress.cpp
compressor.cpp
diff --git a/vespalib/src/vespa/vespalib/util/child_process.cpp b/vespalib/src/vespa/vespalib/util/child_process.cpp
deleted file mode 100644
index 93db56cdf67..00000000000
--- a/vespalib/src/vespa/vespalib/util/child_process.cpp
+++ /dev/null
@@ -1,346 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "guard.h"
-#include "child_process.h"
-#include <cstring>
-#include <vespa/vespalib/util/size_literals.h>
-
-namespace vespalib {
-
-namespace child_process {
-
-using namespace std::chrono;
-
-/**
- * @brief ChildProcess internal timeout management.
- **/
-class Timer
-{
-private:
- const steady_clock::time_point _startTime;
- const int64_t _maxTimeMS;
- milliseconds _elapsed;
-
-public:
- Timer(int64_t maxTimeMS)
- : _startTime(steady_clock::now()),
- _maxTimeMS(maxTimeMS),
- _elapsed(0)
- { }
- Timer &update() {
- _elapsed = duration_cast<milliseconds>(steady_clock::now() - _startTime);
- return *this;
- }
- int64_t elapsed() const {
- return _elapsed.count();
- }
- int64_t remaining() const {
- if (_maxTimeMS == -1) {
- return -1;
- }
- if (elapsed() > _maxTimeMS) {
- return 0;
- }
- return (_maxTimeMS - _elapsed.count());
- }
- int64_t waitTime() const {
- int res = remaining();
- if (res >= 0 && res <= 10000) {
- return res;
- }
- return 10000;
- }
- bool timeOut() const {
- return (remaining() == 0);
- }
-};
-
-} // namespace child_process
-
-
-void
-ChildProcess::Reader::OnReceiveData(const void *data, size_t length)
-{
- const char *buf = (const char *) data;
- std::unique_lock lock(_lock);
- if (_gotEOF || (buf != nullptr && length == 0)) { // ignore special cases
- return;
- }
- if (buf == nullptr) { // EOF
- if (--_num_streams == 0) {
- _gotEOF = true;
- }
- } else {
- _queue.push(std::string(buf, length));
- }
- if (_waitCnt > 0) {
- _cond.notify_one();
- }
-}
-
-
-bool
-ChildProcess::Reader::hasData()
-{
- // NB: caller has lock on _cond
- return (!_data.empty() || !_queue.empty());
-}
-
-
-bool
-ChildProcess::Reader::waitForData(child_process::Timer &timer, std::unique_lock<std::mutex> &guard)
-{
- // NB: caller has lock on _cond
- CounterGuard count(_waitCnt);
- while (!timer.update().timeOut() && !hasData() && !_gotEOF) {
- _cond.wait_for(guard, std::chrono::milliseconds(timer.waitTime()));
- }
- return hasData();
-}
-
-
-void
-ChildProcess::Reader::updateEOF()
-{
- // NB: caller has lock on _cond
- if (_data.empty() && _queue.empty() && _gotEOF) {
- _readEOF = true;
- }
-}
-
-
-ChildProcess::Reader::Reader(int num_streams)
- : _lock(),
- _cond(),
- _queue(),
- _data(),
- _num_streams(num_streams),
- _gotEOF(false),
- _waitCnt(0),
- _readEOF(false)
-{
-}
-
-
-ChildProcess::Reader::~Reader() = default;
-
-
-uint32_t
-ChildProcess::Reader::read(char *buf, uint32_t len, int msTimeout)
-{
- if (eof()) {
- return 0;
- }
- child_process::Timer timer(msTimeout);
- std::unique_lock guard(_lock);
- waitForData(timer, guard);
- uint32_t bytes = 0;
- while (bytes < len && hasData()) {
- if (_data.empty()) {
- _data = _queue.front();
- _queue.pop();
- }
- if (len - bytes < _data.length()) {
- memcpy(buf + bytes, _data.data(), len - bytes);
- _data.erase(0, len - bytes);
- bytes = len;
- } else {
- memcpy(buf + bytes, _data.data(), _data.length());
- bytes += _data.length();
- _data.clear();
- }
- }
- updateEOF();
- return bytes;
-}
-
-
-bool
-ChildProcess::Reader::readLine(std::string &line, int msTimeout)
-{
- line.clear();
- if (eof()) {
- return false;
- }
- child_process::Timer timer(msTimeout);
- std::unique_lock guard(_lock);
- while (waitForData(timer, guard)) {
- while (hasData()) {
- if (_data.empty()) {
- _data = _queue.front();
- _queue.pop();
- }
- std::string::size_type ofs = _data.find('\n');
- if (ofs == std::string::npos) {
- line.append(_data);
- _data.clear();
- } else {
- line.append(_data, 0, ofs);
- _data.erase(0, ofs + 1);
- updateEOF();
- return true;
- }
- }
- }
- updateEOF();
- if (eof()) {
- return !line.empty();
- }
- _data.swap(line);
- return false;
-}
-
-//-----------------------------------------------------------------------------
-
-void
-ChildProcess::checkProc()
-{
- if (_running) {
- bool stillRunning;
- if (_proc.PollWait(&_exitCode, &stillRunning) && !stillRunning) {
- _running = false;
- _failed = (_exitCode != 0);
- }
- }
-}
-
-
-ChildProcess::ChildProcess(const char *cmd)
- : _reader(1),
- _proc(cmd, &_reader),
- _running(false),
- _failed(false),
- _exitCode(-918273645)
-{
- _running = _proc.CreateWithShell();
- _failed = !_running;
-}
-
-ChildProcess::ChildProcess(const char *cmd, capture_stderr_tag)
- : _reader(2),
- _proc(cmd, &_reader, &_reader),
- _running(false),
- _failed(false),
- _exitCode(-918273645)
-{
- _running = _proc.CreateWithShell();
- _failed = !_running;
-}
-
-
-ChildProcess::~ChildProcess() = default;
-
-
-bool
-ChildProcess::write(const char *buf, uint32_t len)
-{
- if (len == 0) {
- return true;
- }
- return _proc.WriteStdin(buf, len);
-}
-
-
-bool
-ChildProcess::close()
-{
- return _proc.WriteStdin(nullptr, 0);
-}
-
-
-uint32_t
-ChildProcess::read(char *buf, uint32_t len, int msTimeout)
-{
- return _reader.read(buf, len, msTimeout);
-}
-
-
-bool
-ChildProcess::readLine(std::string &line, int msTimeout)
-{
- return _reader.readLine(line, msTimeout);
-}
-
-
-bool
-ChildProcess::wait(int msTimeout)
-{
- bool done = true;
- checkProc();
- if (_running) {
- if (msTimeout != -1) {
- msTimeout = (msTimeout + 999) / 1000;
- }
- if (_proc.Wait(&_exitCode, msTimeout)) {
- _failed = (_exitCode != 0);
- } else {
- _failed = true;
- done = false;
- }
- _running = false;
- }
- return done;
-}
-
-
-bool
-ChildProcess::running()
-{
- checkProc();
- return _running;
-}
-
-
-bool
-ChildProcess::failed()
-{
- checkProc();
- return _failed;
-}
-
-int
-ChildProcess::getExitCode()
-{
- return _exitCode;
-}
-
-
-bool
-ChildProcess::run(const std::string &input, const char *cmd,
- std::string &output, int msTimeout)
-{
- ChildProcess proc(cmd);
- child_process::Timer timer(msTimeout);
- char buf[4_Ki];
- proc.write(input.data(), input.length());
- proc.close(); // close stdin
- while (!proc.eof() && !timer.timeOut()) {
- uint32_t res = proc.read(buf, sizeof(buf), timer.remaining());
- output.append(buf, res);
- timer.update();
- }
- if ( ! output.empty() && output.find('\n') == output.size() - 1) {
- output.erase(output.size() - 1, 1);
- }
- proc.wait(timer.update().remaining());
- return (!proc.running() && !proc.failed());
-}
-
-
-bool
-ChildProcess::run(const char *cmd, std::string &output, int msTimeout)
-{
- std::string input; // empty input
- return run(input, cmd, output, msTimeout);
-}
-
-
-bool
-ChildProcess::run(const char *cmd, int msTimeout)
-{
- std::string input; // empty input
- std::string output; // ignore output
- return run(input, cmd, output, msTimeout);
-}
-
-} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/util/child_process.h b/vespalib/src/vespa/vespalib/util/child_process.h
deleted file mode 100644
index 877c56a8cb1..00000000000
--- a/vespalib/src/vespa/vespalib/util/child_process.h
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/fastos/process.h>
-#ifndef FASTOS_NO_THREADS
-#include <string>
-#include <queue>
-#include <condition_variable>
-
-namespace vespalib::child_process { class Timer; }
-
-namespace vespalib {
-/**
- * @brief Child Process utility class for running external programs
- *
- * Designed for use in unit tests and other places
- * where you need to run, control and communicate with
- * some external program.
- **/
-class ChildProcess
-{
-private:
- class Reader : public FastOS_ProcessRedirectListener
- {
- private:
- std::mutex _lock;
- std::condition_variable _cond;
- std::queue<std::string> _queue;
- std::string _data;
- int _num_streams;
- bool _gotEOF;
- int _waitCnt;
- bool _readEOF;
-
- void OnReceiveData(const void *data, size_t length) override;
- bool hasData();
- bool waitForData(child_process::Timer &timer, std::unique_lock<std::mutex> &lock);
- void updateEOF();
-
- public:
- Reader(int num_streams);
- ~Reader() override;
-
- uint32_t read(char *buf, uint32_t len, int msTimeout);
- bool readLine(std::string &line, int msTimeout);
- bool eof() const { return _readEOF; };
- };
-
- Reader _reader;
- FastOS_Process _proc;
- bool _running;
- bool _failed;
- int _exitCode;
-
- void checkProc();
-
-public:
- ChildProcess(const ChildProcess &) = delete;
- ChildProcess &operator=(const ChildProcess &) = delete;
- struct capture_stderr_tag{};
-
- /**
- * @brief Run a child process
- *
- * Starts a process running the given command
- * @param cmd A shell command line to run
- **/
- explicit ChildProcess(const char *cmd);
-
- /**
- * @brief Run a child process
- *
- * Starts a process running the given command. stderr is
- * redirected into stdout.
- * @param cmd A shell command line to run
- **/
- explicit ChildProcess(const char *cmd, capture_stderr_tag);
-
- /** @brief destructor doing cleanup if needed */
- ~ChildProcess();
-
- /**
- * @return process id
- **/
- pid_t getPid() { return _proc.GetProcessId(); }
-
- /**
- * @brief send data as input to the running process
- *
- * The given data will be sent so it becomes
- * available on the running process's standard input.
- *
- * @param buf the data containing len bytes to be sent
- * @param len the number of bytes to send
- * @return true if successful
- **/
- bool write(const char *buf, uint32_t len);
-
- /**
- * @brief close the running process's standard input
- *
- * when running a program that consumes stdin,
- * make sure to call this method to signal
- * that it can finish.
- * @return true if successful
- **/
- bool close();
-
- /**
- * @brief read program output
- *
- * If the running program writes data to its standard output, you
- * can and should get the data with read() or readLine() calls.
- *
- * @param buf pointer where data is stored
- * @param len number of bytes to try to read
- * @param msTimeout number of milliseconds to wait for data
- **/
- uint32_t read(char *buf, uint32_t len, int msTimeout = 10000);
-
- /**
- * @brief read a line of program output
- *
- * See read().
- * @param line reference to a string where a line of program output will be stored
- * @param msTimeout number of milliseconds to wait for data
- * @return true if successful
- **/
- bool readLine(std::string &line, int msTimeout = 10000);
-
- /**
- * @brief check if the program has finished writing output
- * @return true if standard output from the process is closed
- **/
- bool eof() const { return _reader.eof(); }
-
- /**
- * @brief wait for the program to exit
- * @param msTimeout milliseconds to wait; the default (-1) will wait forever
- * @return true if the program exited, false on timeout
- **/
- bool wait(int msTimeout = -1);
-
- /** @brief check if the program is still running */
- bool running();
-
- /**
- * @brief get the exit code of the started program.
- *
- * Will return the stored exitcode.
- * It assumes that the command is done.
- * @return exit code.
- **/
- int getExitCode();
-
- /**
- * @brief check if program failed
- *
- * Check if we failed to run the program or the program finished with
- * a non-zero exit status.
- * @return true if something went wrong
- **/
- bool failed();
-
- /**
- * @brief run a command
- *
- * Utility function that runs the given command, sends input, and
- * loops reading output until the program finishes or the timeout
- * expires.
- * Any final terminating newline will be erased from output,
- * just like for shell backticks.
- *
- * @param input The input the program will receive
- * @param cmd The command to run
- * @param output Any output will be appended to this string
- * @param msTimeout milliseconds timeout; -1 means wait forever for program to finish
- **/
- static bool run(const std::string &input, const char *cmd,
- std::string &output, int msTimeout = -1);
- /**
- * @brief run a command
- *
- * Utility function that runs the given command with no input, and
- * loops reading output until the program finishes or the timeout
- * expires.
- * Any final terminating newline will be erased from output,
- * just like for shell backticks.
- *
- * @param cmd The command to run
- * @param output Any output will be appended to this string
- * @param msTimeout milliseconds timeout; -1 means wait forever for program to finish
- **/
- static bool run(const char *cmd, std::string &output, int msTimeout = -1);
-
- /**
- * @brief run a command
- *
- * Utility function that runs the given command with no input, and
- * loops reading output until the program finishes or the timeout
- * expires. Output (if any) is ignored.
- *
- * @param cmd The command to run
- * @param msTimeout milliseconds timeout; -1 means wait forever for program to finish
- **/
- static bool run(const char *cmd, int msTimeout = -1);
-};
-
-} // namespace vespalib
-
-#endif // FASTOS_NO_THREADS
diff --git a/vespamalloc/src/tests/doubledelete/expectsignal.cpp b/vespamalloc/src/tests/doubledelete/expectsignal.cpp
index e9b71649268..df6398dcd20 100644
--- a/vespamalloc/src/tests/doubledelete/expectsignal.cpp
+++ b/vespamalloc/src/tests/doubledelete/expectsignal.cpp
@@ -1,6 +1,6 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/testapp.h>
-#include <vespa/vespalib/util/child_process.h>
+#include <vespa/vespalib/process/process.h>
#include <sys/wait.h>
using namespace vespalib;
@@ -9,9 +9,6 @@ class Test : public TestApp
{
public:
int Main() override;
-private:
- bool useProcessStarter() const override { return true; }
-
};
int Test::Main()
@@ -25,14 +22,11 @@ int Test::Main()
fprintf(stderr, "argc=%d : Running '%s' expecting signal %d\n", _argc, _argv[2], retval);
- ChildProcess cmd(_argv[2]);
- for(std::string line; cmd.readLine(line, 60000);) {
+ Process cmd(_argv[2]);
+ for (vespalib::string line = cmd.read_line(); !line.empty(); line = cmd.read_line()) {
fprintf(stdout, "%s\n", line.c_str());
}
-
- ASSERT_TRUE(cmd.wait(60000));
-
- int exitCode = cmd.getExitCode();
+ int exitCode = cmd.join();
if (exitCode == 65535) {
fprintf(stderr, "[ERROR] child killed (timeout)\n");
diff --git a/vespamalloc/src/tests/overwrite/expectsignal.cpp b/vespamalloc/src/tests/overwrite/expectsignal.cpp
index 904cedd479f..df6398dcd20 100644
--- a/vespamalloc/src/tests/overwrite/expectsignal.cpp
+++ b/vespamalloc/src/tests/overwrite/expectsignal.cpp
@@ -1,6 +1,6 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/testapp.h>
-#include <vespa/vespalib/util/child_process.h>
+#include <vespa/vespalib/process/process.h>
#include <sys/wait.h>
using namespace vespalib;
@@ -9,8 +9,6 @@ class Test : public TestApp
{
public:
int Main() override;
-private:
- virtual bool useProcessStarter() const override { return true; }
};
int Test::Main()
@@ -24,14 +22,11 @@ int Test::Main()
fprintf(stderr, "argc=%d : Running '%s' expecting signal %d\n", _argc, _argv[2], retval);
- ChildProcess cmd(_argv[2]);
- for(std::string line; cmd.readLine(line, 60000);) {
+ Process cmd(_argv[2]);
+ for (vespalib::string line = cmd.read_line(); !line.empty(); line = cmd.read_line()) {
fprintf(stdout, "%s\n", line.c_str());
}
-
- ASSERT_TRUE(cmd.wait(60000));
-
- int exitCode = cmd.getExitCode();
+ int exitCode = cmd.join();
if (exitCode == 65535) {
fprintf(stderr, "[ERROR] child killed (timeout)\n");
diff --git a/vespamalloc/src/tests/thread/thread.cpp b/vespamalloc/src/tests/thread/thread.cpp
index b101b862268..d6f1ad5c9c0 100644
--- a/vespamalloc/src/tests/thread/thread.cpp
+++ b/vespamalloc/src/tests/thread/thread.cpp
@@ -11,8 +11,6 @@ class Test : public TestApp
public:
~Test();
int Main() override;
-private:
- bool useIPCHelper() const override { return true; }
};
Test::~Test()