• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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