Skip to content

Commit

Permalink
[lldb] Updated lldb-server to spawn the child process and share socke…
Browse files Browse the repository at this point in the history
…t on Windows

`lldb-server platform --server` works on Windows now w/o multithreading. The rest functionality remains unchanged.

Added also PipeWindows::WriteWithTimeout(), fixed PipeWindows::ReadWithTimeout() and missing initialization of  m_read_overlapped.hEvent in the constructor PipeWindows(lldb::pipe_t read, lldb::pipe_t write).

Fixes llvm#90923, fixes llvm#56346.

This is the part 1 of the replacement of llvm#100670.

In the part 2 I plan to switch `lldb-server gdbserver` to use `--fd` and listen a common gdb port for all gdbserver connections. Then we can remove gdb port mapping to fix llvm#97537.
  • Loading branch information
slydiman committed Jul 31, 2024
1 parent c35c4c7 commit 526708c
Show file tree
Hide file tree
Showing 6 changed files with 375 additions and 50 deletions.
3 changes: 3 additions & 0 deletions lldb/include/lldb/Host/windows/PipeWindows.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ class PipeWindows : public PipeBase {
Status Delete(llvm::StringRef name) override;

Status Write(const void *buf, size_t size, size_t &bytes_written) override;
Status WriteWithTimeout(const void *buf, size_t size,
const std::chrono::microseconds &timeout,
size_t &bytes_written);
Status ReadWithTimeout(void *buf, size_t size,
const std::chrono::microseconds &timeout,
size_t &bytes_read) override;
Expand Down
69 changes: 61 additions & 8 deletions lldb/source/Host/windows/PipeWindows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ PipeWindows::PipeWindows(pipe_t read, pipe_t write)
}

ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
m_read_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr);

ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
m_write_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr);
}

PipeWindows::~PipeWindows() { Close(); }
Expand All @@ -77,6 +80,7 @@ Status PipeWindows::CreateNew(bool child_process_inherit) {

m_write_fd = _open_osfhandle((intptr_t)m_write, _O_WRONLY);
ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
m_write_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr);

return Status();
}
Expand Down Expand Up @@ -202,6 +206,7 @@ Status PipeWindows::OpenNamedPipe(llvm::StringRef name,
m_write_fd = _open_osfhandle((intptr_t)m_write, _O_WRONLY);

ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
m_write_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr);
}

return Status();
Expand All @@ -228,6 +233,8 @@ int PipeWindows::ReleaseWriteFileDescriptor() {
return PipeWindows::kInvalidDescriptor;
int result = m_write_fd;
m_write_fd = PipeWindows::kInvalidDescriptor;
if (m_write_overlapped.hEvent)
::CloseHandle(m_write_overlapped.hEvent);
m_write = INVALID_HANDLE_VALUE;
ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
return result;
Expand All @@ -250,6 +257,9 @@ void PipeWindows::CloseWriteFileDescriptor() {
if (!CanWrite())
return;

if (m_write_overlapped.hEvent)
::CloseHandle(m_write_overlapped.hEvent);

_close(m_write_fd);
m_write = INVALID_HANDLE_VALUE;
m_write_fd = PipeWindows::kInvalidDescriptor;
Expand Down Expand Up @@ -283,7 +293,12 @@ Status PipeWindows::ReadWithTimeout(void *buf, size_t size,
DWORD sys_bytes_read = size;
BOOL result = ::ReadFile(m_read, buf, sys_bytes_read, &sys_bytes_read,
&m_read_overlapped);
if (!result && GetLastError() != ERROR_IO_PENDING)
if (result) {
bytes_read = sys_bytes_read;
return Status();
}

if (GetLastError() != ERROR_IO_PENDING)
return Status(::GetLastError(), eErrorTypeWin32);

DWORD timeout = (duration == std::chrono::microseconds::zero())
Expand Down Expand Up @@ -319,18 +334,56 @@ Status PipeWindows::ReadWithTimeout(void *buf, size_t size,

Status PipeWindows::Write(const void *buf, size_t num_bytes,
size_t &bytes_written) {
return WriteWithTimeout(buf, num_bytes, std::chrono::microseconds::zero(),
bytes_written);
}

Status PipeWindows::WriteWithTimeout(const void *buf, size_t size,
const std::chrono::microseconds &duration,
size_t &bytes_written) {
if (!CanWrite())
return Status(ERROR_INVALID_HANDLE, eErrorTypeWin32);

DWORD sys_bytes_written = 0;
BOOL write_result = ::WriteFile(m_write, buf, num_bytes, &sys_bytes_written,
&m_write_overlapped);
if (!write_result && GetLastError() != ERROR_IO_PENDING)
bytes_written = 0;
DWORD sys_bytes_write = size;
BOOL result = ::WriteFile(m_write, buf, sys_bytes_write, &sys_bytes_write,
&m_write_overlapped);
if (result) {
bytes_written = sys_bytes_write;
return Status();
}

if (GetLastError() != ERROR_IO_PENDING)
return Status(::GetLastError(), eErrorTypeWin32);

BOOL result = GetOverlappedResult(m_write, &m_write_overlapped,
&sys_bytes_written, TRUE);
if (!result)
DWORD timeout = (duration == std::chrono::microseconds::zero())
? INFINITE
: duration.count() * 1000;
DWORD wait_result = ::WaitForSingleObject(m_write_overlapped.hEvent, timeout);
if (wait_result != WAIT_OBJECT_0) {
// The operation probably failed. However, if it timed out, we need to
// cancel the I/O. Between the time we returned from WaitForSingleObject
// and the time we call CancelIoEx, the operation may complete. If that
// hapens, CancelIoEx will fail and return ERROR_NOT_FOUND. If that
// happens, the original operation should be considered to have been
// successful.
bool failed = true;
DWORD failure_error = ::GetLastError();
if (wait_result == WAIT_TIMEOUT) {
BOOL cancel_result = CancelIoEx(m_write, &m_write_overlapped);
if (!cancel_result && GetLastError() == ERROR_NOT_FOUND)
failed = false;
}
if (failed)
return Status(failure_error, eErrorTypeWin32);
}

// Now we call GetOverlappedResult setting bWait to false, since we've
// already waited as long as we're willing to.
if (!GetOverlappedResult(m_write, &m_write_overlapped, &sys_bytes_write,
FALSE))
return Status(::GetLastError(), eErrorTypeWin32);

bytes_written = sys_bytes_write;
return Status();
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,40 @@ GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(
GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() =
default;

void GDBRemoteCommunicationServerPlatform::Proc(
const lldb_private::Args &args) {
if (!IsConnected())
return;

if (args.GetArgumentCount() > 0) {
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
std::optional<uint16_t> port;
std::string socket_name;
Status error = LaunchGDBServer(args,
"", // hostname
pid, port, socket_name);
if (error.Success())
SetPendingGdbServer(pid, *port, socket_name);
}

bool interrupt = false;
bool done = false;
Status error;
while (!interrupt && !done) {
if (GetPacketAndSendResponse(std::nullopt, error, interrupt, done) !=
GDBRemoteCommunication::PacketResult::Success)
break;
}

if (error.Fail()) {
Log *log = GetLog(LLDBLog::Platform);
LLDB_LOGF(log,
"GDBRemoteCommunicationServerPlatform::%s() "
"GetPacketAndSendResponse: %s",
__FUNCTION__, error.AsCString());
}
}

Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
const lldb_private::Args &args, std::string hostname, lldb::pid_t &pid,
std::optional<uint16_t> &port, std::string &socket_name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class GDBRemoteCommunicationServerPlatform

void SetPortOffset(uint16_t port_offset);

void SetInferiorArguments(const lldb_private::Args &args);
void Proc(const lldb_private::Args &args);

// Set port if you want to use a specific port number.
// Otherwise port will be set to the port that was chosen for you.
Expand Down
2 changes: 2 additions & 0 deletions lldb/tools/lldb-server/LLDBServerUtilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ class TestLogHandler : public LogHandler {
: m_stream_sp(stream_sp) {}

void Emit(llvm::StringRef message) override {
std::lock_guard<std::mutex> guard(m_mutex);
(*m_stream_sp) << message;
m_stream_sp->flush();
}

private:
std::mutex m_mutex;
std::shared_ptr<raw_ostream> m_stream_sp;
};

Expand Down
Loading

0 comments on commit 526708c

Please sign in to comment.