Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync ReadKeyProc thread with pipeline thread #3294

Merged
merged 4 commits into from
Apr 27, 2022

Conversation

SeeminglyScience
Copy link
Contributor

@SeeminglyScience SeeminglyScience commented Apr 27, 2022

PR Summary

Fix #3292

The pipeline thread was returning before the ReadKeyProc thread had finished processing the dummy input. This was occurring somewhat frequently when ReadLine was invoked multiple times in a row, surfacing a race condition.

With these changes, the pipeline thread will wait for dummy input to be received, dequeue the key, and continue with normal cancellation logic.

PR Checklist

  • PR has a meaningful title
    • Use the present tense and imperative mood when describing your changes
  • Summarized changes
  • Make sure you've added one or more new tests
  • Make sure you've tested these changes in terminals that PowerShell is commonly used in (i.e. conhost.exe, Windows Terminal, Visual Studio Code Integrated Terminal, etc.)
  • User-facing changes
    • Not Applicable
    • OR
    • Documentation needed at PowerShell-Docs
      • Doc Issue filed:
Microsoft Reviewers: Open in CodeFlow

The pipeline thread was returning before the ReadKeyProcThread had
finished processing the dummy input. This was occuring somewhat
frequently when ReadLine was invoked multiple times in a row creating a
race condition.

With these changes, the pipeline thread will wait for dummy input to be
received, dequeue the key, and continue with normal cancellation logic.
Copy link
Member

@andyleejordan andyleejordan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super freaking interesting. Can we setup a call with @daxian-dbw and step through this? I think you've found the threads racing, but damn, this is interesting.

@SeeminglyScience
Copy link
Contributor Author

Can we setup a call with @daxian-dbw and step through this?

Yeah definitely ❤️

Copy link
Member

@daxian-dbw daxian-dbw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SeeminglyScience Good work narrowing down the cause!
There may still be a race condition with this change. timeout case won't affect this change. Looking.

Copy link
Member

@daxian-dbw daxian-dbw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with a minor comment.

@andyleejordan
Copy link
Member

Also tested and verified, and this resolves the problem. We've (well, @SeeminglyScience really) narrowed down the "extra prompt" issue as well, and while related to what we've been debugging, the cause is separate (our DisconnectHandler is erroneously causing us to cancel the REPL, which then gets invoked again immediately).

@@ -877,7 +861,7 @@ private void DelayedOneTimeInitialize()
_readKeyWaitHandle = new AutoResetEvent(false);
_keyReadWaitHandle = new AutoResetEvent(false);
_closingWaitHandle = new ManualResetEvent(false);
_requestKeyWaitHandles = new WaitHandle[] {_keyReadWaitHandle, _closingWaitHandle, null};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ha, the questions I had earlier but hadn't written yet are now irrelevant. Yay!

@daxian-dbw
Copy link
Member

Would it make sense to use CancellationToken.None instead of the static _defaultCancellationToken now? I think the only place _defaultCancellationToken is used is in public static string ReadLine(Runspace runspace, EngineIntrinsics engineIntrinsics, bool? lastRunStatus).

@SeeminglyScience
Copy link
Contributor Author

Would it make sense to use CancellationToken.None instead of the static _defaultCancellationToken now? I think the only place _defaultCancellationToken is used is in public static string ReadLine(Runspace runspace, EngineIntrinsics engineIntrinsics, bool? lastRunStatus).

Oooo another good catch, yeah I think that would work fine now since IsCancellationRequested doesn't change when you do CancellationToken.None.WaitHandle.Set(). I'll get that changed

We can now use CancellationToken.None instead of creating a dummy
cancellation token because we use
`CancellationToken.IsCancellationRequested`.
Copy link
Member

@daxian-dbw daxian-dbw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@andyleejordan
Copy link
Member

Woo-hoo!

@SeeminglyScience SeeminglyScience deleted the sync-readkey-thread branch April 27, 2022 18:18
@ghost
Copy link

ghost commented Apr 27, 2022

🎉 v2.2.4-beta1 has been released which incorporates this pull request. 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Readline crashes with ThrowForEmptyQueue
3 participants