1 #region Copyright notice and license 2 // Copyright 2015 gRPC authors. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 #endregion 16 using System; 17 using System.Runtime.InteropServices; 18 using System.Threading.Tasks; 19 using Grpc.Core.Profiling; 20 21 using Grpc.Core.Utils; 22 23 namespace Grpc.Core.Internal 24 { 25 /// <summary> 26 /// grpc_completion_queue from <c>grpc/grpc.h</c> 27 /// </summary> 28 internal class CompletionQueueSafeHandle : SafeHandleZeroIsInvalid 29 { 30 static readonly NativeMethods Native = NativeMethods.Get(); 31 32 AtomicCounter shutdownRefcount; 33 CompletionRegistry completionRegistry; 34 CompletionQueueSafeHandle()35 private CompletionQueueSafeHandle() 36 { 37 } 38 39 /// <summary> 40 /// Create a completion queue that can only be used for Pluck operations. 41 /// </summary> CreateSync()42 public static CompletionQueueSafeHandle CreateSync() 43 { 44 return Native.grpcsharp_completion_queue_create_sync(); 45 } 46 47 /// <summary> 48 /// Create a completion queue that can only be used for Next operations. 49 /// </summary> CreateAsync(CompletionRegistry completionRegistry)50 public static CompletionQueueSafeHandle CreateAsync(CompletionRegistry completionRegistry) 51 { 52 var cq = Native.grpcsharp_completion_queue_create_async(); 53 cq.completionRegistry = completionRegistry; 54 cq.shutdownRefcount = new AtomicCounter(1); 55 return cq; 56 } 57 Next()58 public CompletionQueueEvent Next() 59 { 60 return Native.grpcsharp_completion_queue_next(this); 61 } 62 Pluck(IntPtr tag)63 public CompletionQueueEvent Pluck(IntPtr tag) 64 { 65 return Native.grpcsharp_completion_queue_pluck(this, tag); 66 } 67 68 /// <summary> 69 /// Creates a new usage scope for this completion queue. Once successfully created, 70 /// the completion queue won't be shutdown before scope.Dispose() is called. 71 /// </summary> NewScope()72 public UsageScope NewScope() 73 { 74 return new UsageScope(this); 75 } 76 Shutdown()77 public void Shutdown() 78 { 79 DecrementShutdownRefcount(); 80 } 81 82 /// <summary> 83 /// Completion registry associated with this completion queue. 84 /// Doesn't need to be set if only using Pluck() operations. 85 /// </summary> 86 public CompletionRegistry CompletionRegistry 87 { 88 get { return completionRegistry; } 89 } 90 ReleaseHandle()91 protected override bool ReleaseHandle() 92 { 93 Native.grpcsharp_completion_queue_destroy(handle); 94 return true; 95 } 96 DecrementShutdownRefcount()97 private void DecrementShutdownRefcount() 98 { 99 if (shutdownRefcount == null || shutdownRefcount.Decrement() == 0) 100 { 101 Native.grpcsharp_completion_queue_shutdown(this); 102 } 103 } 104 BeginOp()105 private void BeginOp() 106 { 107 GrpcPreconditions.CheckNotNull(shutdownRefcount, nameof(shutdownRefcount)); 108 bool success = false; 109 shutdownRefcount.IncrementIfNonzero(ref success); 110 GrpcPreconditions.CheckState(success, "Shutdown has already been called"); 111 } 112 EndOp()113 private void EndOp() 114 { 115 GrpcPreconditions.CheckNotNull(shutdownRefcount, nameof(shutdownRefcount)); 116 DecrementShutdownRefcount(); 117 } 118 119 // Allows declaring BeginOp and EndOp of a completion queue with a using statement. 120 // Declared as struct for better performance. 121 public struct UsageScope : IDisposable 122 { 123 readonly CompletionQueueSafeHandle cq; 124 UsageScopeGrpc.Core.Internal.CompletionQueueSafeHandle.UsageScope125 public UsageScope(CompletionQueueSafeHandle cq) 126 { 127 this.cq = cq; 128 this.cq.BeginOp(); 129 } 130 DisposeGrpc.Core.Internal.CompletionQueueSafeHandle.UsageScope131 public void Dispose() 132 { 133 cq.EndOp(); 134 } 135 } 136 } 137 } 138