Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Replace StreamAsyncHelper with StreamApmExtensions in System.Net.Security #7800

Merged
merged 1 commit into from
Apr 17, 2016

Conversation

stephentoub
Copy link
Member

System.Net.Security was originally written to use Stream.Begin/EndRead/Write. When it was ported to .NET Core, it took a dependency on a helper that provided such Begin/End methods, but this helper was originally written for a different purpose: providing async Begin/End wrappers for the synchronous Read/Write methods. As a result of this mismatch, the async calls in System.Net.Security are queueing work items that then do work synchronously, blocking thread pool threads unnecessarily. This commit changes those helpers to sit on top of ReadAsync/WriteAsync instead. Eventually System.Net.Security should have its async I/O redone to sit natively on ReadAsync/WriteAsync using async/await, as it'll result in less overhead, but for now with minimal changes this improves the scalability of the library.

cc: @davidsh, @CIPop, @ericeil, @mikeharder

@benaadams
Copy link
Member

Wonderful, wonderful, wonderful... 😁

🚀


if (task == null || ar == null)
{
throw new ArgumentException(SR.InvalidOperation_WrongAsyncResultOrEndReadCalledMultiple);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can the resources be deleted as well, or are they still used elsewhere in the assembly?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yup, deleted, thanks.

…rity

System.Net.Security was originally written to use Stream.Begin/EndRead/Write.  When it was ported to .NET Core, it took a dependency on a helper that provided such Begin/End methods, but this helper was originally written for a different purpose: providing async Begin/End wrappers for the synchronous Read/Write methods.  As a result of this mismatch, the async calls in System.Net.Security are queueing work items that then do work synchronously, blocking thread pool threads unnecessarily.  This commit changes those helpers to sit on top of ReadAsync/WriteAsync instead.  Eventually System.Net.Security should have its async I/O redone to sit natively on ReadAsync/WriteAsync using async/await, as it'll result in less overhead, but for now with minimal changes this improves the scalability of the library.
@davidsh
Copy link
Contributor

davidsh commented Apr 17, 2016

LGTM

@stephentoub stephentoub merged commit d10541f into dotnet:master Apr 17, 2016
@stephentoub stephentoub deleted the netsecurity_streamhelpers branch April 17, 2016 23:19
@joshfree joshfree added the blocking Marks issues that we want to fast track in order to unblock other important work label Apr 18, 2016
@CIPop
Copy link
Member

CIPop commented Apr 19, 2016

@ericstj @weshaggard PTAL : I remember there were some corner cases that StreamAsyncHelper was potentially handling (which is why it was recommended initially).

Thanks @stephentoub! LGTM

@benaadams
Copy link
Member

@stephentoub issue on full framework is

Checking coreclr

@benaadams
Copy link
Member

Works on coreclr! 😄

@benaadams
Copy link
Member

Issue on full framework is it use the frameworks SSL stream which has the issue. This version is only compatible with net46 and not net451; is it possible for it to target 451?

@stephentoub
Copy link
Member Author

What's the underlying stream being wrapped by SslStream?

@benaadams
Copy link
Member

benaadams commented Apr 25, 2016

Its a custom stream that implements sync and async https://github.com/aspnet/KestrelHttpServer/blob/dev/src/Microsoft.AspNetCore.Server.Kestrel/Http/FrameResponseStream.cs

Actually its read/write so likely is this one first https://github.com/aspnet/KestrelHttpServer/blob/dev/src/Microsoft.AspNetCore.Server.Kestrel/Http/FrameDuplexStream.cs

Which has BeginWrite and EndWrite defined in 451; in addition to ReadAsync+WriteAsync

@stephentoub
Copy link
Member Author

Thanks, @benaadams. The problem is that the .NET Framework code for SslStream is written on top of the Begin/End methods, but you can't override the Begin/End methods as they're not exposed in the contracts, so SslStream ends up using the base Stream.Begin/EndXx methods, which a) just queue work items to call the synchronous methods, and b) because those synchronous methods are rarely implemented to be used concurrently uses a semaphore to ensure access is serialized. I'm discussing options offline with some folks, e.g. changing the .NET Framework implementation of Begin/End, adding the Begin/End methods back to the contracts, etc.

@benaadams
Copy link
Member

Would using corefx's version of SslStream be an option or would that not help?

@stephentoub
Copy link
Member Author

Would using corefx's version of SslStream be an option or would that not help?

It would address this particular case of the problem, but not other cases (other types consuming the Begin/End methods). I also don't think it would be feasible, unless all of the code were cloned/renamed into ASP.NET's implementation, which has its own obvious and significant downsides.

@benaadams
Copy link
Member

Related issue aspnet/KestrelHttpServer#768

@karelz karelz modified the milestone: 1.0.0-rtm Dec 3, 2016
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
…reamhelpers

Replace StreamAsyncHelper with StreamApmExtensions in System.Net.Security

Commit migrated from dotnet/corefx@d10541f
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Net blocking Marks issues that we want to fast track in order to unblock other important work
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants