From 3265002a48b821e01b75f9a2795fff581af24518 Mon Sep 17 00:00:00 2001 From: stonewell Date: Sun, 22 May 2016 21:08:29 -0700 Subject: [PATCH 1/5] add --pipe arguement, let winpty run under pipe mode which do not check isatty for stdin,stdout,stderr --- src/unix-adapter/InputHandler.cc | 5 ++++- src/unix-adapter/OutputHandler.cc | 5 ++++- src/unix-adapter/main.cc | 15 ++++++++++++--- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/unix-adapter/InputHandler.cc b/src/unix-adapter/InputHandler.cc index 3f1bed85..bb1665a7 100644 --- a/src/unix-adapter/InputHandler.cc +++ b/src/unix-adapter/InputHandler.cc @@ -34,6 +34,8 @@ #include "Util.h" #include "WakeupFd.h" +extern bool g_pipe_mode; + InputHandler::InputHandler(HANDLE winpty, WakeupFd &completionWakeup) : m_winpty(winpty), m_completionWakeup(completionWakeup), @@ -41,7 +43,8 @@ InputHandler::InputHandler(HANDLE winpty, WakeupFd &completionWakeup) : m_shouldShutdown(0), m_threadCompleted(0) { - assert(isatty(STDIN_FILENO)); + if (!g_pipe_mode) + assert(isatty(STDIN_FILENO)); pthread_create(&m_thread, NULL, InputHandler::threadProcS, this); } diff --git a/src/unix-adapter/OutputHandler.cc b/src/unix-adapter/OutputHandler.cc index 64b5163c..b50977f0 100644 --- a/src/unix-adapter/OutputHandler.cc +++ b/src/unix-adapter/OutputHandler.cc @@ -33,6 +33,8 @@ #include "Util.h" #include "WakeupFd.h" +extern bool g_pipe_mode; + OutputHandler::OutputHandler(HANDLE winpty, WakeupFd &completionWakeup) : m_winpty(winpty), m_completionWakeup(completionWakeup), @@ -40,7 +42,8 @@ OutputHandler::OutputHandler(HANDLE winpty, WakeupFd &completionWakeup) : m_shouldShutdown(0), m_threadCompleted(0) { - assert(isatty(STDOUT_FILENO)); + if (!g_pipe_mode) + assert(isatty(STDOUT_FILENO)); pthread_create(&m_thread, NULL, OutputHandler::threadProcS, this); } diff --git a/src/unix-adapter/main.cc b/src/unix-adapter/main.cc index 863f6349..24a4f9ae 100644 --- a/src/unix-adapter/main.cc +++ b/src/unix-adapter/main.cc @@ -51,7 +51,8 @@ #define CSI "\x1b[" static WakeupFd *g_mainWakeup = NULL; - +bool g_pipe_mode = false; + static WakeupFd &mainWakeup() { if (g_mainWakeup == NULL) { @@ -329,6 +330,7 @@ struct Arguments { static void parseArguments(int argc, char *argv[], Arguments &out) { out.mouseInput = false; + g_pipe_mode = false; const char *const program = argc >= 1 ? argv[0] : ""; int argi = 1; while (argi < argc) { @@ -344,6 +346,8 @@ static void parseArguments(int argc, char *argv[], Arguments &out) } else if (arg == "--version") { dumpVersionToStdout(); exit(0); + } else if (arg == "--pipe") { + g_pipe_mode = true; } else if (arg == "--") { break; } else { @@ -449,7 +453,11 @@ int main(int argc, char *argv[]) } registerResizeSignalHandler(); - termios mode = setRawTerminalMode(); + + termios mode; + + if (!g_pipe_mode) + mode = setRawTerminalMode(); if (args.mouseInput) { // Start by disabling UTF-8 coordinate mode (1005), just in case we @@ -512,7 +520,8 @@ int main(int argc, char *argv[]) CSI"?1006l" CSI"?1015l" CSI"?1003l" CSI"?1002l" CSI"?1000l"); } - restoreTerminalMode(mode); + if (!g_pipe_mode) + restoreTerminalMode(mode); winpty_close(winpty); return exitCode; From 6b547aec68151b6bddf631cd3c6c1c2d050cebf5 Mon Sep 17 00:00:00 2001 From: stonewell Date: Mon, 23 May 2016 22:42:39 -0700 Subject: [PATCH 2/5] add control pipe when running pipe mode --- src/include/winpty.h | 6 ++ src/libwinpty/winpty.cc | 5 + src/unix-adapter/ControlHandler.cc | 152 +++++++++++++++++++++++++++++ src/unix-adapter/ControlHandler.h | 57 +++++++++++ src/unix-adapter/main.cc | 41 ++++++++ 5 files changed, 261 insertions(+) create mode 100644 src/unix-adapter/ControlHandler.cc create mode 100644 src/unix-adapter/ControlHandler.h diff --git a/src/include/winpty.h b/src/include/winpty.h index 26a19ceb..09dddd83 100644 --- a/src/include/winpty.h +++ b/src/include/winpty.h @@ -86,6 +86,12 @@ WINPTY_API int winpty_get_process_id(winpty_t *pc); */ WINPTY_API HANDLE winpty_get_data_pipe(winpty_t *pc); +/* + * Returns an overlapped-mode pipe handle that can be read and written + * like a Unix terminal. + */ +WINPTY_API HANDLE winpty_get_control_pipe(winpty_t *pc); + /* * Change the size of the Windows console. */ diff --git a/src/libwinpty/winpty.cc b/src/libwinpty/winpty.cc index 58d7529f..0b2d4c21 100644 --- a/src/libwinpty/winpty.cc +++ b/src/libwinpty/winpty.cc @@ -542,6 +542,11 @@ WINPTY_API HANDLE winpty_get_data_pipe(winpty_t *pc) return pc->dataPipe; } +WINPTY_API HANDLE winpty_get_control_pipe(winpty_t *pc) +{ + return pc->controlPipe; +} + WINPTY_API int winpty_set_size(winpty_t *pc, int cols, int rows) { auto packet = newPacket(); diff --git a/src/unix-adapter/ControlHandler.cc b/src/unix-adapter/ControlHandler.cc new file mode 100644 index 00000000..22f85b72 --- /dev/null +++ b/src/unix-adapter/ControlHandler.cc @@ -0,0 +1,152 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "ControlHandler.h" + +#include +#include +#include +#include + +#include +#include + +#include "../shared/DebugClient.h" +#include "Event.h" +#include "Util.h" +#include "WakeupFd.h" + +ControlHandler::ControlHandler(HANDLE control, HANDLE winpty, WakeupFd &completionWakeup) : + m_control(control), + m_winpty(winpty), + m_completionWakeup(completionWakeup), + m_threadHasBeenJoined(false), + m_shouldShutdown(0), + m_threadCompleted(0) +{ + pthread_create(&m_thread, NULL, ControlHandler::threadProcS, this); +} + +void ControlHandler::shutdown() { + startShutdown(); + if (!m_threadHasBeenJoined) { + int ret = pthread_join(m_thread, NULL); + assert(ret == 0 && "pthread_join failed"); + m_threadHasBeenJoined = true; + } +} + +void ControlHandler::threadProc() { + Event ioEvent; + std::vector buffer(4096); + while (true) { + // Handle shutdown + m_wakeup.reset(); + if (m_shouldShutdown) { + trace("ControlHandler: shutting down"); + break; + } + + // Read from the pipe. + { + DWORD numRead; + OVERLAPPED over = {0}; + over.hEvent = ioEvent.handle(); + BOOL ret = ReadFile(m_control, + &buffer[0], buffer.size(), + &numRead, + &over); + if (!ret && GetLastError() == ERROR_IO_PENDING) { + const HANDLE handles[] = { + ioEvent.handle(), + m_wakeup.handle(), + }; + const DWORD waitRet = + WaitForMultipleObjects(2, handles, FALSE, INFINITE); + if (waitRet == WAIT_OBJECT_0 + 1) { + trace("ControlHandler: shutting down, canceling I/O"); + assert(m_shouldShutdown); + CancelIo(m_control); + GetOverlappedResult(m_control, &over, &numRead, TRUE); + break; + } + assert(waitRet == WAIT_OBJECT_0); + ret = GetOverlappedResult(m_control, &over, &numRead, TRUE); + } + if (!ret || numRead == 0) { + if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { + trace("ControlHandler: pipe closed: numRead=%u", + static_cast(numRead)); + } else { + trace("ControlHandler: read failed: " + "ret=%d lastError=0x%x numRead=%u", + ret, + static_cast(GetLastError()), + static_cast(numRead)); + } + break; + } + } //end read + + { + //Write to pipe + DWORD written; + OVERLAPPED over = {0}; + over.hEvent = ioEvent.handle(); + BOOL ret = WriteFile(m_winpty, + &buffer[0], numRead, + &written, + &over); + if (!ret && GetLastError() == ERROR_IO_PENDING) { + const HANDLE handles[] = { + ioEvent.handle(), + m_wakeup.handle(), + }; + const DWORD waitRet = + WaitForMultipleObjects(2, handles, FALSE, INFINITE); + if (waitRet == WAIT_OBJECT_0 + 1) { + trace("InputHandler: shutting down, canceling I/O"); + assert(m_shouldShutdown); + CancelIo(m_winpty); + GetOverlappedResult(m_winpty, &over, &written, TRUE); + break; + } + assert(waitRet == WAIT_OBJECT_0); + ret = GetOverlappedResult(m_winpty, &over, &written, TRUE); + } + if (!ret || written != static_cast(numRead)) { + if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { + trace("InputHandler: pipe closed: written=%u", + static_cast(written)); + } else { + trace("InputHandler: write failed: " + "ret=%d lastError=0x%x numRead=%d written=%u", + ret, + static_cast(GetLastError()), + numRead, + static_cast(written)); + } + break; + } + }//end write + } + m_threadCompleted = 1; + m_completionWakeup.set(); +} diff --git a/src/unix-adapter/ControlHandler.h b/src/unix-adapter/ControlHandler.h new file mode 100644 index 00000000..c7f50134 --- /dev/null +++ b/src/unix-adapter/ControlHandler.h @@ -0,0 +1,57 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef UNIX_ADAPTER_CONTROL_HANDLER_H +#define UNIX_ADAPTER_CONTROL_HANDLER_H + +#include +#include +#include + +#include "Event.h" +#include "WakeupFd.h" + +// Connect winpty overlapped I/O to Cygwin blocking STDOUT_FILENO. +class ControlHandler { +public: + ControlHandler(HANDLE control, HANDLE winpty, WakeupFd &completionWakeup); + ~ControlHandler() { shutdown(); } + bool isComplete() { return m_threadCompleted; } + void startShutdown() { m_shouldShutdown = 1; m_wakeup.set(); } + void shutdown(); + +private: + static void *threadProcS(void *pvthis) { + reinterpret_cast(pvthis)->threadProc(); + return NULL; + } + void threadProc(); + + HANDLE m_control; + HANDLE m_winpty; + pthread_t m_thread; + WakeupFd &m_completionWakeup; + Event m_wakeup; + bool m_threadHasBeenJoined; + volatile sig_atomic_t m_shouldShutdown; + volatile sig_atomic_t m_threadCompleted; +}; + +#endif // UNIX_ADAPTER_CONTROL_HANDLER_H diff --git a/src/unix-adapter/main.cc b/src/unix-adapter/main.cc index 24a4f9ae..12fcec97 100644 --- a/src/unix-adapter/main.cc +++ b/src/unix-adapter/main.cc @@ -43,6 +43,7 @@ #include "../shared/DebugClient.h" #include "../shared/UnixCtrlChars.h" #include "../shared/WinptyVersion.h" +#include "../shared/StringBuilder.h" #include "InputHandler.h" #include "OutputHandler.h" #include "Util.h" @@ -319,6 +320,7 @@ static void usage(const char *program, int exitCode) printf(" --mouse Enable terminal mouse input\n"); printf(" --showkey Dump STDIN escape sequences\n"); printf(" --version Show the winpty version number\n"); + printf(" --pipe run winpty in pipe mode, the stdin/stdout/stderr will be piped from other process\n"); exit(exitCode); } @@ -331,6 +333,7 @@ static void parseArguments(int argc, char *argv[], Arguments &out) { out.mouseInput = false; g_pipe_mode = false; + const char *const program = argc >= 1 ? argv[0] : ""; int argi = 1; while (argi < argc) { @@ -405,6 +408,26 @@ static std::string formatErrorMessage(DWORD err) return msg; } +static HANDLE createControlPipe() { + WStringBuilder sb(4); + sb << GetCurrentProcessId(); + + const std::wstring control_pipe_name = + L"\\\\.\\pipe\\winpty-" + sb.str_moved(); + + return CreateNamedPipeW(control_pipe_name.c_str(), + /*dwOpenMode=*/ + PIPE_ACCESS_DUPLEX | + FILE_FLAG_FIRST_PIPE_INSTANCE, + /*dwPipeMode=*/ + 0, + /*nMaxInstances=*/1, + /*nOutBufferSize=*/0, + /*nInBufferSize=*/0, + /*nDefaultTimeOut=*/3000, + NULL); +} + int main(int argc, char *argv[]) { setlocale(LC_ALL, ""); @@ -480,6 +503,16 @@ int main(int argc, char *argv[]) CSI"?1000h" CSI"?1002h" CSI"?1003h" CSI"?1015h" CSI"?1006h"); } + HANDLE control_pipe = INVALID_HANDLE_VALUE; + ControlHandler * controlHandler = NULL; + + if (g_pipe_mode) { + control_pipe = createControlPipe(); + controlHandler = new ControlHandler(control_pipe, + winpty_get_control_pipe(winptr), + mainWakeup()); + } + OutputHandler outputHandler(winpty_get_data_pipe(winpty), mainWakeup()); InputHandler inputHandler(winpty_get_data_pipe(winpty), mainWakeup()); @@ -510,6 +543,11 @@ int main(int argc, char *argv[]) outputHandler.shutdown(); inputHandler.shutdown(); + if (controlHandler) { + controlHandler->shutdown(); + delete controlHandler; + } + const int exitCode = winpty_get_exit_code(winpty); if (args.mouseInput) { @@ -524,5 +562,8 @@ int main(int argc, char *argv[]) restoreTerminalMode(mode); winpty_close(winpty); + if (control_pipe != INVALID_HANDLE_VALUE) + CloseHandle(control_pipe); + return exitCode; } From 695d795cd859329e36de42153c687075b2af1b32 Mon Sep 17 00:00:00 2001 From: stonewell Date: Mon, 23 May 2016 23:12:28 -0700 Subject: [PATCH 3/5] change to control input/output handler to handle read/write --- src/shared/Buffer.cc | 2 +- src/unix-adapter/ControlHandler.cc | 152 ------------------ src/unix-adapter/ControlInputHandler.cc | 111 +++++++++++++ ...ControlHandler.h => ControlInputHandler.h} | 12 +- src/unix-adapter/ControlOutputHandler.cc | 111 +++++++++++++ src/unix-adapter/ControlOutputHandler.h | 57 +++++++ src/unix-adapter/main.cc | 31 ++-- 7 files changed, 307 insertions(+), 169 deletions(-) delete mode 100644 src/unix-adapter/ControlHandler.cc create mode 100644 src/unix-adapter/ControlInputHandler.cc rename src/unix-adapter/{ControlHandler.h => ControlInputHandler.h} (85%) create mode 100644 src/unix-adapter/ControlOutputHandler.cc create mode 100644 src/unix-adapter/ControlOutputHandler.h diff --git a/src/shared/Buffer.cc b/src/shared/Buffer.cc index d566f7a4..31dd30ba 100644 --- a/src/shared/Buffer.cc +++ b/src/shared/Buffer.cc @@ -45,7 +45,7 @@ void WriteBuffer::putRawData(const void *data, size_t len) { void WriteBuffer::replaceRawData(size_t pos, const void *data, size_t len) { ASSERT(pos <= m_buf.size() && len <= m_buf.size() - pos); const auto p = reinterpret_cast(data); - std::copy(p, p + len, m_buf.begin()); + std::copy(p, p + len, m_buf.begin() + pos); } void WriteBuffer::putInt32(int32_t i) { diff --git a/src/unix-adapter/ControlHandler.cc b/src/unix-adapter/ControlHandler.cc deleted file mode 100644 index 22f85b72..00000000 --- a/src/unix-adapter/ControlHandler.cc +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) 2011-2015 Ryan Prichard -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "ControlHandler.h" - -#include -#include -#include -#include - -#include -#include - -#include "../shared/DebugClient.h" -#include "Event.h" -#include "Util.h" -#include "WakeupFd.h" - -ControlHandler::ControlHandler(HANDLE control, HANDLE winpty, WakeupFd &completionWakeup) : - m_control(control), - m_winpty(winpty), - m_completionWakeup(completionWakeup), - m_threadHasBeenJoined(false), - m_shouldShutdown(0), - m_threadCompleted(0) -{ - pthread_create(&m_thread, NULL, ControlHandler::threadProcS, this); -} - -void ControlHandler::shutdown() { - startShutdown(); - if (!m_threadHasBeenJoined) { - int ret = pthread_join(m_thread, NULL); - assert(ret == 0 && "pthread_join failed"); - m_threadHasBeenJoined = true; - } -} - -void ControlHandler::threadProc() { - Event ioEvent; - std::vector buffer(4096); - while (true) { - // Handle shutdown - m_wakeup.reset(); - if (m_shouldShutdown) { - trace("ControlHandler: shutting down"); - break; - } - - // Read from the pipe. - { - DWORD numRead; - OVERLAPPED over = {0}; - over.hEvent = ioEvent.handle(); - BOOL ret = ReadFile(m_control, - &buffer[0], buffer.size(), - &numRead, - &over); - if (!ret && GetLastError() == ERROR_IO_PENDING) { - const HANDLE handles[] = { - ioEvent.handle(), - m_wakeup.handle(), - }; - const DWORD waitRet = - WaitForMultipleObjects(2, handles, FALSE, INFINITE); - if (waitRet == WAIT_OBJECT_0 + 1) { - trace("ControlHandler: shutting down, canceling I/O"); - assert(m_shouldShutdown); - CancelIo(m_control); - GetOverlappedResult(m_control, &over, &numRead, TRUE); - break; - } - assert(waitRet == WAIT_OBJECT_0); - ret = GetOverlappedResult(m_control, &over, &numRead, TRUE); - } - if (!ret || numRead == 0) { - if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { - trace("ControlHandler: pipe closed: numRead=%u", - static_cast(numRead)); - } else { - trace("ControlHandler: read failed: " - "ret=%d lastError=0x%x numRead=%u", - ret, - static_cast(GetLastError()), - static_cast(numRead)); - } - break; - } - } //end read - - { - //Write to pipe - DWORD written; - OVERLAPPED over = {0}; - over.hEvent = ioEvent.handle(); - BOOL ret = WriteFile(m_winpty, - &buffer[0], numRead, - &written, - &over); - if (!ret && GetLastError() == ERROR_IO_PENDING) { - const HANDLE handles[] = { - ioEvent.handle(), - m_wakeup.handle(), - }; - const DWORD waitRet = - WaitForMultipleObjects(2, handles, FALSE, INFINITE); - if (waitRet == WAIT_OBJECT_0 + 1) { - trace("InputHandler: shutting down, canceling I/O"); - assert(m_shouldShutdown); - CancelIo(m_winpty); - GetOverlappedResult(m_winpty, &over, &written, TRUE); - break; - } - assert(waitRet == WAIT_OBJECT_0); - ret = GetOverlappedResult(m_winpty, &over, &written, TRUE); - } - if (!ret || written != static_cast(numRead)) { - if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { - trace("InputHandler: pipe closed: written=%u", - static_cast(written)); - } else { - trace("InputHandler: write failed: " - "ret=%d lastError=0x%x numRead=%d written=%u", - ret, - static_cast(GetLastError()), - numRead, - static_cast(written)); - } - break; - } - }//end write - } - m_threadCompleted = 1; - m_completionWakeup.set(); -} diff --git a/src/unix-adapter/ControlInputHandler.cc b/src/unix-adapter/ControlInputHandler.cc new file mode 100644 index 00000000..b3f9c3f4 --- /dev/null +++ b/src/unix-adapter/ControlInputHandler.cc @@ -0,0 +1,111 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "ControlInputHandler.h" + +#include +#include +#include +#include + +#include +#include + +#include "../shared/DebugClient.h" +#include "Event.h" +#include "Util.h" +#include "WakeupFd.h" + +ControlInputHandler::ControlInputHandler(HANDLE control, HANDLE winpty, WakeupFd &completionWakeup) : + m_control(control), + m_winpty(winpty), + m_completionWakeup(completionWakeup), + m_threadHasBeenJoined(false), + m_shouldShutdown(0), + m_threadCompleted(0) +{ + pthread_create(&m_thread, NULL, ControlInputHandler::threadProcS, this); +} + +void ControlInputHandler::shutdown() { + startShutdown(); + if (!m_threadHasBeenJoined) { + int ret = pthread_join(m_thread, NULL); + assert(ret == 0 && "pthread_join failed"); + m_threadHasBeenJoined = true; + } +} + +void ControlInputHandler::threadProc() { + while (true) { + // Handle shutdown + m_wakeup.reset(); + if (m_shouldShutdown) { + trace("ControlInputHandler: shutting down"); + break; + } + + // Read from the pipe. + DWORD numRead; + char data; + + BOOL ret = ReadFile(m_control, + &data, 1, + &numRead, + nullptr); + if (!ret || numRead == 0) { + if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { + trace("ControlInputHandler: pipe closed: numRead=%u", + static_cast(numRead)); + } else { + trace("ControlInputHandler: read failed: " + "ret=%d lastError=0x%x numRead=%u", + ret, + static_cast(GetLastError()), + static_cast(numRead)); + } + break; + } + + //Write to pipe + DWORD written; + ret = WriteFile(m_winpty, + &data, numRead, + &written, + nullptr); + if (!ret || written != numRead) { + if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { + trace("ControlInputHandler: pipe closed: written=%u", + static_cast(written)); + } else { + trace("ControlInputHandler: write failed: " + "ret=%d lastError=0x%x numRead=%d written=%u", + ret, + static_cast(GetLastError()), + numRead, + static_cast(written)); + } + break; + } + + } + m_threadCompleted = 1; + m_completionWakeup.set(); +} diff --git a/src/unix-adapter/ControlHandler.h b/src/unix-adapter/ControlInputHandler.h similarity index 85% rename from src/unix-adapter/ControlHandler.h rename to src/unix-adapter/ControlInputHandler.h index c7f50134..81b07021 100644 --- a/src/unix-adapter/ControlHandler.h +++ b/src/unix-adapter/ControlInputHandler.h @@ -18,8 +18,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#ifndef UNIX_ADAPTER_CONTROL_HANDLER_H -#define UNIX_ADAPTER_CONTROL_HANDLER_H +#ifndef UNIX_ADAPTER_CONTROL_INPUT_HANDLER_H +#define UNIX_ADAPTER_CONTROL_INPUT_HANDLER_H #include #include @@ -29,17 +29,17 @@ #include "WakeupFd.h" // Connect winpty overlapped I/O to Cygwin blocking STDOUT_FILENO. -class ControlHandler { +class ControlInputHandler { public: - ControlHandler(HANDLE control, HANDLE winpty, WakeupFd &completionWakeup); - ~ControlHandler() { shutdown(); } + ControlInputHandler(HANDLE control, HANDLE winpty, WakeupFd &completionWakeup); + ~ControlInputHandler() { shutdown(); } bool isComplete() { return m_threadCompleted; } void startShutdown() { m_shouldShutdown = 1; m_wakeup.set(); } void shutdown(); private: static void *threadProcS(void *pvthis) { - reinterpret_cast(pvthis)->threadProc(); + reinterpret_cast(pvthis)->threadProc(); return NULL; } void threadProc(); diff --git a/src/unix-adapter/ControlOutputHandler.cc b/src/unix-adapter/ControlOutputHandler.cc new file mode 100644 index 00000000..3de7d060 --- /dev/null +++ b/src/unix-adapter/ControlOutputHandler.cc @@ -0,0 +1,111 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "ControlOutputHandler.h" + +#include +#include +#include +#include + +#include +#include + +#include "../shared/DebugClient.h" +#include "Event.h" +#include "Util.h" +#include "WakeupFd.h" + +ControlOutputHandler::ControlOutputHandler(HANDLE control, HANDLE winpty, WakeupFd &completionWakeup) : + m_control(control), + m_winpty(winpty), + m_completionWakeup(completionWakeup), + m_threadHasBeenJoined(false), + m_shouldShutdown(0), + m_threadCompleted(0) +{ + pthread_create(&m_thread, NULL, ControlOutputHandler::threadProcS, this); +} + +void ControlOutputHandler::shutdown() { + startShutdown(); + if (!m_threadHasBeenJoined) { + int ret = pthread_join(m_thread, NULL); + assert(ret == 0 && "pthread_join failed"); + m_threadHasBeenJoined = true; + } +} + +void ControlOutputHandler::threadProc() { + while (true) { + // Handle shutdown + m_wakeup.reset(); + if (m_shouldShutdown) { + trace("ControlOutputHandler: shutting down"); + break; + } + + // Read from the pipe. + DWORD numRead; + char data; + + BOOL ret = ReadFile(m_winpty, + &data, 1, + &numRead, + nullptr); + if (!ret || numRead == 0) { + if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { + trace("ControlOutputHandler: pipe closed: numRead=%u", + static_cast(numRead)); + } else { + trace("ControlOutputHandler: read failed: " + "ret=%d lastError=0x%x numRead=%u", + ret, + static_cast(GetLastError()), + static_cast(numRead)); + } + break; + } + + //Write to pipe + DWORD written; + ret = WriteFile(m_control, + &data, numRead, + &written, + nullptr); + if (!ret || written != numRead) { + if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { + trace("ControlInputHandler: pipe closed: written=%u", + static_cast(written)); + } else { + trace("ControlInputHandler: write failed: " + "ret=%d lastError=0x%x numRead=%d written=%u", + ret, + static_cast(GetLastError()), + numRead, + static_cast(written)); + } + break; + } + + } + m_threadCompleted = 1; + m_completionWakeup.set(); +} diff --git a/src/unix-adapter/ControlOutputHandler.h b/src/unix-adapter/ControlOutputHandler.h new file mode 100644 index 00000000..871af800 --- /dev/null +++ b/src/unix-adapter/ControlOutputHandler.h @@ -0,0 +1,57 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef UNIX_ADAPTER_CONTROL_OUTPUT_HANDLER_H +#define UNIX_ADAPTER_CONTROL_OUTPUT_HANDLER_H + +#include +#include +#include + +#include "Event.h" +#include "WakeupFd.h" + +// Connect winpty overlapped I/O to Cygwin blocking STDOUT_FILENO. +class ControlOutputHandler { +public: + ControlOutputHandler(HANDLE control, HANDLE winpty, WakeupFd &completionWakeup); + ~ControlOutputHandler() { shutdown(); } + bool isComplete() { return m_threadCompleted; } + void startShutdown() { m_shouldShutdown = 1; m_wakeup.set(); } + void shutdown(); + +private: + static void *threadProcS(void *pvthis) { + reinterpret_cast(pvthis)->threadProc(); + return NULL; + } + void threadProc(); + + HANDLE m_control; + HANDLE m_winpty; + pthread_t m_thread; + WakeupFd &m_completionWakeup; + Event m_wakeup; + bool m_threadHasBeenJoined; + volatile sig_atomic_t m_shouldShutdown; + volatile sig_atomic_t m_threadCompleted; +}; + +#endif // UNIX_ADAPTER_CONTROL_OUTPUT_HANDLER_H diff --git a/src/unix-adapter/main.cc b/src/unix-adapter/main.cc index 12fcec97..ec6e0a6a 100644 --- a/src/unix-adapter/main.cc +++ b/src/unix-adapter/main.cc @@ -49,6 +49,9 @@ #include "Util.h" #include "WakeupFd.h" +#include "ControlInputHandler.h" +#include "ControlOutputHandler.h" + #define CSI "\x1b[" static WakeupFd *g_mainWakeup = NULL; @@ -504,13 +507,17 @@ int main(int argc, char *argv[]) } HANDLE control_pipe = INVALID_HANDLE_VALUE; - ControlHandler * controlHandler = NULL; + ControlInputHandler * controlInputHandler = NULL; + ControlOutputHandler * controlOutputHandler = NULL; if (g_pipe_mode) { control_pipe = createControlPipe(); - controlHandler = new ControlHandler(control_pipe, - winpty_get_control_pipe(winptr), - mainWakeup()); + controlInputHandler = new ControlInputHandler(control_pipe, + winpty_get_control_pipe(winptr), + mainWakeup()); + controlOutputHandler = new ControlOutputHandler(control_pipe, + winpty_get_control_pipe(winptr), + mainWakeup()); } OutputHandler outputHandler(winpty_get_data_pipe(winpty), mainWakeup()); @@ -543,11 +550,6 @@ int main(int argc, char *argv[]) outputHandler.shutdown(); inputHandler.shutdown(); - if (controlHandler) { - controlHandler->shutdown(); - delete controlHandler; - } - const int exitCode = winpty_get_exit_code(winpty); if (args.mouseInput) { @@ -562,8 +564,17 @@ int main(int argc, char *argv[]) restoreTerminalMode(mode); winpty_close(winpty); - if (control_pipe != INVALID_HANDLE_VALUE) + //control pipe may block on control pipe or winpty control pipe + //so do shutdown on everything closed + if (g_pipe_mode) { CloseHandle(control_pipe); + + controlInputHandler->shutdown(); + delete controlInputHandler; + + controlOutputHandler->shutdown(); + delete controlOutputHandler; + } return exitCode; } From 4389dcbdafec230cc10b49841ef0c16f317f54f3 Mon Sep 17 00:00:00 2001 From: stonewell Date: Mon, 23 May 2016 23:22:07 -0700 Subject: [PATCH 4/5] merge control input/output handler into control handler --- ...ntrolInputHandler.cc => ControlHandler.cc} | 28 ++--- ...ControlInputHandler.h => ControlHandler.h} | 17 ++- src/unix-adapter/ControlOutputHandler.cc | 111 ------------------ src/unix-adapter/ControlOutputHandler.h | 57 --------- src/unix-adapter/main.cc | 29 +++-- 5 files changed, 42 insertions(+), 200 deletions(-) rename src/unix-adapter/{ControlInputHandler.cc => ControlHandler.cc} (81%) rename src/unix-adapter/{ControlInputHandler.h => ControlHandler.h} (80%) delete mode 100644 src/unix-adapter/ControlOutputHandler.cc delete mode 100644 src/unix-adapter/ControlOutputHandler.h diff --git a/src/unix-adapter/ControlInputHandler.cc b/src/unix-adapter/ControlHandler.cc similarity index 81% rename from src/unix-adapter/ControlInputHandler.cc rename to src/unix-adapter/ControlHandler.cc index b3f9c3f4..e736b9e1 100644 --- a/src/unix-adapter/ControlInputHandler.cc +++ b/src/unix-adapter/ControlHandler.cc @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#include "ControlInputHandler.h" +#include "ControlHandler.h" #include #include @@ -33,18 +33,18 @@ #include "Util.h" #include "WakeupFd.h" -ControlInputHandler::ControlInputHandler(HANDLE control, HANDLE winpty, WakeupFd &completionWakeup) : - m_control(control), - m_winpty(winpty), +ControlHandler::ControlHandler(HANDLE r, HANDLE w, WakeupFd &completionWakeup) : + m_read_pipe(r), + m_write_pipe(w), m_completionWakeup(completionWakeup), m_threadHasBeenJoined(false), m_shouldShutdown(0), m_threadCompleted(0) { - pthread_create(&m_thread, NULL, ControlInputHandler::threadProcS, this); + pthread_create(&m_thread, NULL, ControlHandler::threadProcS, this); } -void ControlInputHandler::shutdown() { +void ControlHandler::shutdown() { startShutdown(); if (!m_threadHasBeenJoined) { int ret = pthread_join(m_thread, NULL); @@ -53,12 +53,12 @@ void ControlInputHandler::shutdown() { } } -void ControlInputHandler::threadProc() { +void ControlHandler::threadProc() { while (true) { // Handle shutdown m_wakeup.reset(); if (m_shouldShutdown) { - trace("ControlInputHandler: shutting down"); + trace("ControlHandler: shutting down"); break; } @@ -66,16 +66,16 @@ void ControlInputHandler::threadProc() { DWORD numRead; char data; - BOOL ret = ReadFile(m_control, + BOOL ret = ReadFile(m_read_pipe, &data, 1, &numRead, nullptr); if (!ret || numRead == 0) { if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { - trace("ControlInputHandler: pipe closed: numRead=%u", + trace("ControlHandler: pipe closed: numRead=%u", static_cast(numRead)); } else { - trace("ControlInputHandler: read failed: " + trace("ControlHandler: read failed: " "ret=%d lastError=0x%x numRead=%u", ret, static_cast(GetLastError()), @@ -86,16 +86,16 @@ void ControlInputHandler::threadProc() { //Write to pipe DWORD written; - ret = WriteFile(m_winpty, + ret = WriteFile(m_write_pipe, &data, numRead, &written, nullptr); if (!ret || written != numRead) { if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { - trace("ControlInputHandler: pipe closed: written=%u", + trace("ControlHandler: pipe closed: written=%u", static_cast(written)); } else { - trace("ControlInputHandler: write failed: " + trace("ControlHandler: write failed: " "ret=%d lastError=0x%x numRead=%d written=%u", ret, static_cast(GetLastError()), diff --git a/src/unix-adapter/ControlInputHandler.h b/src/unix-adapter/ControlHandler.h similarity index 80% rename from src/unix-adapter/ControlInputHandler.h rename to src/unix-adapter/ControlHandler.h index 81b07021..090dbafb 100644 --- a/src/unix-adapter/ControlInputHandler.h +++ b/src/unix-adapter/ControlHandler.h @@ -18,8 +18,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#ifndef UNIX_ADAPTER_CONTROL_INPUT_HANDLER_H -#define UNIX_ADAPTER_CONTROL_INPUT_HANDLER_H +#ifndef UNIX_ADAPTER_CONTROL_HANDLER_H +#define UNIX_ADAPTER_CONTROL_HANDLER_H #include #include @@ -28,24 +28,23 @@ #include "Event.h" #include "WakeupFd.h" -// Connect winpty overlapped I/O to Cygwin blocking STDOUT_FILENO. -class ControlInputHandler { +class ControlHandler { public: - ControlInputHandler(HANDLE control, HANDLE winpty, WakeupFd &completionWakeup); - ~ControlInputHandler() { shutdown(); } + ControlHandler(HANDLE read_pipe, HANDLE write_pipe, WakeupFd &completionWakeup); + ~ControlHandler() { shutdown(); } bool isComplete() { return m_threadCompleted; } void startShutdown() { m_shouldShutdown = 1; m_wakeup.set(); } void shutdown(); private: static void *threadProcS(void *pvthis) { - reinterpret_cast(pvthis)->threadProc(); + reinterpret_cast(pvthis)->threadProc(); return NULL; } void threadProc(); - HANDLE m_control; - HANDLE m_winpty; + HANDLE m_read_pipe; + HANDLE m_write_pipe; pthread_t m_thread; WakeupFd &m_completionWakeup; Event m_wakeup; diff --git a/src/unix-adapter/ControlOutputHandler.cc b/src/unix-adapter/ControlOutputHandler.cc deleted file mode 100644 index 3de7d060..00000000 --- a/src/unix-adapter/ControlOutputHandler.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2011-2015 Ryan Prichard -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "ControlOutputHandler.h" - -#include -#include -#include -#include - -#include -#include - -#include "../shared/DebugClient.h" -#include "Event.h" -#include "Util.h" -#include "WakeupFd.h" - -ControlOutputHandler::ControlOutputHandler(HANDLE control, HANDLE winpty, WakeupFd &completionWakeup) : - m_control(control), - m_winpty(winpty), - m_completionWakeup(completionWakeup), - m_threadHasBeenJoined(false), - m_shouldShutdown(0), - m_threadCompleted(0) -{ - pthread_create(&m_thread, NULL, ControlOutputHandler::threadProcS, this); -} - -void ControlOutputHandler::shutdown() { - startShutdown(); - if (!m_threadHasBeenJoined) { - int ret = pthread_join(m_thread, NULL); - assert(ret == 0 && "pthread_join failed"); - m_threadHasBeenJoined = true; - } -} - -void ControlOutputHandler::threadProc() { - while (true) { - // Handle shutdown - m_wakeup.reset(); - if (m_shouldShutdown) { - trace("ControlOutputHandler: shutting down"); - break; - } - - // Read from the pipe. - DWORD numRead; - char data; - - BOOL ret = ReadFile(m_winpty, - &data, 1, - &numRead, - nullptr); - if (!ret || numRead == 0) { - if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { - trace("ControlOutputHandler: pipe closed: numRead=%u", - static_cast(numRead)); - } else { - trace("ControlOutputHandler: read failed: " - "ret=%d lastError=0x%x numRead=%u", - ret, - static_cast(GetLastError()), - static_cast(numRead)); - } - break; - } - - //Write to pipe - DWORD written; - ret = WriteFile(m_control, - &data, numRead, - &written, - nullptr); - if (!ret || written != numRead) { - if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { - trace("ControlInputHandler: pipe closed: written=%u", - static_cast(written)); - } else { - trace("ControlInputHandler: write failed: " - "ret=%d lastError=0x%x numRead=%d written=%u", - ret, - static_cast(GetLastError()), - numRead, - static_cast(written)); - } - break; - } - - } - m_threadCompleted = 1; - m_completionWakeup.set(); -} diff --git a/src/unix-adapter/ControlOutputHandler.h b/src/unix-adapter/ControlOutputHandler.h deleted file mode 100644 index 871af800..00000000 --- a/src/unix-adapter/ControlOutputHandler.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2011-2015 Ryan Prichard -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef UNIX_ADAPTER_CONTROL_OUTPUT_HANDLER_H -#define UNIX_ADAPTER_CONTROL_OUTPUT_HANDLER_H - -#include -#include -#include - -#include "Event.h" -#include "WakeupFd.h" - -// Connect winpty overlapped I/O to Cygwin blocking STDOUT_FILENO. -class ControlOutputHandler { -public: - ControlOutputHandler(HANDLE control, HANDLE winpty, WakeupFd &completionWakeup); - ~ControlOutputHandler() { shutdown(); } - bool isComplete() { return m_threadCompleted; } - void startShutdown() { m_shouldShutdown = 1; m_wakeup.set(); } - void shutdown(); - -private: - static void *threadProcS(void *pvthis) { - reinterpret_cast(pvthis)->threadProc(); - return NULL; - } - void threadProc(); - - HANDLE m_control; - HANDLE m_winpty; - pthread_t m_thread; - WakeupFd &m_completionWakeup; - Event m_wakeup; - bool m_threadHasBeenJoined; - volatile sig_atomic_t m_shouldShutdown; - volatile sig_atomic_t m_threadCompleted; -}; - -#endif // UNIX_ADAPTER_CONTROL_OUTPUT_HANDLER_H diff --git a/src/unix-adapter/main.cc b/src/unix-adapter/main.cc index ec6e0a6a..08a22028 100644 --- a/src/unix-adapter/main.cc +++ b/src/unix-adapter/main.cc @@ -49,8 +49,8 @@ #include "Util.h" #include "WakeupFd.h" -#include "ControlInputHandler.h" -#include "ControlOutputHandler.h" +#include "ControlHandler.h" + #define CSI "\x1b[" @@ -418,7 +418,7 @@ static HANDLE createControlPipe() { const std::wstring control_pipe_name = L"\\\\.\\pipe\\winpty-" + sb.str_moved(); - return CreateNamedPipeW(control_pipe_name.c_str(), + HANDLE h = CreateNamedPipeW(control_pipe_name.c_str(), /*dwOpenMode=*/ PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, @@ -429,6 +429,11 @@ static HANDLE createControlPipe() { /*nInBufferSize=*/0, /*nDefaultTimeOut=*/3000, NULL); + + if (h != INVALID_HANDLE_VALUE) + ConnectNamedPipe(h, NULL); + + return h; } int main(int argc, char *argv[]) @@ -512,12 +517,18 @@ int main(int argc, char *argv[]) if (g_pipe_mode) { control_pipe = createControlPipe(); - controlInputHandler = new ControlInputHandler(control_pipe, - winpty_get_control_pipe(winptr), - mainWakeup()); - controlOutputHandler = new ControlOutputHandler(control_pipe, - winpty_get_control_pipe(winptr), - mainWakeup()); + + if (control_pipe == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Error creating control pipe.\n"); + exit(1); + } + + controlInputHandler = new ControlHandler(control_pipe, + winpty_get_control_pipe(winptr), + mainWakeup()); + controlOutputHandler = new ControlHandler(winpty_get_control_pipe(winptr), + control_pipe, + mainWakeup()); } OutputHandler outputHandler(winpty_get_data_pipe(winpty), mainWakeup()); From c1018d6881b2648677a10fa5ffe8be87c887cda0 Mon Sep 17 00:00:00 2001 From: Stone Si Date: Wed, 25 May 2016 12:31:19 -0700 Subject: [PATCH 5/5] finish pipe mode --- src/unix-adapter/ControlHandler.cc | 82 +++++++++++++++++++++--------- src/unix-adapter/main.cc | 48 +++++++---------- src/unix-adapter/subdir.mk | 1 + 3 files changed, 77 insertions(+), 54 deletions(-) diff --git a/src/unix-adapter/ControlHandler.cc b/src/unix-adapter/ControlHandler.cc index e736b9e1..cb9fe301 100644 --- a/src/unix-adapter/ControlHandler.cc +++ b/src/unix-adapter/ControlHandler.cc @@ -53,6 +53,43 @@ void ControlHandler::shutdown() { } } +static BOOL read_pipe(HANDLE p, char * buf, int read_size) { + char * tmp = buf; + + while (read_size > 0) { + DWORD numRead = 0; + BOOL ret = ReadFile(p, + tmp, + read_size, + &numRead, + NULL); + + if (!ret || numRead == 0) { + return FALSE; + } + + read_size -= numRead; + tmp += numRead; + } + + return TRUE; +} + +static BOOL read_packet(HANDLE p, std::vector & buf) { + typedef unsigned __int64 uint64_t; + + uint64_t size = 0; + + char * tmp = (char *)&size; + if (!read_pipe(p, tmp, sizeof(uint64_t))) + return FALSE; + + buf.insert(buf.end(), tmp, tmp + sizeof(uint64_t)); + buf.resize(size); + + return read_pipe(p, &buf[sizeof(uint64_t)], size - sizeof(uint64_t)); +} + void ControlHandler::threadProc() { while (true) { // Handle shutdown @@ -63,48 +100,45 @@ void ControlHandler::threadProc() { } // Read from the pipe. - DWORD numRead; - char data; - - BOOL ret = ReadFile(m_read_pipe, - &data, 1, - &numRead, - nullptr); - if (!ret || numRead == 0) { - if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { - trace("ControlHandler: pipe closed: numRead=%u", - static_cast(numRead)); - } else { - trace("ControlHandler: read failed: " - "ret=%d lastError=0x%x numRead=%u", - ret, - static_cast(GetLastError()), - static_cast(numRead)); - } + std::vector data; + + ConnectNamedPipe(m_read_pipe, NULL); + + BOOL ret = read_packet(m_read_pipe, + data); + + if (!ret) { + trace("ControlHandler: read failed: " + "ret=%d lastError=0x%x", + ret, + static_cast(GetLastError())); break; } //Write to pipe DWORD written; ret = WriteFile(m_write_pipe, - &data, numRead, + &data[0], data.size(), &written, - nullptr); - if (!ret || written != numRead) { + NULL); + if (!ret || written != data.size()) { if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { trace("ControlHandler: pipe closed: written=%u", static_cast(written)); } else { trace("ControlHandler: write failed: " - "ret=%d lastError=0x%x numRead=%d written=%u", + "ret=%d lastError=0x%x numRead=%ld written=%u", ret, static_cast(GetLastError()), - numRead, + static_cast(data.size()), static_cast(written)); } break; } - + + DWORD numRead = 0; + ReadFile(m_write_pipe, &data[0], 4, &numRead, NULL); + WriteFile(m_read_pipe, &data[0], numRead, &written, NULL); } m_threadCompleted = 1; m_completionWakeup.set(); diff --git a/src/unix-adapter/main.cc b/src/unix-adapter/main.cc index 08a22028..9a6eb66f 100644 --- a/src/unix-adapter/main.cc +++ b/src/unix-adapter/main.cc @@ -43,7 +43,6 @@ #include "../shared/DebugClient.h" #include "../shared/UnixCtrlChars.h" #include "../shared/WinptyVersion.h" -#include "../shared/StringBuilder.h" #include "InputHandler.h" #include "OutputHandler.h" #include "Util.h" @@ -411,29 +410,23 @@ static std::string formatErrorMessage(DWORD err) return msg; } -static HANDLE createControlPipe() { - WStringBuilder sb(4); - sb << GetCurrentProcessId(); +static void createControlPipe(HANDLE & r) { + DWORD pid = GetCurrentProcessId(); - const std::wstring control_pipe_name = - L"\\\\.\\pipe\\winpty-" + sb.str_moved(); + WCHAR buf[255] = {0}; + wsprintf(buf, L"\\\\.\\pipe\\winpty-%ld", pid); - HANDLE h = CreateNamedPipeW(control_pipe_name.c_str(), + r = CreateNamedPipeW(buf, /*dwOpenMode=*/ PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, /*dwPipeMode=*/ - 0, + PIPE_TYPE_MESSAGE | PIPE_WAIT, /*nMaxInstances=*/1, - /*nOutBufferSize=*/0, - /*nInBufferSize=*/0, + /*nOutBufferSize=*/64 * 1024, + /*nInBufferSize=*/64 * 1024, /*nDefaultTimeOut=*/3000, NULL); - - if (h != INVALID_HANDLE_VALUE) - ConnectNamedPipe(h, NULL); - - return h; } int main(int argc, char *argv[]) @@ -512,25 +505,21 @@ int main(int argc, char *argv[]) } HANDLE control_pipe = INVALID_HANDLE_VALUE; - ControlInputHandler * controlInputHandler = NULL; - ControlOutputHandler * controlOutputHandler = NULL; + ControlHandler * controlInputHandler = NULL; if (g_pipe_mode) { - control_pipe = createControlPipe(); + createControlPipe(control_pipe); if (control_pipe == INVALID_HANDLE_VALUE) { fprintf(stderr, "Error creating control pipe.\n"); exit(1); } - + controlInputHandler = new ControlHandler(control_pipe, - winpty_get_control_pipe(winptr), + winpty_get_control_pipe(winpty), mainWakeup()); - controlOutputHandler = new ControlHandler(winpty_get_control_pipe(winptr), - control_pipe, - mainWakeup()); } - + OutputHandler outputHandler(winpty_get_data_pipe(winpty), mainWakeup()); InputHandler inputHandler(winpty_get_data_pipe(winpty), mainWakeup()); @@ -579,12 +568,11 @@ int main(int argc, char *argv[]) //so do shutdown on everything closed if (g_pipe_mode) { CloseHandle(control_pipe); - - controlInputHandler->shutdown(); - delete controlInputHandler; - - controlOutputHandler->shutdown(); - delete controlOutputHandler; + + if (controlInputHandler) { + controlInputHandler->shutdown(); + delete controlInputHandler; + } } return exitCode; diff --git a/src/unix-adapter/subdir.mk b/src/unix-adapter/subdir.mk index ce2cd084..26562599 100644 --- a/src/unix-adapter/subdir.mk +++ b/src/unix-adapter/subdir.mk @@ -23,6 +23,7 @@ ALL_TARGETS += build/$(UNIX_ADAPTER_EXE) $(eval $(call def_unix_target,unix-adapter,)) UNIX_ADAPTER_OBJECTS = \ + build/unix-adapter/unix-adapter/ControlHandler.o \ build/unix-adapter/unix-adapter/InputHandler.o \ build/unix-adapter/unix-adapter/OutputHandler.o \ build/unix-adapter/unix-adapter/Util.o \