remove delegate allocation and boxing from cancellation registrations

pull/19610/head
mgravell 6 years ago
parent 59011087b0
commit 39775cf30f
  1. 11
      src/csharp/Grpc.Core.Tests/CallCancellationTest.cs
  2. 10
      src/csharp/Grpc.Core/Internal/AsyncCall.cs
  3. 8
      src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
  4. 3
      src/csharp/Grpc.Core/Internal/ClientResponseStream.cs
  5. 4
      src/csharp/Grpc.Core/Internal/ServerRequestStream.cs

@ -178,5 +178,16 @@ namespace Grpc.Core.Tests
Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
} }
} }
[Test]
public void CanDisposeDefaultCancellationRegistration()
{
// prove that we're fine to dispose default CancellationTokenRegistration
// values without boxing them to IDisposable for a null-check
var obj = default(CancellationTokenRegistration);
obj.Dispose();
using (obj) {}
}
} }
} }

@ -38,7 +38,7 @@ namespace Grpc.Core.Internal
bool registeredWithChannel; bool registeredWithChannel;
// Dispose of to de-register cancellation token registration // Dispose of to de-register cancellation token registration
IDisposable cancellationTokenRegistration; CancellationTokenRegistration cancellationTokenRegistration;
// Completion of a pending unary response if not null. // Completion of a pending unary response if not null.
TaskCompletionSource<TResponse> unaryResponseTcs; TaskCompletionSource<TResponse> unaryResponseTcs;
@ -409,7 +409,7 @@ namespace Grpc.Core.Internal
// deadlock. // deadlock.
// See https://github.com/grpc/grpc/issues/14777 // See https://github.com/grpc/grpc/issues/14777
// See https://github.com/dotnet/corefx/issues/14903 // See https://github.com/dotnet/corefx/issues/14903
cancellationTokenRegistration?.Dispose(); cancellationTokenRegistration.Dispose();
} }
protected override bool IsClient protected override bool IsClient
@ -509,11 +509,7 @@ namespace Grpc.Core.Internal
// Make sure that once cancellationToken for this call is cancelled, Cancel() will be called. // Make sure that once cancellationToken for this call is cancelled, Cancel() will be called.
private void RegisterCancellationCallback() private void RegisterCancellationCallback()
{ {
var token = details.Options.CancellationToken; cancellationTokenRegistration = RegisterCancellationCallbackForToken(details.Options.CancellationToken);
if (token.CanBeCanceled)
{
cancellationTokenRegistration = token.Register(() => this.Cancel());
}
} }
/// <summary> /// <summary>

@ -394,5 +394,13 @@ namespace Grpc.Core.Internal
{ {
HandleReadFinished(success, receivedMessageReader); HandleReadFinished(success, receivedMessageReader);
} }
internal CancellationTokenRegistration RegisterCancellationCallbackForToken(CancellationToken cancellationToken)
{
if (cancellationToken.CanBeCanceled) return cancellationToken.Register(CancelCallFromToken, this);
return default(CancellationTokenRegistration);
}
private static readonly Action<object> CancelCallFromToken = state => ((AsyncCallBase<TWrite, TRead>)state).Cancel();
} }
} }

@ -49,8 +49,7 @@ namespace Grpc.Core.Internal
public async Task<bool> MoveNext(CancellationToken token) public async Task<bool> MoveNext(CancellationToken token)
{ {
var cancellationTokenRegistration = token.CanBeCanceled ? token.Register(() => call.Cancel()) : (IDisposable) null; using (call.RegisterCancellationCallbackForToken(token))
using (cancellationTokenRegistration)
{ {
var result = await call.ReadMessageAsync().ConfigureAwait(false); var result = await call.ReadMessageAsync().ConfigureAwait(false);
this.current = result; this.current = result;

@ -49,9 +49,7 @@ namespace Grpc.Core.Internal
public async Task<bool> MoveNext(CancellationToken token) public async Task<bool> MoveNext(CancellationToken token)
{ {
using (call.RegisterCancellationCallbackForToken(token))
var cancellationTokenRegistration = token.CanBeCanceled ? token.Register(() => call.Cancel()) : (IDisposable) null;
using (cancellationTokenRegistration)
{ {
var result = await call.ReadMessageAsync().ConfigureAwait(false); var result = await call.ReadMessageAsync().ConfigureAwait(false);
this.current = result; this.current = result;

Loading…
Cancel
Save