Console: toggle terminal echo based on presence of interactive child processes#35621
Console: toggle terminal echo based on presence of interactive child processes#35621stephentoub merged 17 commits intodotnet:masterfrom
Conversation
…processes .NET applications echo characters during a Console.Read. By default, Unix terminals echo characters as the user is typing them. When a .NET Core application launches an interactive application (e.g. 'vi') that application expects to find the terminal in an echoing state. To make both work, corefx was disabling echo during Console.Read operations, and turning it back on when the read is done. This changes to echoing while there are interactive applications and not echoing when there are none. This means we no longer need to toggle echo off/on for each Console.Read. And the terminal will no longer echo when there is no Console.Read going on.
|
No need to review this one yet, I'll make some more changes next week. |
|
Thanks, @tmds. |
|
This is ready for review. |
|
@wtgodbe @stephentoub @danmosemsft can you please do a review of this PR. I'm going to test some scenarios on my machine looking for things that break. |
|
Scenario 1 Console.ReadKey();pre-PR syscalls: post-PR syscalls: Scenario 2 Console.ReadLine();
Process.Start("nano").WaitForExit();
Console.ReadLine();For the user, this works the same pre and post PR. The echoing is not enabled during the read. Echoing is enabled while nano is running. Echoing is disabled again when nano terminated. Scenario 3 Console.ReadLine();
Process.Start(new ProcessStartInfo { FileName = "sleep", Arguments = "10", RedirectStandardInput = true}).WaitForExit();
System.Console.WriteLine("sleep terminated");
Console.ReadLine();Pre PR, the terminal echoed characters during the sleep process, and printed those characters again for the Console.ReadLine. Post PR, the terminal no longer echos during the sleep process and characters are printed on the Console.ReadLine. Scenario 4 Process.Start("sleep", "0").WaitForExit();This is started in background. The dotnet process finishes successfully (i.e. it is not stopped on SIGTTOU). This relies on the |
|
CC @bradygaster, might be worth testing your scenarios with this change to see if things improve |
wtgodbe
left a comment
There was a problem hiding this comment.
Looks good overall, just a few places where some additional comments wouldn't hurt. Thanks!
|
Thanks for reviewing @wtgodbe , I've added some additional comments. |
stephentoub
left a comment
There was a problem hiding this comment.
Thanks for working on this.
|
@stephentoub I addressed the PR feedback. I left open the more important comments for you to resolve or provide additional feedback. |
|
Thanks, @tmds. I'll review again in the morning. |
|
@wtgodbe, to get some extra eyes on this, could you try out writing a variety of apps that use console and process to do various things, and see if you see any oddities? Maybe try running various console-based tools, running dotnet in various ways, searching around for interesting examples of folks using console and trying them out? |
|
Sure, I can try out a few things later this week. |
|
Thanks, @wtgodbe. |
Thanks for working through all those scenarios. What about other cases like:
Or similarly:
|
|
The assumption made to minimize re-configuring terminal is: Only one process is using the terminal at the same time interactively (that is: echo what gets typed to the screen). A bit unfortunately for this is that by default, When we see a This scheme fails when the assumption is violated, which is: there is an interactive process (e.g. |
|
So in practice, this means that:
|
|
Thanks, @tmds. Let's get this in and then hopefully we'll get enough validation of it to feel confident in the approach. Thanks for working on it. |
|
Getting some real-life usage will be the best validation this is working as intended. Thank you for thorough review @stephentoub ! |
…ut was used by the child (#40563) * Process: Unix: ensure we reconfigure the terminal for Console usage if only one of stdin/stdout was used by the child. Console: Unix: Fix cache check for VTIME (read timeout). Fixes https://github.com/dotnet/corefx/issues/40557 * Also consider not redirecting stderr as terminal usage
…processes (dotnet/corefx#35621) * Console: toggle terminal echo based on presence of interactive child processes .NET applications echo characters during a Console.Read. By default, Unix terminals echo characters as the user is typing them. When a .NET Core application launches an interactive application (e.g. 'vi') that application expects to find the terminal in an echoing state. To make both work, corefx was disabling echo during Console.Read operations, and turning it back on when the read is done. This changes to echoing while there are interactive applications and not echoing when there are none. This means we no longer need to toggle echo off/on for each Console.Read. And the terminal will no longer echo when there is no Console.Read going on. * Make some tcsetattr operations non-blocking * Fix order between changing console settings and SetExited * Fix unbalanced lock/unlocks * Cache notty * Prefer configuring the terminal for Console over child processes * Update comments * Rename some 'console' to 'terminal' * Only decrement when child is using terminal * Rename ConfigureTerminalForConsole back to In/UninitializeConsoleBefore/AfterRead * Move some code to original place * Add some extra comments * PR feedback * typo Commit migrated from dotnet/corefx@007571b
.NET applications echo characters during a Console.Read. By default,
Unix terminals echo characters as the user is typing them.
When a .NET Core application launches an interactive application (e.g. 'vi')
that application expects to find the terminal in an echoing state.
To make both work, corefx was disabling echo during Console.Read operations,
and turning it back on when the read is done.
This changes to echoing while there are interactive applications and not echoing
when there are none.
This means we no longer need to toggle echo off/on for each Console.Read.
And the terminal will no longer echo when there is no Console.Read going on.