Fix deadlock in Python one-line execution.
Python one-line execution was using ConnectionFileDescriptor to do
a non-blocking read against a pipe. This won't work on Windows,
as CFD is implemented using select(), and select() only works with
sockets on Windows.
The solution is to use ConnectionGenericFile on Windows, which uses
the native API to do overlapped I/O on the pipe. This in turn
requires re-implementing Host::Pipe on Windows using native OS
handles instead of the more portable _pipe CRT api.
Reviewed by: Greg Clayton
Differential Revision: http://reviews.llvm.org/D5679
llvm-svn: 219339
diff --git a/lldb/source/Host/windows/PipeWindows.cpp b/lldb/source/Host/windows/PipeWindows.cpp
new file mode 100644
index 0000000..572be87
--- /dev/null
+++ b/lldb/source/Host/windows/PipeWindows.cpp
@@ -0,0 +1,231 @@
+//===-- PipeWindows.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/windows/PipeWindows.h"
+
+#include "llvm/Support/raw_ostream.h"
+
+#include <fcntl.h>
+#include <io.h>
+
+#include <atomic>
+#include <string>
+
+using namespace lldb_private;
+
+namespace
+{
+std::atomic<uint32_t> g_pipe_serial(0);
+}
+
+Pipe::Pipe()
+{
+ m_read = INVALID_HANDLE_VALUE;
+ m_write = INVALID_HANDLE_VALUE;
+
+ m_read_fd = -1;
+ m_write_fd = -1;
+
+ m_read_overlapped = nullptr;
+ m_write_overlapped = nullptr;
+}
+
+Pipe::~Pipe()
+{
+ Close();
+}
+
+bool
+Pipe::Open(bool read_overlapped, bool write_overlapped)
+{
+ if (IsValid())
+ return true;
+
+ 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;
+ pipe_name_stream.flush();
+
+ 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);
+ if (INVALID_HANDLE_VALUE == m_read)
+ return false;
+ m_write = ::CreateFile(pipe_name.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, write_mode, NULL);
+ if (INVALID_HANDLE_VALUE == m_write)
+ {
+ ::CloseHandle(m_read);
+ m_read = INVALID_HANDLE_VALUE;
+ return false;
+ }
+
+ 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));
+ }
+ return true;
+}
+
+int
+Pipe::GetReadFileDescriptor() const
+{
+ return m_read_fd;
+}
+
+int
+Pipe::GetWriteFileDescriptor() const
+{
+ return m_write_fd;
+}
+
+int
+Pipe::ReleaseReadFileDescriptor()
+{
+ 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;
+ }
+ return result;
+}
+
+int
+Pipe::ReleaseWriteFileDescriptor()
+{
+ 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;
+ }
+ return result;
+}
+
+void
+Pipe::Close()
+{
+ CloseReadFileDescriptor();
+ CloseWriteFileDescriptor();
+}
+
+bool
+Pipe::ReadDescriptorIsValid() const
+{
+ return m_read_fd != -1;
+}
+
+bool
+Pipe::WriteDescriptorIsValid() const
+{
+ return m_write_fd != -1;
+}
+
+bool
+Pipe::IsValid() const
+{
+ return ReadDescriptorIsValid() && WriteDescriptorIsValid();
+}
+
+bool
+Pipe::CloseReadFileDescriptor()
+{
+ if (ReadDescriptorIsValid())
+ {
+ int err;
+ err = _close(m_read_fd);
+ m_read_fd = -1;
+ m_read = INVALID_HANDLE_VALUE;
+ if (m_read_overlapped)
+ {
+ delete m_read_overlapped;
+ m_read_overlapped = nullptr;
+ }
+ return err == 0;
+ }
+ return true;
+}
+
+bool
+Pipe::CloseWriteFileDescriptor()
+{
+ if (WriteDescriptorIsValid())
+ {
+ int err;
+ 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;
+ }
+ return err == 0;
+ }
+ return true;
+}
+
+HANDLE
+Pipe::GetReadNativeHandle()
+{
+ return m_read;
+}
+
+HANDLE
+Pipe::GetWriteNativeHandle()
+{
+ return m_write;
+}
+
+size_t
+Pipe::Read(void *buf, size_t num_bytes)
+{
+ 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);
+ return bytes_read;
+ }
+ return 0; // Return 0 since errno won't be set if we didn't call read
+}
+
+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);
+ return bytes_written;
+ }
+ return 0; // Return 0 since errno won't be set if we didn't call write
+}