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

Start thread pool worker threads in the default execution context #46181

Merged
merged 10 commits into from
Dec 19, 2020

Conversation

kouvel
Copy link
Member

@kouvel kouvel commented Dec 17, 2020

The execution context transfers to new threads, and this creates an extra stack frame on the thread and may cause AsyncLocal value change notifications to be sent unnecessarily. Switched to the default context before creating a worker thread.

The execution context transfers to new threads, and this creates an extra stack frame on the thread and may cause AsyncLocal value change notifications to be sent unnecessarily. Switched to the default context before creating a worker thread.
@kouvel kouvel added this to the 6.0.0 milestone Dec 17, 2020
@kouvel kouvel requested a review from janvorli December 17, 2020 03:51
@kouvel kouvel self-assigned this Dec 17, 2020
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@kouvel kouvel closed this Dec 17, 2020
@kouvel kouvel reopened this Dec 17, 2020
@danmoseley
Copy link
Member

Is it possible to test this (even if it's not a certain result)

@kouvel
Copy link
Member Author

kouvel commented Dec 17, 2020

The Dispatch method that kicks off work items force-clears the EC before work items are run, so it wouldn't be user-visible that way. It may be possible through AsyncLocal value-change notifications, but technically it's not incorrect to send those notifications (i.e. not necessarily a bug, but it may be a behavior difference from the native thread pool). I'll try to test with the notifications.

@kouvel
Copy link
Member Author

kouvel commented Dec 17, 2020

Actually it may be a bug that this is fixing. AsyncLocal value change notifications can have side-effects like impersonation, the force-clearing that Dispatch does in the beginning does would not undo that since it doesn't send value-change notifications (the AsyncLocal value would be correct, but the side-effect would not have been undone.

@jkotas
Copy link
Member

jkotas commented Dec 17, 2020

Do we have tests that validate that new threads inherit execution context of the parent thread? I do not see the code that captures the execution context of parent thread in Mono, and no bugs on it either.

@kouvel kouvel added the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label Dec 17, 2020
Copy link
Member

@janvorli janvorli left a comment

Choose a reason for hiding this comment

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

LGTM, thank you!

@kouvel
Copy link
Member Author

kouvel commented Dec 17, 2020

Do we have tests that validate that new threads inherit execution context of the parent thread?

Doesn't look like it. I added a test now, but will need to check the implementation in Mono.

@kouvel
Copy link
Member Author

kouvel commented Dec 17, 2020

The EC flowing into thread pool threads did turn out to be a bug with visible unintended consequences, added a test for it. Also fixed the same thing for gate thread and wait thread creation.

@davidfowl
Copy link
Member

Can't we add a no-capture flag to the thread constructor to avoid capturing the execution context?

@kouvel
Copy link
Member Author

kouvel commented Dec 17, 2020

Yea that's an option, it's the Start methods that flow the EC, maybe we could mimic the UnsafeQueue... methods on ThreadPool and call them Thread.UnsafeStart, which would not flow the EC?

CC @stephentoub

@kouvel
Copy link
Member Author

kouvel commented Dec 17, 2020

Does seem a bit odd though

@kouvel
Copy link
Member Author

kouvel commented Dec 17, 2020

I suppose Thread.UnsafeStart doesn't have to be a public API for the time being, it could just be used as the internal implementation for now, if that's preferred, until it is requested to be a public API. Thoughts?

@jkotas
Copy link
Member

jkotas commented Dec 17, 2020

Yes, make it internal API for this PR

@davidfowl
Copy link
Member

Yep sounds good

@kouvel
Copy link
Member Author

kouvel commented Dec 18, 2020

FYI for new reviewers there will be more changes coming I'll send an update once it's ready for review

@kouvel
Copy link
Member Author

kouvel commented Dec 18, 2020

Updated to add internal Thread.UnsafeStart and used that instead, the code is simpler and cleaner so it's nice. Changes are ready for review, please take a look.

@kouvel kouvel removed the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label Dec 18, 2020
Copy link
Member

@davidfowl davidfowl left a comment

Choose a reason for hiding this comment

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

Looks great. I assume we should do the same for timer threads in the portable timer case but those threads aren't created lazily AFAIK

@kouvel
Copy link
Member Author

kouvel commented Dec 18, 2020

I have updated the portable timer now as well. The timer thread is created lazily the first time a timer is scheduled.

@kouvel kouvel merged commit 876259f into dotnet:master Dec 19, 2020
@kouvel kouvel deleted the TpEcFix branch December 19, 2020 00:01
@ghost ghost locked as resolved and limited conversation to collaborators Jan 18, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants