aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs')
-rw-r--r--src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs54
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();
+ }
+ }
}
}