[Lldb-commits] [lldb] b42a213 - [lldb][windows] drain the ConPTY on process exit (#196371)
via lldb-commits
lldb-commits at lists.llvm.org
Fri May 8 08:40:58 PDT 2026
Author: Charles Zablit
Date: 2026-05-08T16:40:53+01:00
New Revision: b42a2131f2110bf09fc544536af2918c4a6f2429
URL: https://github.com/llvm/llvm-project/commit/b42a2131f2110bf09fc544536af2918c4a6f2429
DIFF: https://github.com/llvm/llvm-project/commit/b42a2131f2110bf09fc544536af2918c4a6f2429.diff
LOG: [lldb][windows] drain the ConPTY on process exit (#196371)
Added:
Modified:
lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
Removed:
################################################################################
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
index 28b5554069c90..eb1c4acc0f2bb 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
@@ -655,6 +655,7 @@ void ProcessWindows::OnExitProcess(uint32_t exit_code) {
LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code);
if (m_pty) {
+ DrainProcessStdout();
m_pty->SetStopping(true);
m_pty->Close();
m_stdio_communication.InterruptRead();
@@ -675,6 +676,32 @@ void ProcessWindows::OnExitProcess(uint32_t exit_code) {
ProcessDebugger::OnExitProcess(exit_code);
}
+void ProcessWindows::DrainProcessStdout() {
+ if (!m_stdio_communication.ReadThreadIsRunning())
+ return;
+ m_stdio_communication.SynchronizeWithReadThread();
+ if (!m_pty || m_pty->GetMode() != PseudoConsole::Mode::ConPTY)
+ return;
+
+ HANDLE pipe = m_pty->GetSTDOUTHandle();
+ for (int consec_empty = 0; consec_empty < 3;) {
+ if (!m_stdio_communication.ReadThreadIsRunning())
+ break;
+ DWORD avail = 0;
+ // PeekNamedPipe is thread safe.
+ if (!::PeekNamedPipe(pipe, nullptr, 0, nullptr, &avail, nullptr))
+ break;
+ if (avail > 0) {
+ consec_empty = 0;
+ m_stdio_communication.SynchronizeWithReadThread();
+ } else {
+ ++consec_empty;
+ if (consec_empty < 3)
+ ::SleepEx(1, FALSE);
+ }
+ }
+}
+
void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
DebuggerThreadSP debugger = m_session_data->m_debugger;
Log *log = GetLog(WindowsLog::Process);
@@ -741,41 +768,10 @@ ProcessWindows::OnDebugException(bool first_chance,
return ExceptionResult::SendToApplication;
}
- // Drain any in-flight process output before announcing the stop. The I/O
- // reader thread and this debug-event thread run concurrently. Without
- // synchronization the eBroadcastBitStateChanged(Stopped) event can reach
- // the Debugger event thread before the preceding eBroadcastBitSTDOUT
- // events.
- auto drain_stdout = [this] {
- if (!m_stdio_communication.ReadThreadIsRunning())
- return;
- m_stdio_communication.SynchronizeWithReadThread();
- if (!m_pty || m_pty->GetMode() != PseudoConsole::Mode::ConPTY)
- return;
-
- HANDLE pipe = m_pty->GetSTDOUTHandle();
- for (int consec_empty = 0; consec_empty < 3;) {
- if (!m_stdio_communication.ReadThreadIsRunning())
- break;
- DWORD avail = 0;
- // PeekNamedPipe is thread safe.
- if (!::PeekNamedPipe(pipe, nullptr, 0, nullptr, &avail, nullptr))
- break;
- if (avail > 0) {
- consec_empty = 0;
- m_stdio_communication.SynchronizeWithReadThread();
- } else {
- ++consec_empty;
- if (consec_empty < 3)
- ::SleepEx(1, FALSE);
- }
- }
- };
-
if (!first_chance) {
// Not any second chance exception is an application crash by definition.
// It may be an expression evaluation crash.
- drain_stdout();
+ DrainProcessStdout();
SetPrivateState(eStateStopped);
}
@@ -796,12 +792,17 @@ ProcessWindows::OnDebugException(bool first_chance,
LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.",
record.GetExceptionAddress());
}
- drain_stdout();
+ // Drain any in-flight process output before announcing the stop. The I/O
+ // reader thread and this debug-event thread run concurrently. Without
+ // synchronization the eBroadcastBitStateChanged(Stopped) event can reach
+ // the Debugger event thread before the preceding eBroadcastBitSTDOUT
+ // events.
+ DrainProcessStdout();
SetPrivateState(eStateStopped);
break;
case EXCEPTION_SINGLE_STEP:
result = ExceptionResult::BreakInDebugger;
- drain_stdout();
+ DrainProcessStdout();
SetPrivateState(eStateStopped);
break;
default:
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
index 228619d0e3d5e..31cf498a16d50 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
@@ -108,6 +108,10 @@ class ProcessWindows : public Process, public ProcessDebugger {
void SetPseudoConsoleHandle() override;
protected:
+ /// Block until the stdio read thread has surfaced everything currently
+ /// buffered in the ConPTY/pipe to the process's STDOUT cache.
+ void DrainProcessStdout();
+
ProcessWindows(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp);
Status DoGetMemoryRegionInfo(lldb::addr_t vm_addr,
More information about the lldb-commits
mailing list