Skip to content

Conversation

@pavelsavara
Copy link
Member

@pavelsavara pavelsavara commented Jan 19, 2026

  • Blocking .Wait() of any type is impossible to implement in single-threaded browser.
  • It's marked with [UnsupportedOSPlatform("browser")]
  • Eventually throws PlatformNotSupportedException

This is attempt to throw earlier and allow IL trimmer to throw away part of the wait subsystem.
Together with #123329 and #123326

@pavelsavara pavelsavara added this to the 11.0.0 milestone Jan 19, 2026
@pavelsavara pavelsavara self-assigned this Jan 19, 2026
@pavelsavara pavelsavara added arch-wasm WebAssembly architecture area-VM-threading-mono size-reduction Issues impacting final app size primary for size sensitive workloads os-browser Browser variant of arch-wasm labels Jan 19, 2026
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to 'size-reduction': @eerhardt, @SamMonoRT, @marek-safar
See info in area-owners.md if you want to be subscribed.

@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.

@pavelsavara
Copy link
Member Author

Log

[19:35:49] info: [FAIL] System.IO.Tests.Sync_DerivedFileStream_ReadWrite_Span.CallMemoryReadWriteAsyncOnDerivedFileStream_ArrayMethodsUsed
[19:35:49] info: System.PlatformNotSupportedException : Operation is not supported on this platform.
[19:35:49] info:    at System.IO.Stream.BeginWriteInternal(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state, Boolean serializeAsynchronously, Boolean apm)
[19:35:49] info:    at System.IO.Stream.BeginWrite(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state)
[19:35:49] info:    at System.IO.FileStream.BaseBeginWrite(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state)
[19:35:49] info:    at System.IO.Strategies.DerivedFileStreamStrategy.BeginWrite(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state)
[19:35:49] info:    at System.IO.FileStream.BeginWrite(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state)
[19:35:49] info:    at System.IO.Stream.<>c.<BeginEndWriteAsync>b__62_0(Stream stream, ReadWriteParameters args, AsyncCallback callback, Object state)
[19:35:49] info:    at System.Threading.Tasks.TaskFactory`1[[System.Threading.Tasks.VoidTaskResult, System.Private.CoreLib, Version=11.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].FromAsyncTrim[Stream,ReadWriteParameters](Stream thisRef, ReadWriteParameters args, Func`5 beginMethod, Func`3 endMethod)
[19:35:49] info:    at System.IO.Stream.BeginEndWriteAsync(Byte[] buffer, Int32 offset, Int32 count)
[19:35:49] info:    at System.IO.Stream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
[19:35:49] info:    at System.IO.FileStream.BaseWriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
[19:35:49] info:    at System.IO.Strategies.DerivedFileStreamStrategy.WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
[19:35:49] info:    at System.IO.FileStream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
[19:35:49] info:    at System.IO.Tests.DerivedFileStream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
[19:35:49] info:    at System.IO.Stream.WriteAsync(ReadOnlyMemory`1 buffer, CancellationToken cancellationToken)
[19:35:49] info:    at System.IO.FileStream.BaseWriteAsync(ReadOnlyMemory`1 buffer, CancellationToken cancellationToken)
[19:35:49] info:    at System.IO.Strategies.DerivedFileStreamStrategy.WriteAsync(ReadOnlyMemory`1 buffer, CancellationToken cancellationToken)
[19:35:49] info:    at System.IO.FileStream.WriteAsync(ReadOnlyMemory`1 buffer, CancellationToken cancellationToken)
[19:35:49] info:    at System.IO.Tests.Sync_DerivedFileStream_ReadWrite_Span.CallMemoryReadWriteAsyncOnDerivedFileStream_ArrayMethodsUsed()

@pavelsavara
Copy link
Member Author

@stephentoub could you please help me figure out why is Stream.BeginEndWriteAsync forcing me into potentially blocking SemaphoreSlim.Wait() ?

Please see test failure in comment above and the simple change on this PR.

I see HasOverriddenBeginEndWrite() but I don't get it.
Why BeginWrite() -> BeginWriteInternal() with serializeAsynchronously: false ?

What could be done about it ?

@pavelsavara
Copy link
Member Author

I guess in all single-threaded cases, the semaphore would be open, so there would be no actual blocking. And that's how it doesn't fail without this PR.

@stephentoub
Copy link
Member

@stephentoub could you please help me figure out why is Stream.BeginEndWriteAsync forcing me into potentially blocking SemaphoreSlim.Wait() ?

Please see test failure in comment above and the simple change on this PR.

I see HasOverriddenBeginEndWrite() but I don't get it. Why BeginWrite() -> BeginWriteInternal() with serializeAsynchronously: false ?

What could be done about it ?

It's emulating the legacy behavior in BeginRead/Write that's been there since .NET Framework 1.x.

Rather than throwing on that path, I think it'd be better to just change serializeAsynchronously to always be true when in a single threaded browser build. We could also consider taking the breaking change to just always have it be true everywhere; we haven't thus far out because these are legacy code paths we really don't want folks using, and so we haven't wanted to absorb the breaking change risk.

@pavelsavara
Copy link
Member Author

Thanks!
I moved the implementation to #123329

@pavelsavara pavelsavara deleted the browser_trimming_stream branch January 21, 2026 10:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-VM-threading-mono os-browser Browser variant of arch-wasm size-reduction Issues impacting final app size primary for size sensitive workloads

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants