Skip to content

Commit 526708c

Browse files
committed
[lldb] Updated lldb-server to spawn the child process and share socket 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 #90923, fixes #56346. This is the part 1 of the replacement of #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 #97537.
1 parent c35c4c7 commit 526708c

File tree

6 files changed

+375
-50
lines changed

6 files changed

+375
-50
lines changed

lldb/include/lldb/Host/windows/PipeWindows.h

+3
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ class PipeWindows : public PipeBase {
6161
Status Delete(llvm::StringRef name) override;
6262

6363
Status Write(const void *buf, size_t size, size_t &bytes_written) override;
64+
Status WriteWithTimeout(const void *buf, size_t size,
65+
const std::chrono::microseconds &timeout,
66+
size_t &bytes_written);
6467
Status ReadWithTimeout(void *buf, size_t size,
6568
const std::chrono::microseconds &timeout,
6669
size_t &bytes_read) override;

lldb/source/Host/windows/PipeWindows.cpp

+61-8
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ PipeWindows::PipeWindows(pipe_t read, pipe_t write)
5858
}
5959

6060
ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
61+
m_read_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr);
62+
6163
ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
64+
m_write_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr);
6265
}
6366

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

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

8185
return Status();
8286
}
@@ -202,6 +206,7 @@ Status PipeWindows::OpenNamedPipe(llvm::StringRef name,
202206
m_write_fd = _open_osfhandle((intptr_t)m_write, _O_WRONLY);
203207

204208
ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
209+
m_write_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr);
205210
}
206211

207212
return Status();
@@ -228,6 +233,8 @@ int PipeWindows::ReleaseWriteFileDescriptor() {
228233
return PipeWindows::kInvalidDescriptor;
229234
int result = m_write_fd;
230235
m_write_fd = PipeWindows::kInvalidDescriptor;
236+
if (m_write_overlapped.hEvent)
237+
::CloseHandle(m_write_overlapped.hEvent);
231238
m_write = INVALID_HANDLE_VALUE;
232239
ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
233240
return result;
@@ -250,6 +257,9 @@ void PipeWindows::CloseWriteFileDescriptor() {
250257
if (!CanWrite())
251258
return;
252259

260+
if (m_write_overlapped.hEvent)
261+
::CloseHandle(m_write_overlapped.hEvent);
262+
253263
_close(m_write_fd);
254264
m_write = INVALID_HANDLE_VALUE;
255265
m_write_fd = PipeWindows::kInvalidDescriptor;
@@ -283,7 +293,12 @@ Status PipeWindows::ReadWithTimeout(void *buf, size_t size,
283293
DWORD sys_bytes_read = size;
284294
BOOL result = ::ReadFile(m_read, buf, sys_bytes_read, &sys_bytes_read,
285295
&m_read_overlapped);
286-
if (!result && GetLastError() != ERROR_IO_PENDING)
296+
if (result) {
297+
bytes_read = sys_bytes_read;
298+
return Status();
299+
}
300+
301+
if (GetLastError() != ERROR_IO_PENDING)
287302
return Status(::GetLastError(), eErrorTypeWin32);
288303

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

320335
Status PipeWindows::Write(const void *buf, size_t num_bytes,
321336
size_t &bytes_written) {
337+
return WriteWithTimeout(buf, num_bytes, std::chrono::microseconds::zero(),
338+
bytes_written);
339+
}
340+
341+
Status PipeWindows::WriteWithTimeout(const void *buf, size_t size,
342+
const std::chrono::microseconds &duration,
343+
size_t &bytes_written) {
322344
if (!CanWrite())
323345
return Status(ERROR_INVALID_HANDLE, eErrorTypeWin32);
324346

325-
DWORD sys_bytes_written = 0;
326-
BOOL write_result = ::WriteFile(m_write, buf, num_bytes, &sys_bytes_written,
327-
&m_write_overlapped);
328-
if (!write_result && GetLastError() != ERROR_IO_PENDING)
347+
bytes_written = 0;
348+
DWORD sys_bytes_write = size;
349+
BOOL result = ::WriteFile(m_write, buf, sys_bytes_write, &sys_bytes_write,
350+
&m_write_overlapped);
351+
if (result) {
352+
bytes_written = sys_bytes_write;
353+
return Status();
354+
}
355+
356+
if (GetLastError() != ERROR_IO_PENDING)
329357
return Status(::GetLastError(), eErrorTypeWin32);
330358

331-
BOOL result = GetOverlappedResult(m_write, &m_write_overlapped,
332-
&sys_bytes_written, TRUE);
333-
if (!result)
359+
DWORD timeout = (duration == std::chrono::microseconds::zero())
360+
? INFINITE
361+
: duration.count() * 1000;
362+
DWORD wait_result = ::WaitForSingleObject(m_write_overlapped.hEvent, timeout);
363+
if (wait_result != WAIT_OBJECT_0) {
364+
// The operation probably failed. However, if it timed out, we need to
365+
// cancel the I/O. Between the time we returned from WaitForSingleObject
366+
// and the time we call CancelIoEx, the operation may complete. If that
367+
// hapens, CancelIoEx will fail and return ERROR_NOT_FOUND. If that
368+
// happens, the original operation should be considered to have been
369+
// successful.
370+
bool failed = true;
371+
DWORD failure_error = ::GetLastError();
372+
if (wait_result == WAIT_TIMEOUT) {
373+
BOOL cancel_result = CancelIoEx(m_write, &m_write_overlapped);
374+
if (!cancel_result && GetLastError() == ERROR_NOT_FOUND)
375+
failed = false;
376+
}
377+
if (failed)
378+
return Status(failure_error, eErrorTypeWin32);
379+
}
380+
381+
// Now we call GetOverlappedResult setting bWait to false, since we've
382+
// already waited as long as we're willing to.
383+
if (!GetOverlappedResult(m_write, &m_write_overlapped, &sys_bytes_write,
384+
FALSE))
334385
return Status(::GetLastError(), eErrorTypeWin32);
386+
387+
bytes_written = sys_bytes_write;
335388
return Status();
336389
}

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp

+34
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,40 @@ GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(
159159
GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() =
160160
default;
161161

162+
void GDBRemoteCommunicationServerPlatform::Proc(
163+
const lldb_private::Args &args) {
164+
if (!IsConnected())
165+
return;
166+
167+
if (args.GetArgumentCount() > 0) {
168+
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
169+
std::optional<uint16_t> port;
170+
std::string socket_name;
171+
Status error = LaunchGDBServer(args,
172+
"", // hostname
173+
pid, port, socket_name);
174+
if (error.Success())
175+
SetPendingGdbServer(pid, *port, socket_name);
176+
}
177+
178+
bool interrupt = false;
179+
bool done = false;
180+
Status error;
181+
while (!interrupt && !done) {
182+
if (GetPacketAndSendResponse(std::nullopt, error, interrupt, done) !=
183+
GDBRemoteCommunication::PacketResult::Success)
184+
break;
185+
}
186+
187+
if (error.Fail()) {
188+
Log *log = GetLog(LLDBLog::Platform);
189+
LLDB_LOGF(log,
190+
"GDBRemoteCommunicationServerPlatform::%s() "
191+
"GetPacketAndSendResponse: %s",
192+
__FUNCTION__, error.AsCString());
193+
}
194+
}
195+
162196
Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
163197
const lldb_private::Args &args, std::string hostname, lldb::pid_t &pid,
164198
std::optional<uint16_t> &port, std::string &socket_name) {

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class GDBRemoteCommunicationServerPlatform
8585

8686
void SetPortOffset(uint16_t port_offset);
8787

88-
void SetInferiorArguments(const lldb_private::Args &args);
88+
void Proc(const lldb_private::Args &args);
8989

9090
// Set port if you want to use a specific port number.
9191
// Otherwise port will be set to the port that was chosen for you.

lldb/tools/lldb-server/LLDBServerUtilities.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@ class TestLogHandler : public LogHandler {
2727
: m_stream_sp(stream_sp) {}
2828

2929
void Emit(llvm::StringRef message) override {
30+
std::lock_guard<std::mutex> guard(m_mutex);
3031
(*m_stream_sp) << message;
3132
m_stream_sp->flush();
3233
}
3334

3435
private:
36+
std::mutex m_mutex;
3537
std::shared_ptr<raw_ostream> m_stream_sp;
3638
};
3739

0 commit comments

Comments
 (0)