Index: include/lldb/Host/windows/PipeWindows.h =================================================================== --- include/lldb/Host/windows/PipeWindows.h +++ include/lldb/Host/windows/PipeWindows.h @@ -10,6 +10,9 @@ #ifndef liblldb_Host_windows_PipeWindows_h_ #define liblldb_Host_windows_PipeWindows_h_ +#include +#include + #include "lldb/Host/windows/windows.h" namespace lldb_private @@ -26,10 +29,11 @@ { public: Pipe(); + Pipe(const char *name); ~Pipe(); - bool Open(bool read_overlapped = false, bool write_overlapped = false); + bool Open(bool child_process_inherit = false); bool IsValid() const; @@ -59,18 +63,22 @@ GetWriteNativeHandle(); size_t Read(void *buf, size_t size); + bool ReadWithTimeout(void *buf, size_t size, const std::chrono::milliseconds &timeout, size_t &bytes_read); size_t Write(const void *buf, size_t size); private: + void Initialize(); + + std::string m_pipe_name; HANDLE m_read; HANDLE m_write; int m_read_fd; int m_write_fd; - OVERLAPPED *m_read_overlapped; - OVERLAPPED *m_write_overlapped; + OVERLAPPED m_read_overlapped; + OVERLAPPED m_write_overlapped; }; } // namespace lldb_private Index: source/Host/windows/PipeWindows.cpp =================================================================== --- source/Host/windows/PipeWindows.cpp +++ source/Host/windows/PipeWindows.cpp @@ -26,14 +26,13 @@ Pipe::Pipe() { - m_read = INVALID_HANDLE_VALUE; - m_write = INVALID_HANDLE_VALUE; - - m_read_fd = -1; - m_write_fd = -1; + Initialize(); +} - m_read_overlapped = nullptr; - m_write_overlapped = nullptr; +Pipe::Pipe(const char *pipe_name) +{ + Initialize(); + m_pipe_name = pipe_name; } Pipe::~Pipe() @@ -41,8 +40,20 @@ Close(); } +void +Pipe::Initialize() +{ + m_read = INVALID_HANDLE_VALUE; + m_write = INVALID_HANDLE_VALUE; + + ZeroMemory(&m_read_overlapped, sizeof(OVERLAPPED)); + ZeroMemory(&m_write_overlapped, sizeof(OVERLAPPED)); + m_read_fd = -1; + m_write_fd = -1; +} + bool -Pipe::Open(bool read_overlapped, bool write_overlapped) +Pipe::Open(bool child_process_inherit) { if (IsValid()) return true; @@ -50,20 +61,22 @@ uint32_t serial = g_pipe_serial.fetch_add(1); std::string pipe_name; llvm::raw_string_ostream pipe_name_stream(pipe_name); - pipe_name_stream << "\\\\.\\Pipe\\lldb.pipe." << ::GetCurrentProcessId() << "." << serial; + if (m_pipe_name.empty()) + pipe_name_stream << "\\\\.\\Pipe\\lldb.pipe." << ::GetCurrentProcessId() << "." << serial; + else + pipe_name_stream << "\\\\.\\Pipe\\" << m_pipe_name; pipe_name_stream.flush(); + m_pipe_name = pipe_name.c_str(); - DWORD read_mode = 0; - DWORD write_mode = 0; - if (read_overlapped) - read_mode |= FILE_FLAG_OVERLAPPED; - if (write_overlapped) - write_mode |= FILE_FLAG_OVERLAPPED; - m_read = - ::CreateNamedPipe(pipe_name.c_str(), PIPE_ACCESS_INBOUND | read_mode, PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024, 1024, 120 * 1000, NULL); + SECURITY_ATTRIBUTES attributes = {0}; + attributes.bInheritHandle = child_process_inherit; + DWORD read_mode = FILE_FLAG_OVERLAPPED; + DWORD write_mode = FILE_FLAG_OVERLAPPED; + m_read = ::CreateNamedPipe(m_pipe_name.c_str(), PIPE_ACCESS_INBOUND | read_mode, PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024, 1024, 120 * 1000, + &attributes); if (INVALID_HANDLE_VALUE == m_read) return false; - m_write = ::CreateFile(pipe_name.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, write_mode, NULL); + m_write = ::CreateFile(m_pipe_name.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, write_mode, &attributes); if (INVALID_HANDLE_VALUE == m_write) { ::CloseHandle(m_read); @@ -74,16 +87,7 @@ m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY); m_write_fd = _open_osfhandle((intptr_t)m_write, _O_WRONLY); - if (read_overlapped) - { - m_read_overlapped = new OVERLAPPED; - ZeroMemory(m_read_overlapped, sizeof(OVERLAPPED)); - } - if (write_overlapped) - { - m_write_overlapped = new OVERLAPPED; - ZeroMemory(m_write_overlapped, sizeof(OVERLAPPED)); - } + m_read_overlapped.hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); return true; } @@ -105,11 +109,8 @@ int result = m_read_fd; m_read_fd = -1; m_read = INVALID_HANDLE_VALUE; - if (m_read_overlapped) - { - delete m_read_overlapped; - m_read_overlapped = nullptr; - } + ::CloseHandle(m_read_overlapped.hEvent); + ZeroMemory(&m_read_overlapped, sizeof(OVERLAPPED)); return result; } @@ -119,11 +120,7 @@ int result = m_write_fd; m_write_fd = -1; m_write = INVALID_HANDLE_VALUE; - if (m_write_overlapped) - { - delete m_write_overlapped; - m_write_overlapped = nullptr; - } + ZeroMemory(&m_write_overlapped, sizeof(OVERLAPPED)); return result; } @@ -160,12 +157,9 @@ int err; err = _close(m_read_fd); m_read_fd = -1; + ::CloseHandle(m_read_overlapped.hEvent); + ZeroMemory(&m_read_overlapped, sizeof(OVERLAPPED)); m_read = INVALID_HANDLE_VALUE; - if (m_read_overlapped) - { - delete m_read_overlapped; - m_read_overlapped = nullptr; - } return err == 0; } return true; @@ -180,11 +174,7 @@ err = _close(m_write_fd); m_write_fd = -1; m_write = INVALID_HANDLE_VALUE; - if (m_write_overlapped) - { - delete m_write_overlapped; - m_write_overlapped = nullptr; - } + ZeroMemory(&m_write_overlapped, sizeof(OVERLAPPED)); return err == 0; } return true; @@ -208,23 +198,59 @@ if (ReadDescriptorIsValid()) { DWORD bytes_read = 0; - ::ReadFile(m_read, buf, num_bytes, &bytes_read, m_read_overlapped); - if (m_read_overlapped) - GetOverlappedResult(m_read, m_read_overlapped, &bytes_read, TRUE); + // For reads with no timeout, we don't need to use the event handle. Set it + // to null so that Windows doesn't mess with it. + HANDLE event_save = m_read_overlapped.hEvent; + m_read_overlapped.hEvent = nullptr; + ::ReadFile(m_read, buf, num_bytes, &bytes_read, &m_read_overlapped); + GetOverlappedResult(m_read, &m_read_overlapped, &bytes_read, TRUE); + m_read_overlapped.hEvent = event_save; return bytes_read; } return 0; // Return 0 since errno won't be set if we didn't call read } +bool +Pipe::ReadWithTimeout(void *buf, size_t num_bytes, const std::chrono::milliseconds &timeout, size_t &bytes_read) +{ + bytes_read = 0; + if (!ReadDescriptorIsValid()) + return false; + + DWORD sys_bytes_read = 0; + ::ReadFile(m_read, buf, num_bytes, &sys_bytes_read, &m_read_overlapped); + DWORD wait_result = WaitForSingleObject(m_read_overlapped.hEvent, timeout.count()); + bool failed = false; + if (wait_result != WAIT_OBJECT_0) + { + if (wait_result == WAIT_TIMEOUT) + { + // Even though we timed out previously, we might have completed between the time + // we timed out and the time we called CancelIoEx. If that happens, it won't + // find a request to cancel and this will fail with ERROR_NOT_FOUND. + BOOL cancel_result = CancelIoEx(m_read, &m_read_overlapped); + if (cancel_result || GetLastError() != ERROR_NOT_FOUND) + failed = true; + } + else + failed = true; + } + + if (!failed) + failed = GetOverlappedResult(m_read, &m_read_overlapped, &sys_bytes_read, FALSE); + + bytes_read = (failed) ? 0 : sys_bytes_read; + return failed; +} + size_t Pipe::Write(const void *buf, size_t num_bytes) { if (WriteDescriptorIsValid()) { DWORD bytes_written = 0; - ::WriteFile(m_write, buf, num_bytes, &bytes_written, m_read_overlapped); - if (m_write_overlapped) - GetOverlappedResult(m_write, m_write_overlapped, &bytes_written, TRUE); + ::WriteFile(m_write, buf, num_bytes, &bytes_written, &m_read_overlapped); + GetOverlappedResult(m_write, &m_write_overlapped, &bytes_written, TRUE); return bytes_written; } return 0; // Return 0 since errno won't be set if we didn't call write Index: source/Interpreter/ScriptInterpreterPython.cpp =================================================================== --- source/Interpreter/ScriptInterpreterPython.cpp +++ source/Interpreter/ScriptInterpreterPython.cpp @@ -603,18 +603,13 @@ // Set output to a temporary file so we can forward the results on to the result object Pipe pipe; -#if defined(_WIN32) - // By default Windows does not create a pipe object that can be used for a non-blocking read. - // We must explicitly request it. Furthermore, we can't use an fd for non-blocking read - // operations, and must use the native os HANDLE. - if (pipe.Open(true, false)) + if (pipe.Open()) { +#if defined(_WIN32) lldb::file_t read_file = pipe.GetReadNativeHandle(); pipe.ReleaseReadFileDescriptor(); std::unique_ptr conn_ap(new ConnectionGenericFile(read_file, true)); #else - if (pipe.Open()) - { std::unique_ptr conn_ap(new ConnectionFileDescriptor(pipe.ReleaseReadFileDescriptor(), true)); #endif if (conn_ap->IsConnected()) Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -13,7 +13,6 @@ // C Includes #include #include -#include #include // C++ Includes @@ -26,6 +25,7 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/Pipe.h" #include "lldb/Host/Socket.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/TimeValue.h" @@ -49,39 +49,28 @@ Error ReadPortFromPipe (const char *const named_pipe_path, uint16_t& port, const int timeout_secs) { - File name_pipe_file; - auto error = name_pipe_file.Open (named_pipe_path, File::eOpenOptionRead | File::eOpenOptionNonBlocking); - if (error.Fail ()) - return error; - - struct timeval tv = {timeout_secs, 0}; - const auto pipe_handle = name_pipe_file.GetWaitableHandle (); - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(pipe_handle, &rfds); - - const auto retval = ::select (pipe_handle + 1, &rfds, NULL, NULL, &tv); - if (retval == -1) - { - error.SetErrorToErrno (); - return error; - } - if (retval == 0) + Error error; + Pipe named_pipe(named_pipe_path); + if (!named_pipe.Open()) { - error.SetErrorString ("timeout exceeded"); + error.SetErrorString("An error occurred opening the pipe."); return error; } char port_cstr[256]; - port_cstr[0] = '\0'; size_t num_bytes = sizeof(port_cstr); - error = name_pipe_file.Read (port_cstr, num_bytes); + size_t bytes_read = 0; + port_cstr[0] = '\0'; - if (error.Success ()) + std::chrono::seconds timeout(timeout_secs); + if (!named_pipe.ReadWithTimeout(port_cstr, num_bytes, timeout, bytes_read)) { - assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); - port = Args::StringToUInt32 (port_cstr, 0); + error.SetErrorString("Timeout exceeded reading from the pipe"); + return error; } + + assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); + port = Args::StringToUInt32 (port_cstr, 0); return error; }