Index: lldb/tools/debugserver/source/DNB.h =================================================================== --- lldb/tools/debugserver/source/DNB.h +++ lldb/tools/debugserver/source/DNB.h @@ -235,4 +235,7 @@ bool DNBGetOSVersionNumbers(uint64_t *major, uint64_t *minor, uint64_t *patch); /// \return the iOSSupportVersion of the host OS. std::string DNBGetMacCatalystVersionString(); + +nub_bool_t DNBStopSTDIOThread(nub_process_t pid); + #endif Index: lldb/tools/debugserver/source/DNB.cpp =================================================================== --- lldb/tools/debugserver/source/DNB.cpp +++ lldb/tools/debugserver/source/DNB.cpp @@ -1732,3 +1732,12 @@ } return false; } + +nub_bool_t DNBStopSTDIOThread(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + procSP->StopSTDIOThread(); + return true; + } + return false; +} Index: lldb/tools/debugserver/source/MacOSX/MachProcess.h =================================================================== --- lldb/tools/debugserver/source/MacOSX/MachProcess.h +++ lldb/tools/debugserver/source/MacOSX/MachProcess.h @@ -187,6 +187,7 @@ // Exception thread functions bool StartSTDIOThread(); + void StopSTDIOThread(); static void *STDIOThread(void *arg); void ExceptionMessageReceived(const MachException::Message &exceptionMessage); task_t ExceptionMessageBundleComplete(); @@ -299,6 +300,9 @@ int GetStdinFileDescriptor() const { return m_child_stdin; } int GetStdoutFileDescriptor() const { return m_child_stdout; } int GetStderrFileDescriptor() const { return m_child_stderr; } + int GetStdoutThreadInterruptFileDescriptor() const { + return m_stdio_thread_interrupt[0]; + } void AppendSTDOUT(char *s, size_t len); size_t GetAvailableSTDOUT(char *buf, size_t buf_size); size_t GetAvailableSTDERR(char *buf, size_t buf_size); @@ -368,6 +372,9 @@ uint32_t m_stop_count; // A count of many times have we stopped pthread_t m_stdio_thread; // Thread ID for the thread that watches for child // process stdio + int m_stdio_thread_interrupt[2]; // File descriptor pair to notify STDIO + // thread that it should stop waiting for + // input and finish. PThreadMutex m_stdio_mutex; // Multithreaded protection for stdio std::string m_stdout_data; Index: lldb/tools/debugserver/source/MacOSX/MachProcess.mm =================================================================== --- lldb/tools/debugserver/source/MacOSX/MachProcess.mm +++ lldb/tools/debugserver/source/MacOSX/MachProcess.mm @@ -1316,15 +1316,29 @@ } m_activities.Clear(); StopProfileThread(); + StopSTDIOThread(); } bool MachProcess::StartSTDIOThread() { DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( )", __FUNCTION__); + if (pipe(m_stdio_thread_interrupt) == -1) { + return false; + } // Create the thread that watches for the child STDIO return ::pthread_create(&m_stdio_thread, NULL, MachProcess::STDIOThread, this) == 0; } +void MachProcess::StopSTDIOThread() { + if (m_stdio_thread) { + ::write(m_stdio_thread_interrupt[1], "", 1); + pthread_join(m_stdio_thread, nullptr); + m_stdio_thread = 0; + close(m_stdio_thread_interrupt[0]); + close(m_stdio_thread_interrupt[1]); + } +} + void MachProcess::SetEnableAsyncProfiling(bool enable, uint64_t interval_usec, DNBProfileDataScanType scan_type) { m_profile_enabled = enable; @@ -2388,6 +2402,8 @@ DNBError err; int stdout_fd = proc->GetStdoutFileDescriptor(); int stderr_fd = proc->GetStderrFileDescriptor(); + int interrupt_fd = proc->GetStdoutThreadInterruptFileDescriptor(); + if (stdout_fd == stderr_fd) stderr_fd = -1; @@ -2400,7 +2416,10 @@ FD_SET(stdout_fd, &read_fds); if (stderr_fd >= 0) FD_SET(stderr_fd, &read_fds); - int nfds = std::max(stdout_fd, stderr_fd) + 1; + + FD_SET(interrupt_fd, &read_fds); + + int nfds = std::max({stdout_fd, stderr_fd, interrupt_fd}) + 1; int num_set_fds = select(nfds, &read_fds, NULL, NULL, NULL); DNBLogThreadedIf(LOG_PROCESS, @@ -2478,6 +2497,9 @@ } while (bytes_read > 0); } + if (FD_ISSET(interrupt_fd, &read_fds)) { + break; + } } } DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (%p): thread exiting...", Index: lldb/tools/debugserver/source/debugserver.cpp =================================================================== --- lldb/tools/debugserver/source/debugserver.cpp +++ lldb/tools/debugserver/source/debugserver.cpp @@ -533,6 +533,13 @@ ctx.EventsAsString(set_events, set_events_str)); if (set_events) { + + if (set_events & RNBContext::event_proc_thread_exiting && + remote->Context().HasValidProcessID()) { + // Make sure we have all the STDIO read from the process before + // flushing. + DNBStopSTDIOThread(remote->Context().ProcessID()); + } if ((set_events & RNBContext::event_proc_thread_exiting) || (set_events & RNBContext::event_proc_stdio_available)) { remote->FlushSTDIO();