• 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