diff options
Diffstat (limited to 'src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs')
-rw-r--r-- | src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs | 54 |
1 files changed, 53 insertions, 1 deletions
diff --git a/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs index 9de2bc7950..3754ad382e 100644 --- a/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs @@ -33,6 +33,8 @@ using System.Runtime.InteropServices; using System.Threading.Tasks; using Grpc.Core.Profiling; +using Grpc.Core.Utils; + namespace Grpc.Core.Internal { /// <summary> @@ -40,6 +42,8 @@ namespace Grpc.Core.Internal /// </summary> internal class CompletionQueueSafeHandle : SafeHandleZeroIsInvalid { + AtomicCounter shutdownRefcount = new AtomicCounter(1); + [DllImport("grpc_csharp_ext.dll")] static extern CompletionQueueSafeHandle grpcsharp_completion_queue_create(); @@ -62,6 +66,7 @@ namespace Grpc.Core.Internal public static CompletionQueueSafeHandle Create() { return grpcsharp_completion_queue_create(); + } public CompletionQueueEvent Next() @@ -77,9 +82,18 @@ namespace Grpc.Core.Internal } } + /// <summary> + /// Creates a new usage scope for this completion queue. Once successfully created, + /// the completion queue won't be shutdown before scope.Dispose() is called. + /// </summary> + public UsageScope NewScope() + { + return new UsageScope(this); + } + public void Shutdown() { - grpcsharp_completion_queue_shutdown(this); + DecrementShutdownRefcount(); } protected override bool ReleaseHandle() @@ -87,5 +101,43 @@ namespace Grpc.Core.Internal grpcsharp_completion_queue_destroy(handle); return true; } + + private void DecrementShutdownRefcount() + { + if (shutdownRefcount.Decrement() == 0) + { + grpcsharp_completion_queue_shutdown(this); + } + } + + private void BeginOp() + { + bool success = false; + shutdownRefcount.IncrementIfNonzero(ref success); + Preconditions.CheckState(success, "Shutdown has already been called"); + } + + private void EndOp() + { + DecrementShutdownRefcount(); + } + + // Allows declaring BeginOp and EndOp of a completion queue with a using statement. + // Declared as struct for better performance. + public struct UsageScope : IDisposable + { + readonly CompletionQueueSafeHandle cq; + + public UsageScope(CompletionQueueSafeHandle cq) + { + this.cq = cq; + this.cq.BeginOp(); + } + + public void Dispose() + { + cq.EndOp(); + } + } } } |