diff options
Diffstat (limited to 'source/core/windows/slang-win-process.cpp')
| -rw-r--r-- | source/core/windows/slang-win-process.cpp | 213 |
1 files changed, 147 insertions, 66 deletions
diff --git a/source/core/windows/slang-win-process.cpp b/source/core/windows/slang-win-process.cpp index 3aa21deb5..8569a0854 100644 --- a/source/core/windows/slang-win-process.cpp +++ b/source/core/windows/slang-win-process.cpp @@ -1,45 +1,64 @@ // slang-win-process-util.cpp +#include "../slang-process-util.h" #include "../slang-process.h" - -#include "../slang-string.h" #include "../slang-string-escape-util.h" #include "../slang-string-util.h" -#include "../slang-process-util.h" - +#include "../slang-string.h" #include "slang-com-helper.h" #ifdef _WIN32 // TODO: We could try to avoid including this at all, but it would // mean trying to hide certain struct layouts, which would add // more dynamic allocation. -# include <windows.h> +#include <windows.h> #endif #include <stdio.h> #include <stdlib.h> #ifndef SLANG_RETURN_FAIL_ON_FALSE -# define SLANG_RETURN_FAIL_ON_FALSE(x) if (!(x)) return SLANG_FAIL; +#define SLANG_RETURN_FAIL_ON_FALSE(x) \ + if (!(x)) \ + return SLANG_FAIL; #endif -namespace Slang { +namespace Slang +{ // Has behavior very similar to unique_ptr - assignment is a move. class WinHandle { public: - /// Detach the encapsulated handle. Returns the handle (which now must be externally handled) - HANDLE detach() { HANDLE handle = m_handle; m_handle = nullptr; return handle; } + /// Detach the encapsulated handle. Returns the handle (which now must be externally handled) + HANDLE detach() + { + HANDLE handle = m_handle; + m_handle = nullptr; + return handle; + } /// Return as a handle operator HANDLE() const { return m_handle; } /// Assign - void operator=(HANDLE handle) { setNull(); m_handle = handle; } - void operator=(WinHandle&& rhs) { HANDLE handle = m_handle; m_handle = rhs.m_handle; rhs.m_handle = handle; } + void operator=(HANDLE handle) + { + setNull(); + m_handle = handle; + } + void operator=(WinHandle&& rhs) + { + HANDLE handle = m_handle; + m_handle = rhs.m_handle; + rhs.m_handle = handle; + } - /// Get ready for writing - SLANG_FORCE_INLINE HANDLE* writeRef() { setNull(); return &m_handle; } + /// Get ready for writing + SLANG_FORCE_INLINE HANDLE* writeRef() + { + setNull(); + return &m_handle; + } /// Get for read access SLANG_FORCE_INLINE const HANDLE* readRef() const { return &m_handle; } @@ -54,21 +73,28 @@ public: bool isNull() const { return m_handle == nullptr; } /// Ctor - WinHandle(HANDLE handle = nullptr) :m_handle(handle) {} - WinHandle(WinHandle&& rhs) :m_handle(rhs.m_handle) { rhs.m_handle = nullptr; } + WinHandle(HANDLE handle = nullptr) + : m_handle(handle) + { + } + WinHandle(WinHandle&& rhs) + : m_handle(rhs.m_handle) + { + rhs.m_handle = nullptr; + } /// Dtor ~WinHandle() { setNull(); } private: - WinHandle(const WinHandle&) = delete; void operator=(const WinHandle& rhs) = delete; HANDLE m_handle; }; -/* A simple Stream implementation of a File HANDLE (or Pipe). Note that currently does not allow getPosition/seek/atEnd */ +/* A simple Stream implementation of a File HANDLE (or Pipe). Note that currently does not allow + * getPosition/seek/atEnd */ class WinPipeStream : public Stream { public: @@ -76,12 +102,23 @@ public: // Stream virtual Int64 getPosition() SLANG_OVERRIDE { return 0; } - virtual SlangResult seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE { SLANG_UNUSED(origin); SLANG_UNUSED(offset); return SLANG_E_NOT_AVAILABLE; } + virtual SlangResult seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE + { + SLANG_UNUSED(origin); + SLANG_UNUSED(offset); + return SLANG_E_NOT_AVAILABLE; + } virtual SlangResult read(void* buffer, size_t length, size_t& outReadBytes) SLANG_OVERRIDE; virtual SlangResult write(const void* buffer, size_t length) SLANG_OVERRIDE; virtual bool isEnd() SLANG_OVERRIDE { return m_streamHandle.isNull(); } - virtual bool canRead() SLANG_OVERRIDE { return _has(FileAccess::Read) && !m_streamHandle.isNull(); } - virtual bool canWrite() SLANG_OVERRIDE { return _has(FileAccess::Write) && !m_streamHandle.isNull(); } + virtual bool canRead() SLANG_OVERRIDE + { + return _has(FileAccess::Read) && !m_streamHandle.isNull(); + } + virtual bool canWrite() SLANG_OVERRIDE + { + return _has(FileAccess::Write) && !m_streamHandle.isNull(); + } virtual void close() SLANG_OVERRIDE; virtual SlangResult flush() SLANG_OVERRIDE; @@ -90,7 +127,6 @@ public: ~WinPipeStream() { close(); } protected: - bool _has(FileAccess access) const { return (Index(access) & Index(m_access)) != 0; } SlangResult _updateState(BOOL res); @@ -104,15 +140,14 @@ protected: class WinProcess : public Process { public: - // Process virtual bool isTerminated() SLANG_OVERRIDE; virtual bool waitForTermination(Int timeInMs) SLANG_OVERRIDE; virtual void terminate(int32_t returnCode) SLANG_OVERRIDE; virtual void kill(int32_t returnCode) SLANG_OVERRIDE; - WinProcess(HANDLE handle, Stream* const* streams) : - m_processHandle(handle) + WinProcess(HANDLE handle, Stream* const* streams) + : m_processHandle(handle) { for (Index i = 0; i < Index(StdStreamType::CountOf); ++i) { @@ -121,17 +156,14 @@ public: } protected: - void _hasTerminated(); - WinHandle m_processHandle; ///< If not set the process has terminated + WinHandle m_processHandle; ///< If not set the process has terminated }; /* !!!!!!!!!!!!!!!!!!!!!!!!!!! WinPipeStream !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -WinPipeStream::WinPipeStream(HANDLE handle, FileAccess access, bool isOwned) : - m_streamHandle(handle), - m_access(access), - m_isOwned(isOwned) +WinPipeStream::WinPipeStream(HANDLE handle, FileAccess access, bool isOwned) + : m_streamHandle(handle), m_access(access), m_isOwned(isOwned) { // On Win32 a HANDLE has to be handled differently if it's a PIPE or FILE, so first determine @@ -198,7 +230,13 @@ SlangResult WinPipeStream::read(void* buffer, size_t length, size_t& outReadByte // Works on anonymous pipes too // https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-peeknamedpipe - SLANG_RETURN_ON_FAIL(_updateState(::PeekNamedPipe(m_streamHandle, nullptr, DWORD(0), &pipeBytesRead, &pipeTotalBytesAvailable, &pipeRemainingBytes))); + SLANG_RETURN_ON_FAIL(_updateState(::PeekNamedPipe( + m_streamHandle, + nullptr, + DWORD(0), + &pipeBytesRead, + &pipeTotalBytesAvailable, + &pipeRemainingBytes))); // If there is nothing to read we are done // If we don't do this ReadFile will *block* if there is nothing available if (pipeTotalBytesAvailable == 0) @@ -206,11 +244,13 @@ SlangResult WinPipeStream::read(void* buffer, size_t length, size_t& outReadByte return SLANG_OK; } - SLANG_RETURN_ON_FAIL(_updateState(::ReadFile(m_streamHandle, buffer, DWORD(length), &bytesRead, nullptr))); + SLANG_RETURN_ON_FAIL( + _updateState(::ReadFile(m_streamHandle, buffer, DWORD(length), &bytesRead, nullptr))); } else { - SLANG_RETURN_ON_FAIL(_updateState(::ReadFile(m_streamHandle, buffer, DWORD(length), &bytesRead, nullptr))); + SLANG_RETURN_ON_FAIL( + _updateState(::ReadFile(m_streamHandle, buffer, DWORD(length), &bytesRead, nullptr))); // If it's not a pipe, and there is nothing left, then we are done. if (length > 0 && bytesRead == 0) @@ -248,7 +288,7 @@ SlangResult WinPipeStream::write(const void* buffer, size_t length) close(); return SLANG_FAIL; } - + SLANG_UNUSED(err); return SLANG_FAIL; } @@ -265,7 +305,7 @@ void WinPipeStream::close() { if (!m_isOwned) { - // If we don't own it just detach it + // If we don't own it just detach it m_streamHandle.detach(); } m_streamHandle.setNull(); @@ -357,31 +397,31 @@ void WinProcess::kill(int32_t returnCode) /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* static */StringEscapeHandler* Process::getEscapeHandler() +/* static */ StringEscapeHandler* Process::getEscapeHandler() { return StringEscapeUtil::getHandler(StringEscapeUtil::Style::Space); } -/* static */UnownedStringSlice Process::getExecutableSuffix() +/* static */ UnownedStringSlice Process::getExecutableSuffix() { return UnownedStringSlice::fromLiteral(".exe"); } -/* static */SlangResult Process::getStdStream(StdStreamType type, RefPtr<Stream>& out) +/* static */ SlangResult Process::getStdStream(StdStreamType type, RefPtr<Stream>& out) { switch (type) { - case StdStreamType::In: + case StdStreamType::In: { out = new WinPipeStream(GetStdHandle(STD_INPUT_HANDLE), FileAccess::Read, false); return SLANG_OK; } - case StdStreamType::Out: + case StdStreamType::Out: { out = new WinPipeStream(GetStdHandle(STD_OUTPUT_HANDLE), FileAccess::Write, false); return SLANG_OK; } - case StdStreamType::ErrorOut: + case StdStreamType::ErrorOut: { out = new WinPipeStream(GetStdHandle(STD_ERROR_HANDLE), FileAccess::Write, false); return SLANG_OK; @@ -391,10 +431,13 @@ void WinProcess::kill(int32_t returnCode) return SLANG_FAIL; } -/* static */SlangResult Process::create(const CommandLine& commandLine, Process::Flags flags, RefPtr<Process>& outProcess) -{ +/* static */ SlangResult Process::create( + const CommandLine& commandLine, + Process::Flags flags, + RefPtr<Process>& outProcess) +{ WinHandle childStdOutRead; - WinHandle childStdErrRead; + WinHandle childStdErrRead; WinHandle childStdInWrite; WinHandle processHandle; @@ -409,7 +452,7 @@ void WinProcess::kill(int32_t returnCode) securityAttributes.bInheritHandle = true; // 0 means use the 'system default' - //const DWORD bufferSize = 64 * 1024; + // const DWORD bufferSize = 64 * 1024; const DWORD bufferSize = 0; { @@ -417,26 +460,59 @@ void WinProcess::kill(int32_t returnCode) WinHandle childStdErrReadTmp; WinHandle childStdInWriteTmp; // create stdout pipe for child process - SLANG_RETURN_FAIL_ON_FALSE(CreatePipe(childStdOutReadTmp.writeRef(), childStdOutWrite.writeRef(), &securityAttributes, bufferSize)); + SLANG_RETURN_FAIL_ON_FALSE(CreatePipe( + childStdOutReadTmp.writeRef(), + childStdOutWrite.writeRef(), + &securityAttributes, + bufferSize)); if ((flags & Process::Flag::DisableStdErrRedirection) == 0) { // create stderr pipe for child process - SLANG_RETURN_FAIL_ON_FALSE(CreatePipe(childStdErrReadTmp.writeRef(), childStdErrWrite.writeRef(), &securityAttributes, bufferSize)); + SLANG_RETURN_FAIL_ON_FALSE(CreatePipe( + childStdErrReadTmp.writeRef(), + childStdErrWrite.writeRef(), + &securityAttributes, + bufferSize)); } - // create stdin pipe for child process - SLANG_RETURN_FAIL_ON_FALSE(CreatePipe(childStdInRead.writeRef(), childStdInWriteTmp.writeRef(), &securityAttributes, bufferSize)); + // create stdin pipe for child process + SLANG_RETURN_FAIL_ON_FALSE(CreatePipe( + childStdInRead.writeRef(), + childStdInWriteTmp.writeRef(), + &securityAttributes, + bufferSize)); const HANDLE currentProcess = GetCurrentProcess(); // https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle - // create a non-inheritable duplicate of the stdout reader - SLANG_RETURN_FAIL_ON_FALSE(DuplicateHandle(currentProcess, childStdOutReadTmp, currentProcess, childStdOutRead.writeRef(), 0, FALSE, DUPLICATE_SAME_ACCESS)); + // create a non-inheritable duplicate of the stdout reader + SLANG_RETURN_FAIL_ON_FALSE(DuplicateHandle( + currentProcess, + childStdOutReadTmp, + currentProcess, + childStdOutRead.writeRef(), + 0, + FALSE, + DUPLICATE_SAME_ACCESS)); // create a non-inheritable duplicate of the stderr reader if (childStdErrReadTmp) - SLANG_RETURN_FAIL_ON_FALSE(DuplicateHandle(currentProcess, childStdErrReadTmp, currentProcess, childStdErrRead.writeRef(), 0, FALSE, DUPLICATE_SAME_ACCESS)); + SLANG_RETURN_FAIL_ON_FALSE(DuplicateHandle( + currentProcess, + childStdErrReadTmp, + currentProcess, + childStdErrRead.writeRef(), + 0, + FALSE, + DUPLICATE_SAME_ACCESS)); // create a non-inheritable duplicate of the stdin writer - SLANG_RETURN_FAIL_ON_FALSE(DuplicateHandle(currentProcess, childStdInWriteTmp, currentProcess, childStdInWrite.writeRef(), 0, FALSE, DUPLICATE_SAME_ACCESS)); + SLANG_RETURN_FAIL_ON_FALSE(DuplicateHandle( + currentProcess, + childStdInWriteTmp, + currentProcess, + childStdInWrite.writeRef(), + 0, + FALSE, + DUPLICATE_SAME_ACCESS)); } // TODO: switch to proper wide-character versions of these... @@ -478,12 +554,14 @@ void WinProcess::kill(int32_t returnCode) } // From docs: - // If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string pointed to by lpApplicationName - // specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. + // If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string + // pointed to by lpApplicationName specifies the module to execute, and the null-terminated + // string pointed to by lpCommandLine specifies the command line. // JS: - // Somewhat confusingly this means that even if lpApplicationName is specified, it muse *ALSO* be included as the first - // whitespace delimited arg must *also* be the (possibly) quoted executable + // Somewhat confusingly this means that even if lpApplicationName is specified, it muse + // *ALSO* be included as the first whitespace delimited arg must *also* be the (possibly) + // quoted executable // https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessa // `CreateProcess` requires write access to this, for some reason... @@ -510,9 +588,9 @@ void WinProcess::kill(int32_t returnCode) { // Lets see if we can set up to debug // https://docs.microsoft.com/en-us/windows/win32/debug/debugging-a-running-process - - //DebugActiveProcess(processInfo.dwProcessId); - + + // DebugActiveProcess(processInfo.dwProcessId); + // Resume the thread ResumeThread(processInfo.hThread); } @@ -527,15 +605,18 @@ void WinProcess::kill(int32_t returnCode) RefPtr<Stream> streams[Index(StdStreamType::CountOf)]; if (childStdErrRead) - streams[Index(StdStreamType::ErrorOut)] = new WinPipeStream(childStdErrRead.detach(), FileAccess::Read); - streams[Index(StdStreamType::Out)] = new WinPipeStream(childStdOutRead.detach(), FileAccess::Read); - streams[Index(StdStreamType::In)] = new WinPipeStream(childStdInWrite.detach(), FileAccess::Write); + streams[Index(StdStreamType::ErrorOut)] = + new WinPipeStream(childStdErrRead.detach(), FileAccess::Read); + streams[Index(StdStreamType::Out)] = + new WinPipeStream(childStdOutRead.detach(), FileAccess::Read); + streams[Index(StdStreamType::In)] = + new WinPipeStream(childStdInWrite.detach(), FileAccess::Write); outProcess = new WinProcess(processHandle.detach(), streams[0].readRef()); return SLANG_OK; } -/* static */void Process::sleepCurrentThread(Int timeInMs) +/* static */ void Process::sleepCurrentThread(Int timeInMs) { ::Sleep(DWORD(timeInMs)); } @@ -549,12 +630,12 @@ static uint64_t _getClockFrequency() static const uint64_t g_frequency = _getClockFrequency(); -/* static */uint64_t Process::getClockFrequency() +/* static */ uint64_t Process::getClockFrequency() { return g_frequency; } -/* static */uint64_t Process::getClockTick() +/* static */ uint64_t Process::getClockTick() { LARGE_INTEGER counter; QueryPerformanceCounter(&counter); |
