brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.4 KiB · 001396f Raw
358 lines · cpp
1//===-- PipeWindows.cpp ---------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Host/windows/PipeWindows.h"10 11#include "llvm/ADT/SmallString.h"12#include "llvm/Support/Process.h"13#include "llvm/Support/raw_ostream.h"14 15#include <fcntl.h>16#include <io.h>17#include <rpc.h>18 19#include <atomic>20#include <string>21 22using namespace lldb;23using namespace lldb_private;24 25static std::atomic<uint32_t> g_pipe_serial(0);26static constexpr llvm::StringLiteral g_pipe_name_prefix = "\\\\.\\Pipe\\";27 28PipeWindows::PipeWindows()29    : m_read(INVALID_HANDLE_VALUE), m_write(INVALID_HANDLE_VALUE),30      m_read_fd(PipeWindows::kInvalidDescriptor),31      m_write_fd(PipeWindows::kInvalidDescriptor) {32  ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));33  ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));34}35 36PipeWindows::PipeWindows(pipe_t read, pipe_t write)37    : m_read((HANDLE)read), m_write((HANDLE)write),38      m_read_fd(PipeWindows::kInvalidDescriptor),39      m_write_fd(PipeWindows::kInvalidDescriptor) {40  assert(read != LLDB_INVALID_PIPE || write != LLDB_INVALID_PIPE);41 42  // Don't risk in passing file descriptors and getting handles from them by43  // _get_osfhandle since the retrieved handles are highly likely unrecognized44  // in the current process and usually crashes the program.  Pass handles45  // instead since the handle can be inherited.46 47  if (read != LLDB_INVALID_PIPE) {48    m_read_fd = _open_osfhandle((intptr_t)read, _O_RDONLY);49    // Make sure the fd and native handle are consistent.50    if (m_read_fd < 0)51      m_read = INVALID_HANDLE_VALUE;52  }53 54  if (write != LLDB_INVALID_PIPE) {55    m_write_fd = _open_osfhandle((intptr_t)write, _O_WRONLY);56    if (m_write_fd < 0)57      m_write = INVALID_HANDLE_VALUE;58  }59 60  ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));61  m_read_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr);62 63  ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));64  m_write_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr);65}66 67PipeWindows::~PipeWindows() { Close(); }68 69Status PipeWindows::CreateNew() {70  // Even for anonymous pipes, we open a named pipe.  This is because you71  // cannot get overlapped i/o on Windows without using a named pipe.  So we72  // synthesize a unique name.73  uint32_t serial = g_pipe_serial.fetch_add(1);74  std::string pipe_name = llvm::formatv(75      "lldb.pipe.{0}.{1}.{2}", GetCurrentProcessId(), &g_pipe_serial, serial);76 77  return CreateNew(pipe_name.c_str());78}79 80Status PipeWindows::CreateNew(llvm::StringRef name) {81  if (name.empty())82    return Status(ERROR_INVALID_PARAMETER, eErrorTypeWin32);83 84  if (CanRead() || CanWrite())85    return Status(ERROR_ALREADY_EXISTS, eErrorTypeWin32);86 87  std::string pipe_path = g_pipe_name_prefix.str();88  pipe_path.append(name.str());89 90  // We always create inheritable handles, but we won't pass them to a child91  // process unless explicitly requested (cf. ProcessLauncherWindows.cpp).92  SECURITY_ATTRIBUTES sa{sizeof(SECURITY_ATTRIBUTES), 0, TRUE};93 94  // Always open for overlapped i/o.  We implement blocking manually in Read95  // and Write.96  DWORD read_mode = FILE_FLAG_OVERLAPPED;97  m_read =98      ::CreateNamedPipeA(pipe_path.c_str(), PIPE_ACCESS_INBOUND | read_mode,99                         PIPE_TYPE_BYTE | PIPE_WAIT, /*nMaxInstances=*/1,100                         /*nOutBufferSize=*/1024,101                         /*nInBufferSize=*/1024,102                         /*nDefaultTimeOut=*/0, &sa);103  if (INVALID_HANDLE_VALUE == m_read)104    return Status(::GetLastError(), eErrorTypeWin32);105  m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY);106  ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));107  m_read_overlapped.hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);108 109  // Open the write end of the pipe. Note that closing either the read or 110  // write end of the pipe could directly close the pipe itself.111  Status result = OpenNamedPipe(name, false);112  if (!result.Success()) {113    CloseReadFileDescriptor();114    return result;115  }116 117  return result;118}119 120Status PipeWindows::CreateWithUniqueName(llvm::StringRef prefix,121                                         llvm::SmallVectorImpl<char> &name) {122  llvm::SmallString<128> pipe_name;123  Status error;124  ::UUID unique_id;125  RPC_CSTR unique_string;126  RPC_STATUS status = ::UuidCreate(&unique_id);127  if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)128    status = ::UuidToStringA(&unique_id, &unique_string);129  if (status == RPC_S_OK) {130    pipe_name = prefix;131    pipe_name += "-";132    pipe_name += reinterpret_cast<char *>(unique_string);133    ::RpcStringFreeA(&unique_string);134    error = CreateNew(pipe_name);135  } else {136    error = Status(status, eErrorTypeWin32);137  }138  if (error.Success())139    name = pipe_name;140  return error;141}142 143Status PipeWindows::OpenAsReader(llvm::StringRef name) {144  if (CanRead())145    return Status(); // Note the name is ignored.146 147  return OpenNamedPipe(name, true);148}149 150llvm::Error PipeWindows::OpenAsWriter(llvm::StringRef name,151                                      const Timeout<std::micro> &timeout) {152  if (CanWrite())153    return llvm::Error::success(); // Note the name is ignored.154 155  return OpenNamedPipe(name, false).takeError();156}157 158Status PipeWindows::OpenNamedPipe(llvm::StringRef name, bool is_read) {159  if (name.empty())160    return Status(ERROR_INVALID_PARAMETER, eErrorTypeWin32);161 162  assert(is_read ? !CanRead() : !CanWrite());163 164  // We always create inheritable handles, but we won't pass them to a child165  // process unless explicitly requested (cf. ProcessLauncherWindows.cpp).166  SECURITY_ATTRIBUTES attributes{sizeof(SECURITY_ATTRIBUTES), 0, TRUE};167 168  std::string pipe_path = g_pipe_name_prefix.str();169  pipe_path.append(name.str());170 171  if (is_read) {172    m_read = ::CreateFileA(pipe_path.c_str(), GENERIC_READ, 0, &attributes,173                           OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);174    if (INVALID_HANDLE_VALUE == m_read)175      return Status(::GetLastError(), eErrorTypeWin32);176 177    m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY);178 179    ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));180    m_read_overlapped.hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);181  } else {182    m_write = ::CreateFileA(pipe_path.c_str(), GENERIC_WRITE, 0, &attributes,183                            OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);184    if (INVALID_HANDLE_VALUE == m_write)185      return Status(::GetLastError(), eErrorTypeWin32);186 187    m_write_fd = _open_osfhandle((intptr_t)m_write, _O_WRONLY);188 189    ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));190    m_write_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr);191  }192 193  return Status();194}195 196int PipeWindows::GetReadFileDescriptor() const { return m_read_fd; }197 198int PipeWindows::GetWriteFileDescriptor() const { return m_write_fd; }199 200int PipeWindows::ReleaseReadFileDescriptor() {201  if (!CanRead())202    return PipeWindows::kInvalidDescriptor;203  int result = m_read_fd;204  m_read_fd = PipeWindows::kInvalidDescriptor;205  if (m_read_overlapped.hEvent)206    ::CloseHandle(m_read_overlapped.hEvent);207  m_read = INVALID_HANDLE_VALUE;208  ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));209  return result;210}211 212int PipeWindows::ReleaseWriteFileDescriptor() {213  if (!CanWrite())214    return PipeWindows::kInvalidDescriptor;215  int result = m_write_fd;216  m_write_fd = PipeWindows::kInvalidDescriptor;217  if (m_write_overlapped.hEvent)218    ::CloseHandle(m_write_overlapped.hEvent);219  m_write = INVALID_HANDLE_VALUE;220  ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));221  return result;222}223 224void PipeWindows::CloseReadFileDescriptor() {225  if (!CanRead())226    return;227 228  if (m_read_overlapped.hEvent)229    ::CloseHandle(m_read_overlapped.hEvent);230 231  _close(m_read_fd);232  m_read = INVALID_HANDLE_VALUE;233  m_read_fd = PipeWindows::kInvalidDescriptor;234  ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));235}236 237void PipeWindows::CloseWriteFileDescriptor() {238  if (!CanWrite())239    return;240 241  if (m_write_overlapped.hEvent)242    ::CloseHandle(m_write_overlapped.hEvent);243 244  _close(m_write_fd);245  m_write = INVALID_HANDLE_VALUE;246  m_write_fd = PipeWindows::kInvalidDescriptor;247  ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));248}249 250void PipeWindows::Close() {251  CloseReadFileDescriptor();252  CloseWriteFileDescriptor();253}254 255Status PipeWindows::Delete(llvm::StringRef name) { return Status(); }256 257bool PipeWindows::CanRead() const { return (m_read != INVALID_HANDLE_VALUE); }258 259bool PipeWindows::CanWrite() const { return (m_write != INVALID_HANDLE_VALUE); }260 261HANDLE262PipeWindows::GetReadNativeHandle() { return m_read; }263 264HANDLE265PipeWindows::GetWriteNativeHandle() { return m_write; }266 267llvm::Expected<size_t> PipeWindows::Read(void *buf, size_t size,268                                         const Timeout<std::micro> &timeout) {269  if (!CanRead())270    return Status(ERROR_INVALID_HANDLE, eErrorTypeWin32).takeError();271 272  DWORD bytes_read = 0;273  BOOL result = ::ReadFile(m_read, buf, size, &bytes_read, &m_read_overlapped);274  if (result)275    return bytes_read;276 277  DWORD failure_error = ::GetLastError();278  if (failure_error != ERROR_IO_PENDING)279    return Status(failure_error, eErrorTypeWin32).takeError();280 281  DWORD timeout_msec =282      timeout ? std::chrono::ceil<std::chrono::milliseconds>(*timeout).count()283              : INFINITE;284  DWORD wait_result =285      ::WaitForSingleObject(m_read_overlapped.hEvent, timeout_msec);286  if (wait_result != WAIT_OBJECT_0) {287    // The operation probably failed.  However, if it timed out, we need to288    // cancel the I/O. Between the time we returned from WaitForSingleObject289    // and the time we call CancelIoEx, the operation may complete.  If that290    // hapens, CancelIoEx will fail and return ERROR_NOT_FOUND. If that291    // happens, the original operation should be considered to have been292    // successful.293    bool failed = true;294    failure_error = ::GetLastError();295    if (wait_result == WAIT_TIMEOUT) {296      BOOL cancel_result = ::CancelIoEx(m_read, &m_read_overlapped);297      if (!cancel_result && ::GetLastError() == ERROR_NOT_FOUND)298        failed = false;299    }300    if (failed)301      return Status(failure_error, eErrorTypeWin32).takeError();302  }303 304  // Now we call GetOverlappedResult setting bWait to false, since we've305  // already waited as long as we're willing to.306  if (!::GetOverlappedResult(m_read, &m_read_overlapped, &bytes_read, FALSE))307    return Status(::GetLastError(), eErrorTypeWin32).takeError();308 309  return bytes_read;310}311 312llvm::Expected<size_t> PipeWindows::Write(const void *buf, size_t size,313                                          const Timeout<std::micro> &timeout) {314  if (!CanWrite())315    return Status(ERROR_INVALID_HANDLE, eErrorTypeWin32).takeError();316 317  DWORD bytes_written = 0;318  BOOL result =319      ::WriteFile(m_write, buf, size, &bytes_written, &m_write_overlapped);320  if (result)321    return bytes_written;322 323  DWORD failure_error = ::GetLastError();324  if (failure_error != ERROR_IO_PENDING)325    return Status(failure_error, eErrorTypeWin32).takeError();326 327  DWORD timeout_msec =328      timeout ? std::chrono::ceil<std::chrono::milliseconds>(*timeout).count()329              : INFINITE;330  DWORD wait_result =331      ::WaitForSingleObject(m_write_overlapped.hEvent, timeout_msec);332  if (wait_result != WAIT_OBJECT_0) {333    // The operation probably failed.  However, if it timed out, we need to334    // cancel the I/O. Between the time we returned from WaitForSingleObject335    // and the time we call CancelIoEx, the operation may complete.  If that336    // hapens, CancelIoEx will fail and return ERROR_NOT_FOUND. If that337    // happens, the original operation should be considered to have been338    // successful.339    bool failed = true;340    failure_error = ::GetLastError();341    if (wait_result == WAIT_TIMEOUT) {342      BOOL cancel_result = ::CancelIoEx(m_write, &m_write_overlapped);343      if (!cancel_result && ::GetLastError() == ERROR_NOT_FOUND)344        failed = false;345    }346    if (failed)347      return Status(failure_error, eErrorTypeWin32).takeError();348  }349 350  // Now we call GetOverlappedResult setting bWait to false, since we've351  // already waited as long as we're willing to.352  if (!::GetOverlappedResult(m_write, &m_write_overlapped, &bytes_written,353                             FALSE))354    return Status(::GetLastError(), eErrorTypeWin32).takeError();355 356  return bytes_written;357}358