llvm-project/lldb/source/Host/windows/PipeWindows.cpp
Zachary Turner b2df30d652 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
2014-10-08 20:38:41 +00:00

232 lines
4.9 KiB
C++

//===-- 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
}