diff --git a/src/libraries/System.Console/src/System/ConsolePal.Windows.cs b/src/libraries/System.Console/src/System/ConsolePal.Windows.cs index ee25d844de866d..f51fed48b02630 100644 --- a/src/libraries/System.Console/src/System/ConsolePal.Windows.cs +++ b/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @@ -347,7 +347,7 @@ public static ConsoleKeyInfo ReadKey(bool intercept) while (true) { r = Interop.Kernel32.ReadConsoleInput(InputHandle, out ir, 1, out int numEventsRead); - if (!r || numEventsRead == 0) + if (!r) { // This will fail when stdin is redirected from a file or pipe. // We could theoretically call Console.Read here, but I @@ -355,6 +355,28 @@ public static ConsoleKeyInfo ReadKey(bool intercept) throw new InvalidOperationException(SR.InvalidOperation_ConsoleReadKeyOnFile); } + if (numEventsRead == 0) + { + // This can happen when there are multiple console-attached + // processes waiting for input, and another one is terminated + // while we are waiting for input. + // + // (This is "almost certainly" a bug, but behavior has been + // this way for a long time, so we should handle it: + // https://github.com/microsoft/terminal/issues/15859) + // + // (It's a rare case to have multiple console-attached + // processes waiting for input, but it can happen sometimes, + // such as when ctrl+c'ing a build process that is spawning + // tons of child processes--sometimes, due to the order in + // which processes exit, a managed shell process (like pwsh) + // might get back to the prompt and start trying to read input + // while there are still child processes getting cleaned up.) + // + // In this case, we just need to retry the read. + continue; + } + ushort keyCode = ir.keyEvent.wVirtualKeyCode; // First check for non-keyboard events & discard them. Generally we tap into only KeyDown events and ignore the KeyUp events