diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
index d03e79685e79..cdc6c7d62ece 100644
--- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
+++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
@@ -636,6 +636,7 @@
+
diff --git a/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs b/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs
index f836c73c3202..538448f6383d 100644
--- a/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs
+++ b/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs
@@ -143,19 +143,13 @@ protected override void Dispose(bool disposing)
public override ValueTask DisposeAsync()
{
- if (GetType() == typeof(MemoryStream))
- {
- // Same as Dispose(true)
- _isOpen = false;
- _writable = false;
- _expandable = false;
- _lastReadTask = null;
- return default;
- }
- else
+ if (GetType() != typeof(MemoryStream))
{
return base.DisposeAsync();
}
+
+ Dispose(disposing: true);
+ return default;
}
// returns a bool saying whether we allocated a new array.
diff --git a/src/System.Private.CoreLib/shared/System/IO/PinnedBufferMemoryStream.cs b/src/System.Private.CoreLib/shared/System/IO/PinnedBufferMemoryStream.cs
index 94331a2ef826..28385a6b740e 100644
--- a/src/System.Private.CoreLib/shared/System/IO/PinnedBufferMemoryStream.cs
+++ b/src/System.Private.CoreLib/shared/System/IO/PinnedBufferMemoryStream.cs
@@ -15,8 +15,9 @@
===========================================================*/
using System;
-using System.Runtime.InteropServices;
using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
namespace System.IO
{
@@ -56,5 +57,11 @@ protected override void Dispose(bool disposing)
base.Dispose(disposing);
}
+
+ public override ValueTask DisposeAsync()
+ {
+ Dispose(disposing: true);
+ return default;
+ }
}
}
diff --git a/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs b/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs
index 4fa6fae6240f..73e92ad30927 100644
--- a/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs
+++ b/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs
@@ -233,15 +233,13 @@ protected override void Dispose(bool disposing)
public override ValueTask DisposeAsync()
{
- try
+ if (GetType() != typeof(UnmanagedMemoryStream))
{
- Dispose(disposing: true);
- return default;
- }
- catch (Exception exc)
- {
- return new ValueTask(Task.FromException(exc));
+ return base.DisposeAsync();
}
+
+ Dispose(disposing: true);
+ return default;
}
private void EnsureNotClosed()
diff --git a/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStreamWrapper.cs b/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStreamWrapper.cs
index 9a598951ee80..dbc88488b551 100644
--- a/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStreamWrapper.cs
+++ b/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStreamWrapper.cs
@@ -59,6 +59,11 @@ protected override void Dispose(bool disposing)
}
}
+ public override ValueTask DisposeAsync()
+ {
+ return _unmanagedStream.DisposeAsync();
+ }
+
public override void Flush()
{
_unmanagedStream.Flush();
diff --git a/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs b/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs
index 694514ef07e8..983281491778 100644
--- a/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs
+++ b/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs
@@ -21,6 +21,8 @@ namespace System.Threading
{
public delegate void ContextCallback(object state);
+ internal delegate void ContextCallback(ref TState state);
+
public sealed class ExecutionContext : IDisposable, ISerializable
{
internal static readonly ExecutionContext Default = new ExecutionContext(isDefault: true);
@@ -201,6 +203,85 @@ internal static void RunInternal(ExecutionContext executionContext, ContextCallb
edi?.Throw();
}
+ // Direct copy of the above RunInternal overload, except that it passes the state into the callback strongly-typed and by ref.
+ internal static void RunInternal(ExecutionContext executionContext, ContextCallback callback, ref TState state)
+ {
+ // Note: ExecutionContext.RunInternal is an extremely hot function and used by every await, ThreadPool execution, etc.
+ // Note: Manual enregistering may be addressed by "Exception Handling Write Through Optimization"
+ // https://github.com/dotnet/coreclr/blob/master/Documentation/design-docs/eh-writethru.md
+
+ // Enregister variables with 0 post-fix so they can be used in registers without EH forcing them to stack
+ // Capture references to Thread Contexts
+ Thread currentThread0 = Thread.CurrentThread;
+ Thread currentThread = currentThread0;
+ ExecutionContext previousExecutionCtx0 = currentThread0.ExecutionContext;
+
+ // Store current ExecutionContext and SynchronizationContext as "previousXxx".
+ // This allows us to restore them and undo any Context changes made in callback.Invoke
+ // so that they won't "leak" back into caller.
+ // These variables will cross EH so be forced to stack
+ ExecutionContext previousExecutionCtx = previousExecutionCtx0;
+ SynchronizationContext previousSyncCtx = currentThread0.SynchronizationContext;
+
+ if (executionContext != null && executionContext.m_isDefault)
+ {
+ // Default is a null ExecutionContext internally
+ executionContext = null;
+ }
+
+ if (previousExecutionCtx0 != executionContext)
+ {
+ // Restore changed ExecutionContext
+ currentThread0.ExecutionContext = executionContext;
+ if ((executionContext != null && executionContext.HasChangeNotifications) ||
+ (previousExecutionCtx0 != null && previousExecutionCtx0.HasChangeNotifications))
+ {
+ // There are change notifications; trigger any affected
+ OnValuesChanged(previousExecutionCtx0, executionContext);
+ }
+ }
+
+ ExceptionDispatchInfo edi = null;
+ try
+ {
+ callback.Invoke(ref state);
+ }
+ catch (Exception ex)
+ {
+ // Note: we have a "catch" rather than a "finally" because we want
+ // to stop the first pass of EH here. That way we can restore the previous
+ // context before any of our callers' EH filters run.
+ edi = ExceptionDispatchInfo.Capture(ex);
+ }
+
+ // Re-enregistrer variables post EH with 1 post-fix so they can be used in registers rather than from stack
+ SynchronizationContext previousSyncCtx1 = previousSyncCtx;
+ Thread currentThread1 = currentThread;
+ // The common case is that these have not changed, so avoid the cost of a write barrier if not needed.
+ if (currentThread1.SynchronizationContext != previousSyncCtx1)
+ {
+ // Restore changed SynchronizationContext back to previous
+ currentThread1.SynchronizationContext = previousSyncCtx1;
+ }
+
+ ExecutionContext previousExecutionCtx1 = previousExecutionCtx;
+ ExecutionContext currentExecutionCtx1 = currentThread1.ExecutionContext;
+ if (currentExecutionCtx1 != previousExecutionCtx1)
+ {
+ // Restore changed ExecutionContext back to previous
+ currentThread1.ExecutionContext = previousExecutionCtx1;
+ if ((currentExecutionCtx1 != null && currentExecutionCtx1.HasChangeNotifications) ||
+ (previousExecutionCtx1 != null && previousExecutionCtx1.HasChangeNotifications))
+ {
+ // There are change notifications; trigger any affected
+ OnValuesChanged(currentExecutionCtx1, previousExecutionCtx1);
+ }
+ }
+
+ // If exception was thrown by callback, rethrow it now original contexts are restored
+ edi?.Throw();
+ }
+
internal static void OnValuesChanged(ExecutionContext previousExecutionCtx, ExecutionContext nextExecutionCtx)
{
Debug.Assert(previousExecutionCtx != nextExecutionCtx);
diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/ManualResetValueTaskSourceLogic.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/ManualResetValueTaskSourceLogic.cs
new file mode 100644
index 000000000000..ba044a9f5637
--- /dev/null
+++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/ManualResetValueTaskSourceLogic.cs
@@ -0,0 +1,258 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.ExceptionServices;
+using System.Runtime.InteropServices;
+
+namespace System.Threading.Tasks.Sources
+{
+ /// Provides the core logic for implementing a manual-reset or .
+ ///
+ [StructLayout(LayoutKind.Auto)]
+ public struct ManualResetValueTaskSourceLogic
+ {
+ ///
+ /// The callback to invoke when the operation completes if was called before the operation completed,
+ /// or if the operation completed before a callback was supplied,
+ /// or null if a callback hasn't yet been provided and the operation hasn't yet completed.
+ ///
+ private Action