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

Commit

Permalink
Add ManualResetValueTaskSourceLogic
Browse files Browse the repository at this point in the history
  • Loading branch information
stephentoub committed Oct 17, 2018
1 parent a7c534f commit 482f5d1
Show file tree
Hide file tree
Showing 9 changed files with 379 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\TaskToApm.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\TaskSchedulerException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\ValueTask.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\Sources\ManualResetValueTaskSourceLogic.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\Sources\IValueTaskSource.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadAbortException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadInterruptedException.cs" />
Expand Down
14 changes: 4 additions & 10 deletions src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
===========================================================*/

using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

namespace System.IO
{
Expand Down Expand Up @@ -56,5 +57,11 @@ protected override void Dispose(bool disposing)

base.Dispose(disposing);
}

public override ValueTask DisposeAsync()
{
Dispose(disposing: true);
return default;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ protected override void Dispose(bool disposing)
}
}

public override ValueTask DisposeAsync()
{
return _unmanagedStream.DisposeAsync();
}

public override void Flush()
{
_unmanagedStream.Flush();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ namespace System.Threading
{
public delegate void ContextCallback(object state);

internal delegate void ContextCallback<TState>(ref TState state);

public sealed class ExecutionContext : IDisposable, ISerializable
{
internal static readonly ExecutionContext Default = new ExecutionContext(isDefault: true);
Expand Down Expand Up @@ -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<TState>(ExecutionContext executionContext, ContextCallback<TState> 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);
Expand Down
Loading

0 comments on commit 482f5d1

Please sign in to comment.