https://github.com/charles-zablit created https://github.com/llvm/llvm-project/pull/196371
https://github.com/llvm/llvm-project/pull/194422 added `drain_stdout` to drain the conpty after the process is interrupted. This patch takes this further by also draining the stdout when the process exits. This fixes the stdout not being printed if the process prints between a breakpoint hit and its end (or does not hit a breakpoint at all). >From 7f34a5d7be06a9b0e3fc77f144a189bbd01b33a3 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Thu, 7 May 2026 18:06:19 +0100 Subject: [PATCH] [lldb][windows] drain the ConPTY on process exit --- .../Process/Windows/Common/ProcessWindows.cpp | 59 ++++++++++--------- .../Process/Windows/Common/ProcessWindows.h | 4 ++ 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp index 28b5554069c90..9dd49a9e7a1ba 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); @@ -746,36 +773,10 @@ ProcessWindows::OnDebugException(bool first_chance, // 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 +797,12 @@ ProcessWindows::OnDebugException(bool first_chance, LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.", record.GetExceptionAddress()); } - drain_stdout(); + 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, _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
