Skip to content

Commit 396b9a0

Browse files
committed
[lldb] Updated lldb-server to spawn the child process and share socket on Windows
`lldb-server --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 396b9a0

File tree

6 files changed

+404
-81
lines changed

6 files changed

+404
-81
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

+89-39
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,54 +293,94 @@ 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)
287-
return Status(::GetLastError(), eErrorTypeWin32);
288-
289-
DWORD timeout = (duration == std::chrono::microseconds::zero())
290-
? INFINITE
291-
: duration.count() * 1000;
292-
DWORD wait_result = ::WaitForSingleObject(m_read_overlapped.hEvent, timeout);
293-
if (wait_result != WAIT_OBJECT_0) {
294-
// The operation probably failed. However, if it timed out, we need to
295-
// cancel the I/O. Between the time we returned from WaitForSingleObject
296-
// and the time we call CancelIoEx, the operation may complete. If that
297-
// hapens, CancelIoEx will fail and return ERROR_NOT_FOUND. If that
298-
// happens, the original operation should be considered to have been
299-
// successful.
300-
bool failed = true;
301-
DWORD failure_error = ::GetLastError();
302-
if (wait_result == WAIT_TIMEOUT) {
303-
BOOL cancel_result = CancelIoEx(m_read, &m_read_overlapped);
304-
if (!cancel_result && GetLastError() == ERROR_NOT_FOUND)
305-
failed = false;
296+
if (!result) {
297+
if (GetLastError() != ERROR_IO_PENDING)
298+
return Status(::GetLastError(), eErrorTypeWin32);
299+
else {
300+
DWORD timeout = (duration == std::chrono::microseconds::zero())
301+
? INFINITE
302+
: duration.count() * 1000;
303+
DWORD wait_result =
304+
::WaitForSingleObject(m_read_overlapped.hEvent, timeout);
305+
if (wait_result != WAIT_OBJECT_0) {
306+
// The operation probably failed. However, if it timed out, we need to
307+
// cancel the I/O. Between the time we returned from WaitForSingleObject
308+
// and the time we call CancelIoEx, the operation may complete. If that
309+
// hapens, CancelIoEx will fail and return ERROR_NOT_FOUND. If that
310+
// happens, the original operation should be considered to have been
311+
// successful.
312+
bool failed = true;
313+
DWORD failure_error = ::GetLastError();
314+
if (wait_result == WAIT_TIMEOUT) {
315+
BOOL cancel_result = CancelIoEx(m_read, &m_read_overlapped);
316+
if (!cancel_result && GetLastError() == ERROR_NOT_FOUND)
317+
failed = false;
318+
}
319+
if (failed)
320+
return Status(failure_error, eErrorTypeWin32);
321+
}
322+
323+
// Now we call GetOverlappedResult setting bWait to false, since we've
324+
// already waited as long as we're willing to.
325+
if (!GetOverlappedResult(m_read, &m_read_overlapped, &sys_bytes_read,
326+
FALSE))
327+
return Status(::GetLastError(), eErrorTypeWin32);
306328
}
307-
if (failed)
308-
return Status(failure_error, eErrorTypeWin32);
309329
}
310-
311-
// Now we call GetOverlappedResult setting bWait to false, since we've
312-
// already waited as long as we're willing to.
313-
if (!GetOverlappedResult(m_read, &m_read_overlapped, &sys_bytes_read, FALSE))
314-
return Status(::GetLastError(), eErrorTypeWin32);
315-
316330
bytes_read = sys_bytes_read;
317331
return Status();
318332
}
319333

320-
Status PipeWindows::Write(const void *buf, size_t num_bytes,
321-
size_t &bytes_written) {
334+
Status PipeWindows::WriteWithTimeout(const void *buf, size_t size,
335+
const std::chrono::microseconds &duration,
336+
size_t &bytes_written) {
322337
if (!CanWrite())
323338
return Status(ERROR_INVALID_HANDLE, eErrorTypeWin32);
324339

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)
329-
return Status(::GetLastError(), eErrorTypeWin32);
340+
bytes_written = 0;
341+
DWORD sys_bytes_write = size;
342+
BOOL result = ::WriteFile(m_write, buf, sys_bytes_write, &sys_bytes_write,
343+
&m_write_overlapped);
344+
if (!result) {
345+
if (GetLastError() != ERROR_IO_PENDING)
346+
return Status(::GetLastError(), eErrorTypeWin32);
347+
else {
348+
DWORD timeout = (duration == std::chrono::microseconds::zero())
349+
? INFINITE
350+
: duration.count() * 1000;
351+
DWORD wait_result =
352+
::WaitForSingleObject(m_write_overlapped.hEvent, timeout);
353+
if (wait_result != WAIT_OBJECT_0) {
354+
// The operation probably failed. However, if it timed out, we need to
355+
// cancel the I/O. Between the time we returned from WaitForSingleObject
356+
// and the time we call CancelIoEx, the operation may complete. If that
357+
// hapens, CancelIoEx will fail and return ERROR_NOT_FOUND. If that
358+
// happens, the original operation should be considered to have been
359+
// successful.
360+
bool failed = true;
361+
DWORD failure_error = ::GetLastError();
362+
if (wait_result == WAIT_TIMEOUT) {
363+
BOOL cancel_result = CancelIoEx(m_write, &m_write_overlapped);
364+
if (!cancel_result && GetLastError() == ERROR_NOT_FOUND)
365+
failed = false;
366+
}
367+
if (failed)
368+
return Status(failure_error, eErrorTypeWin32);
369+
}
370+
371+
// Now we call GetOverlappedResult setting bWait to false, since we've
372+
// already waited as long as we're willing to.
373+
if (!GetOverlappedResult(m_write, &m_write_overlapped, &sys_bytes_write,
374+
FALSE))
375+
return Status(::GetLastError(), eErrorTypeWin32);
376+
}
377+
}
330378

331-
BOOL result = GetOverlappedResult(m_write, &m_write_overlapped,
332-
&sys_bytes_written, TRUE);
333-
if (!result)
334-
return Status(::GetLastError(), eErrorTypeWin32);
379+
bytes_written = sys_bytes_write;
335380
return Status();
336381
}
382+
383+
Status PipeWindows::Write(const void *buf, size_t size, size_t &bytes_written) {
384+
return WriteWithTimeout(buf, size, std::chrono::microseconds::zero(),
385+
bytes_written);
386+
}

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)