summaryrefslogtreecommitdiff
path: root/source/core/unix/slang-unix-process-util.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2021-11-10 17:33:22 -0500
committerGitHub <noreply@github.com>2021-11-10 17:33:22 -0500
commit8a9e518371df03b3f382e0fe869da83751fdda0b (patch)
tree749f9c1c79acd375ec3ee97e45a10007dd6632fa /source/core/unix/slang-unix-process-util.cpp
parent95e82acc0b32c81a9c6ac39708d18a423d8c7b1e (diff)
Interprocess communication via pipes (#2009)
* #include an absolute path didn't work - because paths were taken to always be relative. * Use 'Process' to communicate with an command line tool. * Remove slang-win-stream * Tidy up windows ProcessUtil. * First version of BufferedReadStream. * Windows working IPC for steams. * Test proxy count option. * Split Process/ProcessUtil. Process is platform dependant. ProcessUtil are functions that are platform independent. * First implementation of Unix Process interface. * Unix process compiles on cygwin. * Fix typo in unix process. * Separate unix pipe stream error of invalid access, from pipe availability. * Fix in standard line extraction. * Make fd non blocking. * Fix issues with Windows Process streams. * Added UnixPipe. * Some fixes around UnixPipeStream. * Make a unix stream closed explicit. * Hack to debug linux process/stream. * Revert to old linux pipe handling. * Pass executable path for unit tests. Split out CommandLine into own source. * Small improvements in process/command line. * Check process behavior with crash. * Make stderr and stdout unbuffered for crash testing. * Only turn disable buffering in crash test. * Disable crash test on CI. * Fix crash on clang/linux. * Enable crash test. Remove _appendBuffer as can use StreamUtil functionality.
Diffstat (limited to 'source/core/unix/slang-unix-process-util.cpp')
-rw-r--r--source/core/unix/slang-unix-process-util.cpp246
1 files changed, 0 insertions, 246 deletions
diff --git a/source/core/unix/slang-unix-process-util.cpp b/source/core/unix/slang-unix-process-util.cpp
deleted file mode 100644
index af49eec37..000000000
--- a/source/core/unix/slang-unix-process-util.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-// slang-unix-process-util.cpp
-#include "../slang-process-util.h"
-
-#include "../slang-common.h"
-#include "../slang-string-util.h"
-#include "../slang-string-escape-util.h"
-#include "../slang-memory-arena.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-//#include <dirent.h>
-#include <errno.h>
-#include <poll.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <time.h>
-
-namespace Slang {
-
-
-/* static */UnownedStringSlice ProcessUtil::getExecutableSuffix()
-{
-#if __CYGWIN__
- return UnownedStringSlice::fromLiteral(".exe");
-#else
- return UnownedStringSlice::fromLiteral("");
-#endif
-}
-
-/* static */StringEscapeHandler* ProcessUtil::getEscapeHandler()
-{
- return StringEscapeUtil::getHandler(StringEscapeUtil::Style::Space);
-}
-
-/* static */String ProcessUtil::getCommandLineString(const CommandLine& commandLine)
-{
- auto escapeHandler = getEscapeHandler();
-
- // When outputting the command line we potentially need to escape the path to the
- // command and args - that aren't already explicitly marked as escaped.
-
- StringBuilder cmd;
- StringEscapeUtil::appendMaybeQuoted(escapeHandler, commandLine.m_executable.getUnownedSlice(), cmd);
- for (const auto& arg : commandLine.m_args)
- {
- cmd << " ";
-
- StringEscapeUtil::appendMaybeQuoted(escapeHandler, arg.getUnownedSlice(), cmd);
- }
- return cmd.ToString();
-}
-
-/* static */SlangResult ProcessUtil::execute(const CommandLine& commandLine, ExecuteResult& outExecuteResult)
-{
- outExecuteResult.init();
-
- List<char const*> argPtrs;
-
- // Add the command
- argPtrs.add(commandLine.m_executable.getBuffer());
-
- // Add all the args - they don't need any explicit escaping
- for (auto arg : commandLine.m_args)
- {
- // All args for this target must be unescaped (as they are in CommandLine)
- argPtrs.add(arg.getBuffer());
- }
-
- // Terminate with a null
- argPtrs.add(nullptr);
-
- int stdoutPipe[2];
- int stderrPipe[2];
-
- if (pipe(stdoutPipe) == -1)
- {
- fprintf(stderr, "error: `pipe` failed\n");
- return SLANG_FAIL;
- }
-
- if (pipe(stderrPipe) == -1)
- {
- fprintf(stderr, "error: `pipe` failed\n");
- return SLANG_FAIL;
- }
-
- pid_t childProcessID = fork();
- if (childProcessID == -1)
- {
- fprintf(stderr, "error: `fork` failed\n");
- return SLANG_FAIL;
- }
-
- if (childProcessID == 0)
- {
- // We are the child process.
-
- dup2(stdoutPipe[1], STDOUT_FILENO);
- dup2(stderrPipe[1], STDERR_FILENO);
-
- close(stdoutPipe[0]);
- close(stdoutPipe[1]);
-
- close(stderrPipe[0]);
- close(stderrPipe[1]);
-
- execvp(argPtrs[0], (char* const*)&argPtrs[0]);
-
- // If we get here, then `exec` failed
- fprintf(stderr, "error: `exec` failed\n");
- return SLANG_FAIL;
- }
- else
- {
- // We are the parent process
-
- close(stdoutPipe[1]);
- close(stderrPipe[1]);
-
- int stdoutFD = stdoutPipe[0];
- int stderrFD = stderrPipe[0];
-
- pollfd pollInfos[2];
- nfds_t pollInfoCount = 2;
-
- pollInfos[0].fd = stdoutFD;
- pollInfos[0].events = POLLIN;
- pollInfos[0].revents = 0;
- pollInfos[1].fd = stderrFD;
- pollInfos[1].events = POLLIN;
- pollInfos[1].revents = 0;
-
- int remainingCount = 2;
- int iterations = 0;
- while (remainingCount)
- {
- // Safeguard against infinite loop:
- iterations++;
- if (iterations > 10000)
- {
- fprintf(stderr, "poll(): %d iterations\n", iterations);
- return SLANG_FAIL;
- }
-
- // Set a timeout of 100 seconds;
- // we really shouldn't wait too long...
- int pollTimeout = 100000;
- int pollResult = poll(pollInfos, pollInfoCount, pollTimeout);
- if (pollResult <= 0)
- {
- // If there was a signal that got in
- // the way, then retry...
- if (pollResult == -1 && errno == EINTR)
- continue;
-
- // timeout or error...
- fprintf(stderr, "error: `poll` failed or timed out\n");
- return SLANG_FAIL;
- }
-
- enum { kBufferSize = 1024 };
- char buffer[kBufferSize];
-
- if (pollInfos[0].revents)
- {
- auto count = read(stdoutFD, buffer, kBufferSize);
- if (count <= 0)
- {
- // end-of-file
- close(stdoutFD);
- pollInfos[0].fd = -1;
- remainingCount--;
- }
-
- outExecuteResult.standardOutput.append(buffer, buffer + count);
- }
-
- if (pollInfos[1].revents)
- {
- auto count = read(stderrFD, buffer, kBufferSize);
- if (count <= 0)
- {
- // end-of-file
- close(stderrFD);
- pollInfos[1].fd = -1;
- remainingCount--;
- }
-
- outExecuteResult.standardError.append(buffer, buffer + count);
- }
- }
-
- int childStatus = 0;
- iterations = 0;
- for (;;)
- {
- // Safeguard against infinite loop:
- iterations++;
- if (iterations > 10000)
- {
- fprintf(stderr, "waitpid(): %d iterations\n", iterations);
- return SLANG_FAIL;
- }
-
- pid_t terminatedProcessID = waitpid(childProcessID, &childStatus, 0);
- if (terminatedProcessID == -1)
- {
- fprintf(stderr, "error: `waitpid` failed\n");
- return SLANG_FAIL;
- }
-
- if (terminatedProcessID == childProcessID)
- {
- if (WIFEXITED(childStatus))
- {
- outExecuteResult.resultCode = (int)(int8_t)WEXITSTATUS(childStatus);
- }
- else
- {
- outExecuteResult.resultCode = 1;
- }
- return SLANG_OK;
- }
- }
- }
-
- return SLANG_FAIL;
-}
-
-/* static */uint64_t ProcessUtil::getClockFrequency()
-{
- return 1000000000;
-}
-
-/* static */uint64_t ProcessUtil::getClockTick()
-{
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
- return uint64_t(now.tv_sec) * 1000000000 + now.tv_nsec;
-}
-
-} // namespace Slang