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 = new AtomicCounter(1); 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 return cq; 55 } 56 Next()57 public CompletionQueueEvent Next() 58 { 59 return Native.grpcsharp_completion_queue_next(this); 60 } 61 Pluck(IntPtr tag)62 public CompletionQueueEvent Pluck(IntPtr tag) 63 { 64 return Native.grpcsharp_completion_queue_pluck(this, tag); 65 } 66 67 /// <summary> 68 /// Creates a new usage scope for this completion queue. Once successfully created, 69 /// the completion queue won't be shutdown before scope.Dispose() is called. 70 /// </summary> NewScope()71 public UsageScope NewScope() 72 { 73 return new UsageScope(this); 74 } 75 Shutdown()76 public void Shutdown() 77 { 78 DecrementShutdownRefcount(); 79 } 80 81 /// <summary> 82 /// Completion registry associated with this completion queue. 83 /// Doesn't need to be set if only using Pluck() operations. 84 /// </summary> 85 public CompletionRegistry CompletionRegistry 86 { 87 get { return completionRegistry; } 88 } 89 ReleaseHandle()90 protected override bool ReleaseHandle() 91 { 92 Native.grpcsharp_completion_queue_destroy(handle); 93 return true; 94 } 95 DecrementShutdownRefcount()96 private void DecrementShutdownRefcount() 97 { 98 if (shutdownRefcount.Decrement() == 0) 99 { 100 Native.grpcsharp_completion_queue_shutdown(this); 101 } 102 } 103 BeginOp()104 private void BeginOp() 105 { 106 bool success = false; 107 shutdownRefcount.IncrementIfNonzero(ref success); 108 GrpcPreconditions.CheckState(success, "Shutdown has already been called"); 109 } 110 EndOp()111 private void EndOp() 112 { 113 DecrementShutdownRefcount(); 114 } 115 116 // Allows declaring BeginOp and EndOp of a completion queue with a using statement. 117 // Declared as struct for better performance. 118 public struct UsageScope : IDisposable 119 { 120 readonly CompletionQueueSafeHandle cq; 121 UsageScopeGrpc.Core.Internal.CompletionQueueSafeHandle.UsageScope122 public UsageScope(CompletionQueueSafeHandle cq) 123 { 124 this.cq = cq; 125 this.cq.BeginOp(); 126 } 127 DisposeGrpc.Core.Internal.CompletionQueueSafeHandle.UsageScope128 public void Dispose() 129 { 130 cq.EndOp(); 131 } 132 } 133 } 134 } 135