================
@@ -954,4 +945,162 @@ Status ProcessWindows::DisableWatchpoint(WatchpointSP
wp_sp, bool notify) {
return error;
}
+
+class IOHandlerProcessSTDIOWindows : public IOHandler {
+public:
+ IOHandlerProcessSTDIOWindows(Process *process, HANDLE conpty_input)
+ : IOHandler(process->GetTarget().GetDebugger(),
+ IOHandler::Type::ProcessIO),
+ m_process(process),
+ m_read_file(GetInputFD(), File::eOpenOptionReadOnly, false),
+ m_write_file(conpty_input) {
+ m_pipe.CreateNew();
+ }
+
+ ~IOHandlerProcessSTDIOWindows() override = default;
+
+ void SetIsRunning(bool running) {
+ std::lock_guard<std::mutex> guard(m_mutex);
+ SetIsDone(!running);
+ m_is_running = running;
+ }
+
+ void Run() override {
+ if (!m_read_file.IsValid() || m_write_file == INVALID_HANDLE_VALUE ||
+ !m_pipe.CanRead() || !m_pipe.CanWrite()) {
+ SetIsDone(true);
+ return;
+ }
+
+ SetIsDone(false);
+ SetIsRunning(true);
+
+ HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
+ HANDLE hInterrupt = (HANDLE)_get_osfhandle(m_pipe.GetReadFileDescriptor());
+ HANDLE waitHandles[2] = {hStdin, hInterrupt};
+
+ while (true) {
+ {
+ std::lock_guard<std::mutex> guard(m_mutex);
+ if (GetIsDone())
+ goto exit_loop;
+ }
+
+ DWORD result = WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE);
+ switch (result) {
+ case WAIT_FAILED:
+ goto exit_loop;
+ case WAIT_OBJECT_0: {
+ char ch = 0;
+ DWORD read = 0;
+ if (!ReadFile(hStdin, &ch, 1, &read, nullptr) || read != 1)
+ goto exit_loop;
+
+ DWORD written = 0;
+ if (!WriteFile(m_write_file, &ch, 1, &written, nullptr) || written !=
1)
+ goto exit_loop;
+ break;
+ }
+ case WAIT_OBJECT_0 + 1: {
+ char ch = 0;
+ DWORD read = 0;
+ if (!ReadFile(hInterrupt, &ch, 1, &read, nullptr) || read != 1)
+ goto exit_loop;
+
+ if (ch == 'q')
+ goto exit_loop;
+ if (ch == 'i' && StateIsRunningState(m_process->GetState()))
+ m_process->SendAsyncInterrupt();
+ break;
+ }
+ default:
+ goto exit_loop;
+ }
+ }
+
+ exit_loop:;
+ SetIsRunning(false);
+ }
+
+ void Cancel() override {
+ std::lock_guard<std::mutex> guard(m_mutex);
+ SetIsDone(true);
+ // Only write to our pipe to cancel if we are in
+ // IOHandlerProcessSTDIO::Run(). We can end up with a python command that
+ // is being run from the command interpreter:
+ //
+ // (lldb) step_process_thousands_of_times
+ //
+ // In this case the command interpreter will be in the middle of handling
+ // the command and if the process pushes and pops the IOHandler thousands
+ // of times, we can end up writing to m_pipe without ever consuming the
+ // bytes from the pipe in IOHandlerProcessSTDIO::Run() and end up
+ // deadlocking when the pipe gets fed up and blocks until data is consumed.
+ if (m_is_running) {
+ char ch = 'q'; // Send 'q' for quit
+ if (llvm::Error err = m_pipe.Write(&ch, 1).takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Process), std::move(err),
+ "Pipe write failed: {0}");
+ }
+ }
+ }
+
+ bool Interrupt() override {
+ // Do only things that are safe to do in an interrupt context (like in a
----------------
compnerd wrote:
I think it is better to let go of having the classes match, lets do what is
needed on the platform.
https://github.com/llvm/llvm-project/pull/168729
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits