diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2019-06-12 09:05:40 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-06-12 09:05:40 -0400 |
| commit | 9d514e65f00dde0e309f33591f31fbf7f132a005 (patch) | |
| tree | 7e3a751377651ef9eda06f0b1ad345af1796c596 /tools/slang-test/os.cpp | |
| parent | fc083a75b94ac4b4e735b4a7ff566191b9123f74 (diff) | |
Runtime execution of Visual Studio Compiler (#978)
* Work in progress to be able to invoke VS from within code.
* First pass at windows version of refactor of OSProcessSpawner
* Closer to getting VS path lookup working.
* Make OSString assignable/ctor able
* Work out program files directory directly, so don't have to expand %%.
* WIP: Improve handling of process spawning.
* Add support for splitting input by line.
* * Correctly locates visual studio install
* Added functionality to invoke vs via cmd
* Add option to execute the command line.
* Handle in ProcessUtil for windows -> WinHandle.
* Rename files slang-win-visual-studio-util.cpp/.h and slang-process-util.h
* First pass at unix/linux version of ProcessUtil.
* Fix reading Visual Studio path from the registry.
* Get compiling on linux with.
* Fix vcvarsall.bat name
* Use ProcessUtil to execute external code.
* Remove OSProcessSpawner.
* Remove includes for "os.h" where no longer needed.
* Fix tabbing issue in premake5.lua
Remove test code from slang-test-main.cpp
* Fix premake4.lua tabbing issue.
* Small fixes to slang-process-util.h
Init ExecuteResult on Win execute.
* Improve comments.
* Fix bug in StringUtil::calcLines - with oddly terminated source input being able to read past end.
Make slang-generate use StringUtil over it's own impl.
* Fix off by one bug in working out Visual Studio version.
* Fix bug in calculating Visual Studio Version
* Fix compilation on linux with string parameter being passed to messageFormat.
* Remove erroneous use of kOSError codes - use Result.
Diffstat (limited to 'tools/slang-test/os.cpp')
| -rw-r--r-- | tools/slang-test/os.cpp | 469 |
1 files changed, 0 insertions, 469 deletions
diff --git a/tools/slang-test/os.cpp b/tools/slang-test/os.cpp index a938a71e7..eceeef2d7 100644 --- a/tools/slang-test/os.cpp +++ b/tools/slang-test/os.cpp @@ -123,266 +123,6 @@ OSFindFilesResult osFindChildDirectories( return result; } -// OSProcessSpawner - -struct OSProcessSpawner_ReaderThreadInfo -{ - HANDLE file; - String output; -}; - -static DWORD WINAPI osReaderThreadProc(LPVOID threadParam) -{ - OSProcessSpawner_ReaderThreadInfo* info = (OSProcessSpawner_ReaderThreadInfo*)threadParam; - HANDLE file = info->file; - - static const int kChunkSize = 1024; - char buffer[kChunkSize]; - - StringBuilder outputBuilder; - - // We need to re-write the output to deal with line - // endings, so we check for paired '\r' and '\n' - // characters, which may span chunks. - int prevChar = -1; - - for (;;) - { - DWORD bytesRead = 0; - BOOL readResult = ReadFile(file, buffer, kChunkSize, &bytesRead, nullptr); - - if (!readResult || GetLastError() == ERROR_BROKEN_PIPE) - { - break; - } - - // walk the buffer and rewrite to eliminate '\r' '\n' pairs - char* readCursor = buffer; - char const* end = buffer + bytesRead; - char* writeCursor = buffer; - - while (readCursor != end) - { - int p = prevChar; - int c = *readCursor++; - prevChar = c; - switch (c) - { - case '\r': case '\n': - // swallow input if '\r' and '\n' appear in sequence - if ((p ^ c) == ('\r' ^ '\n')) - { - // but don't swallow the next byte - prevChar = -1; - continue; - } - // always replace '\r' with '\n' - c = '\n'; - break; - - default: - break; - } - - *writeCursor++ = (char)c; - } - bytesRead = (DWORD)(writeCursor - buffer); - - // Note: Current "core" implementation gives no way to know - // the length of the buffer, so we ultimately have - // to just assume null termination... - outputBuilder.Append(buffer, bytesRead); - } - - info->output = outputBuilder.ProduceString(); - - return 0; -} - -void OSProcessSpawner::pushExecutableName( - Slang::String executableName) -{ - executableName_ = executableName; - commandLine_.Append(executableName); - isExecutablePath_ = false; -} - -void OSProcessSpawner::pushExecutablePath( - Slang::String executablePath) -{ - executableName_ = executablePath; - commandLine_.Append(executablePath); - isExecutablePath_ = true; -} - -void OSProcessSpawner::pushArgument( - Slang::String argument) -{ - // TODO(tfoley): handle cases where arguments need some escaping - commandLine_.Append(" "); - commandLine_.Append(argument); - - argumentList_.add(argument); -} - -Slang::String OSProcessSpawner::getCommandLine() -{ - return commandLine_; -} - -OSError OSProcessSpawner::spawnAndWaitForCompletion() -{ - SECURITY_ATTRIBUTES securityAttributes; - securityAttributes.nLength = sizeof(securityAttributes); - securityAttributes.lpSecurityDescriptor = nullptr; - securityAttributes.bInheritHandle = true; - - // create stdout pipe for child process - HANDLE childStdOutReadTmp = nullptr; - HANDLE childStdOutWrite = nullptr; - if (!CreatePipe(&childStdOutReadTmp, &childStdOutWrite, &securityAttributes, 0)) - { - return kOSError_OperationFailed; - } - - // create stderr pipe for child process - HANDLE childStdErrReadTmp = nullptr; - HANDLE childStdErrWrite = nullptr; - if (!CreatePipe(&childStdErrReadTmp, &childStdErrWrite, &securityAttributes, 0)) - { - return kOSError_OperationFailed; - } - - // create stdin pipe for child process - HANDLE childStdInRead = nullptr; - HANDLE childStdInWriteTmp = nullptr; - if (!CreatePipe(&childStdInRead, &childStdInWriteTmp, &securityAttributes, 0)) - { - return kOSError_OperationFailed; - } - - HANDLE currentProcess = GetCurrentProcess(); - - // create a non-inheritable duplicate of the stdout reader - HANDLE childStdOutRead = nullptr; - if (!DuplicateHandle( - currentProcess, childStdOutReadTmp, - currentProcess, &childStdOutRead, - 0, FALSE, DUPLICATE_SAME_ACCESS)) - { - return kOSError_OperationFailed; - } - if (!CloseHandle(childStdOutReadTmp)) - { - return kOSError_OperationFailed; - } - - // create a non-inheritable duplicate of the stderr reader - HANDLE childStdErrRead = nullptr; - if (!DuplicateHandle( - currentProcess, childStdErrReadTmp, - currentProcess, &childStdErrRead, - 0, FALSE, DUPLICATE_SAME_ACCESS)) - { - return kOSError_OperationFailed; - } - if (!CloseHandle(childStdErrReadTmp)) - { - return kOSError_OperationFailed; - } - - // create a non-inheritable duplicate of the stdin writer - HANDLE childStdInWrite = nullptr; - if (!DuplicateHandle( - currentProcess, childStdInWriteTmp, - currentProcess, &childStdInWrite, - 0, FALSE, DUPLICATE_SAME_ACCESS)) - { - return kOSError_OperationFailed; - } - if (!CloseHandle(childStdInWriteTmp)) - { - return kOSError_OperationFailed; - } - - // Now we can actually get around to starting a process - PROCESS_INFORMATION processInfo; - ZeroMemory(&processInfo, sizeof(processInfo)); - - // TODO: switch to proper wide-character versions of these... - STARTUPINFOW startupInfo; - ZeroMemory(&startupInfo, sizeof(startupInfo)); - startupInfo.cb = sizeof(startupInfo); - startupInfo.hStdError = childStdErrWrite; - startupInfo.hStdOutput = childStdOutWrite; - startupInfo.hStdInput = childStdInRead; - startupInfo.dwFlags = STARTF_USESTDHANDLES; - - // `CreateProcess` requires write access to this, for some reason... - BOOL success = CreateProcessW( - isExecutablePath_ ? executableName_.toWString().begin() : nullptr, - (LPWSTR)commandLine_.ToString().toWString().begin(), - nullptr, - nullptr, - true, - CREATE_NO_WINDOW, - nullptr, // TODO: allow specifying environment variables? - nullptr, - &startupInfo, - &processInfo); - if (!success) - { - return kOSError_OperationFailed; - } - - // close handles we are now done with - CloseHandle(processInfo.hThread); - CloseHandle(childStdOutWrite); - CloseHandle(childStdErrWrite); - CloseHandle(childStdInRead); - - // Create a thread to read from the child's stdout. - OSProcessSpawner_ReaderThreadInfo stdOutThreadInfo; - stdOutThreadInfo.file = childStdOutRead; - HANDLE stdOutThread = CreateThread(nullptr, 0, &osReaderThreadProc, (LPVOID)&stdOutThreadInfo, 0, nullptr); - - // Create a thread to read from the child's stderr. - OSProcessSpawner_ReaderThreadInfo stdErrThreadInfo; - stdErrThreadInfo.file = childStdErrRead; - HANDLE stdErrThread = CreateThread(nullptr, 0, &osReaderThreadProc, (LPVOID)&stdErrThreadInfo, 0, nullptr); - - // wait for the process to exit - // TODO: set a timeout as a safety measure... - WaitForSingleObject(processInfo.hProcess, INFINITE); - - // get exit code for process - DWORD childExitCode = 0; - if (!GetExitCodeProcess(processInfo.hProcess, &childExitCode)) - { - return kOSError_OperationFailed; - } - - // wait for the reader threads - WaitForSingleObject(stdOutThread, INFINITE); - WaitForSingleObject(stdErrThread, INFINITE); - - CloseHandle(processInfo.hProcess); - CloseHandle(childStdOutRead); - CloseHandle(childStdErrRead); - CloseHandle(childStdInWrite); - - standardOutput_ = stdOutThreadInfo.output; - standardError_ = stdErrThreadInfo.output; - resultCode_ = childExitCode; - - return kOSError_None; -} - -char const* osGetExecutableSuffix() -{ - return ".exe"; -} - #else static bool advance(OSFindFilesResult& result) @@ -475,213 +215,4 @@ OSFindFilesResult osFindChildDirectories( return result; } -// OSProcessSpawner - -void OSProcessSpawner::pushExecutableName( - Slang::String executableName) -{ - executableName_ = executableName; - arguments_.add(executableName); - isExecutablePath_ = false; -} - -void OSProcessSpawner::pushExecutablePath( - Slang::String executablePath) -{ - executableName_ = executablePath; - arguments_.add(executablePath); - isExecutablePath_ = true; -} - -void OSProcessSpawner::pushArgument( - Slang::String argument) -{ - arguments_.add(argument); - argumentList_.add(argument); -} - -Slang::String OSProcessSpawner::getCommandLine() -{ - Slang::UInt argCount = arguments_.getCount(); - - Slang::StringBuilder sb; - for(Slang::UInt ii = 0; ii < argCount; ++ii) - { - if(ii != 0) sb << " "; - sb << arguments_[ii]; - } - return sb.ProduceString(); -} - -OSError OSProcessSpawner::spawnAndWaitForCompletion() -{ - List<char const*> argPtrs; - for(auto arg : arguments_) - { - argPtrs.add(arg.getBuffer()); - } - argPtrs.add(NULL); - - int stdoutPipe[2]; - int stderrPipe[2]; - - if(pipe(stdoutPipe) == -1) - return kOSError_OperationFailed; - - if(pipe(stderrPipe) == -1) - return kOSError_OperationFailed; - - pid_t childProcessID = fork(); - if (childProcessID == -1) - return kOSError_OperationFailed; - - 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"); - exit(1); - } - 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 kOSError_OperationFailed; - } - - // Set a timeout of ten seconds; - // we really shouldn't wait too long... - int pollTimeout = 10000; - 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... - return kOSError_OperationFailed; - } - - 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--; - } - - 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--; - } - - 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 kOSError_OperationFailed; - } - - - pid_t terminatedProcessID = waitpid( - childProcessID, - &childStatus, - 0); - if (terminatedProcessID == -1) - { - return kOSError_OperationFailed; - } - - if(terminatedProcessID == childProcessID) - { - if(WIFEXITED(childStatus)) - { - resultCode_ = (int)(int8_t)WEXITSTATUS(childStatus); - } - else - { - resultCode_ = 1; - } - - return kOSError_None; - } - } - - } - - return kOSError_OperationFailed; -} - -char const* osGetExecutableSuffix() -{ - return ""; -} - #endif |
