no need to call GrpcEnvironment.Initialize() explicitly

pull/2332/head
Jan Tattermusch 10 years ago
parent aa91ad2c8d
commit 04eb89ca26
  1. 6
      src/csharp/Grpc.Core.Tests/ClientServerTest.cs
  2. 17
      src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
  3. 12
      src/csharp/Grpc.Core.Tests/PInvokeTest.cs
  4. 3
      src/csharp/Grpc.Core.Tests/ServerTest.cs
  5. 16
      src/csharp/Grpc.Core/Calls.cs
  6. 30
      src/csharp/Grpc.Core/Channel.cs
  7. 110
      src/csharp/Grpc.Core/GrpcEnvironment.cs
  8. 9
      src/csharp/Grpc.Core/Internal/AsyncCall.cs
  9. 9
      src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
  10. 30
      src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
  11. 12
      src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
  12. 35
      src/csharp/Grpc.Core/Internal/DebugStats.cs
  13. 8
      src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
  14. 26
      src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
  15. 14
      src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
  16. 17
      src/csharp/Grpc.Core/Server.cs
  17. 2
      src/csharp/Grpc.Examples.MathClient/MathClient.cs
  18. 2
      src/csharp/Grpc.Examples.MathServer/MathServer.cs
  19. 3
      src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
  20. 3
      src/csharp/Grpc.IntegrationTesting/InteropClient.cs
  21. 3
      src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
  22. 2
      src/csharp/Grpc.IntegrationTesting/InteropServer.cs

@ -73,12 +73,6 @@ namespace Grpc.Core.Tests
Server server; Server server;
Channel channel; Channel channel;
[TestFixtureSetUp]
public void InitClass()
{
GrpcEnvironment.Initialize();
}
[SetUp] [SetUp]
public void Init() public void Init()
{ {

@ -43,16 +43,17 @@ namespace Grpc.Core.Tests
[Test] [Test]
public void InitializeAndShutdownGrpcEnvironment() public void InitializeAndShutdownGrpcEnvironment()
{ {
GrpcEnvironment.Initialize(); var env = GrpcEnvironment.GetInstance();
Assert.IsNotNull(GrpcEnvironment.ThreadPool.CompletionQueue); Assert.IsNotNull(env.CompletionQueue);
GrpcEnvironment.Shutdown(); GrpcEnvironment.Shutdown();
} }
[Test] [Test]
public void SubsequentInvocations() public void SubsequentInvocations()
{ {
GrpcEnvironment.Initialize(); var env1 = GrpcEnvironment.GetInstance();
GrpcEnvironment.Initialize(); var env2 = GrpcEnvironment.GetInstance();
Assert.IsTrue(object.ReferenceEquals(env1, env2));
GrpcEnvironment.Shutdown(); GrpcEnvironment.Shutdown();
GrpcEnvironment.Shutdown(); GrpcEnvironment.Shutdown();
} }
@ -60,15 +61,13 @@ namespace Grpc.Core.Tests
[Test] [Test]
public void InitializeAfterShutdown() public void InitializeAfterShutdown()
{ {
GrpcEnvironment.Initialize(); var env1 = GrpcEnvironment.GetInstance();
var tp1 = GrpcEnvironment.ThreadPool;
GrpcEnvironment.Shutdown(); GrpcEnvironment.Shutdown();
GrpcEnvironment.Initialize(); var env2 = GrpcEnvironment.GetInstance();
var tp2 = GrpcEnvironment.ThreadPool;
GrpcEnvironment.Shutdown(); GrpcEnvironment.Shutdown();
Assert.IsFalse(object.ReferenceEquals(tp1, tp2)); Assert.IsFalse(object.ReferenceEquals(env1, env2));
} }
} }
} }

@ -53,18 +53,6 @@ namespace Grpc.Core.Tests
[DllImport("grpc_csharp_ext.dll")] [DllImport("grpc_csharp_ext.dll")]
static extern IntPtr grpcsharp_test_nop(IntPtr ptr); static extern IntPtr grpcsharp_test_nop(IntPtr ptr);
[TestFixtureSetUp]
public void Init()
{
GrpcEnvironment.Initialize();
}
[TestFixtureTearDown]
public void Cleanup()
{
GrpcEnvironment.Shutdown();
}
/// <summary> /// <summary>
/// (~1.26us .NET Windows) /// (~1.26us .NET Windows)
/// </summary> /// </summary>

@ -44,13 +44,10 @@ namespace Grpc.Core.Tests
[Test] [Test]
public void StartAndShutdownServer() public void StartAndShutdownServer()
{ {
GrpcEnvironment.Initialize();
Server server = new Server(); Server server = new Server();
server.AddListeningPort("localhost", Server.PickUnusedPort); server.AddListeningPort("localhost", Server.PickUnusedPort);
server.Start(); server.Start();
server.ShutdownAsync().Wait(); server.ShutdownAsync().Wait();
GrpcEnvironment.Shutdown(); GrpcEnvironment.Shutdown();
} }
} }

@ -58,7 +58,7 @@ namespace Grpc.Core
where TResponse : class where TResponse : class
{ {
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name); asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
var asyncResult = asyncCall.UnaryCallAsync(req, call.Headers); var asyncResult = asyncCall.UnaryCallAsync(req, call.Headers);
RegisterCancellationCallback(asyncCall, token); RegisterCancellationCallback(asyncCall, token);
return await asyncResult; return await asyncResult;
@ -69,7 +69,7 @@ namespace Grpc.Core
where TResponse : class where TResponse : class
{ {
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name); asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
asyncCall.StartServerStreamingCall(req, call.Headers); asyncCall.StartServerStreamingCall(req, call.Headers);
RegisterCancellationCallback(asyncCall, token); RegisterCancellationCallback(asyncCall, token);
var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall); var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall);
@ -81,7 +81,7 @@ namespace Grpc.Core
where TResponse : class where TResponse : class
{ {
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name); asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
var resultTask = asyncCall.ClientStreamingCallAsync(call.Headers); var resultTask = asyncCall.ClientStreamingCallAsync(call.Headers);
RegisterCancellationCallback(asyncCall, token); RegisterCancellationCallback(asyncCall, token);
var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall); var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall);
@ -93,7 +93,7 @@ namespace Grpc.Core
where TResponse : class where TResponse : class
{ {
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name); asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
asyncCall.StartDuplexStreamingCall(call.Headers); asyncCall.StartDuplexStreamingCall(call.Headers);
RegisterCancellationCallback(asyncCall, token); RegisterCancellationCallback(asyncCall, token);
var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall); var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall);
@ -108,13 +108,5 @@ namespace Grpc.Core
token.Register(() => asyncCall.Cancel()); token.Register(() => asyncCall.Cancel());
} }
} }
/// <summary>
/// Gets shared completion queue used for async calls.
/// </summary>
private static CompletionQueueSafeHandle GetCompletionQueue()
{
return GrpcEnvironment.ThreadPool.CompletionQueue;
}
} }
} }

@ -42,8 +42,10 @@ namespace Grpc.Core
/// </summary> /// </summary>
public class Channel : IDisposable public class Channel : IDisposable
{ {
readonly GrpcEnvironment environment;
readonly ChannelSafeHandle handle; readonly ChannelSafeHandle handle;
readonly string target; readonly string target;
bool disposed;
/// <summary> /// <summary>
/// Creates a channel that connects to a specific host. /// Creates a channel that connects to a specific host.
@ -54,6 +56,7 @@ namespace Grpc.Core
/// <param name="options">Channel options.</param> /// <param name="options">Channel options.</param>
public Channel(string host, Credentials credentials = null, IEnumerable<ChannelOption> options = null) public Channel(string host, Credentials credentials = null, IEnumerable<ChannelOption> options = null)
{ {
this.environment = GrpcEnvironment.GetInstance();
using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(options)) using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(options))
{ {
if (credentials != null) if (credentials != null)
@ -105,10 +108,35 @@ namespace Grpc.Core
} }
} }
internal CompletionQueueSafeHandle CompletionQueue
{
get
{
return this.environment.CompletionQueue;
}
}
internal CompletionRegistry CompletionRegistry
{
get
{
return this.environment.CompletionRegistry;
}
}
internal GrpcEnvironment Environment
{
get
{
return this.environment;
}
}
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (handle != null && !handle.IsInvalid) if (disposing && handle != null && !disposed)
{ {
disposed = true;
handle.Dispose(); handle.Dispose();
} }
} }

@ -33,7 +33,9 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Grpc.Core.Internal; using Grpc.Core.Internal;
using Grpc.Core.Utils;
namespace Grpc.Core namespace Grpc.Core
{ {
@ -51,20 +53,18 @@ namespace Grpc.Core
static extern void grpcsharp_shutdown(); static extern void grpcsharp_shutdown();
static object staticLock = new object(); static object staticLock = new object();
static volatile GrpcEnvironment instance; static GrpcEnvironment instance;
readonly GrpcThreadPool threadPool; readonly GrpcThreadPool threadPool;
readonly CompletionRegistry completionRegistry; readonly CompletionRegistry completionRegistry;
readonly DebugStats debugStats = new DebugStats();
bool isClosed; bool isClosed;
/// <summary> /// <summary>
/// Makes sure GRPC environment is initialized. Subsequent invocations don't have any /// Returns an instance of initialized gRPC environment.
/// effect unless you call Shutdown first. /// Subsequent invocations return the same instance unless Shutdown has been called first.
/// Although normal use cases assume you will call this just once in your application's
/// lifetime (and call Shutdown once you're done), for the sake of easier testing it's
/// allowed to initialize the environment again after it has been successfully shutdown.
/// </summary> /// </summary>
public static void Initialize() internal static GrpcEnvironment GetInstance()
{ {
lock (staticLock) lock (staticLock)
{ {
@ -72,12 +72,13 @@ namespace Grpc.Core
{ {
instance = new GrpcEnvironment(); instance = new GrpcEnvironment();
} }
return instance;
} }
} }
/// <summary> /// <summary>
/// Shuts down the GRPC environment if it was initialized before. /// Shuts down the gRPC environment if it was initialized before.
/// Repeated invocations have no effect. /// Blocks until the environment has been fully shutdown.
/// </summary> /// </summary>
public static void Shutdown() public static void Shutdown()
{ {
@ -87,50 +88,55 @@ namespace Grpc.Core
{ {
instance.Close(); instance.Close();
instance = null; instance = null;
CheckDebugStats();
} }
} }
} }
internal static GrpcThreadPool ThreadPool /// <summary>
/// Creates gRPC environment.
/// </summary>
private GrpcEnvironment()
{
GrpcLog.RedirectNativeLogs(Console.Error);
grpcsharp_init();
completionRegistry = new CompletionRegistry(this);
threadPool = new GrpcThreadPool(this, THREAD_POOL_SIZE);
threadPool.Start();
// TODO: use proper logging here
Console.WriteLine("GRPC initialized.");
}
/// <summary>
/// Gets the completion registry used by this gRPC environment.
/// </summary>
internal CompletionRegistry CompletionRegistry
{ {
get get
{ {
var inst = instance; return this.completionRegistry;
if (inst == null)
{
throw new InvalidOperationException("GRPC environment not initialized");
}
return inst.threadPool;
} }
} }
internal static CompletionRegistry CompletionRegistry /// <summary>
/// Gets the completion queue used by this gRPC environment.
/// </summary>
internal CompletionQueueSafeHandle CompletionQueue
{ {
get get
{ {
var inst = instance; return this.threadPool.CompletionQueue;
if (inst == null)
{
throw new InvalidOperationException("GRPC environment not initialized");
}
return inst.completionRegistry;
} }
} }
/// <summary> /// <summary>
/// Creates gRPC environment. /// Gets the completion queue used by this gRPC environment.
/// </summary> /// </summary>
private GrpcEnvironment() internal DebugStats DebugStats
{ {
GrpcLog.RedirectNativeLogs(Console.Error); get
grpcsharp_init(); {
completionRegistry = new CompletionRegistry(); return this.debugStats;
threadPool = new GrpcThreadPool(THREAD_POOL_SIZE); }
threadPool.Start();
// TODO: use proper logging here
Console.WriteLine("GRPC initialized.");
} }
/// <summary> /// <summary>
@ -146,32 +152,28 @@ namespace Grpc.Core
grpcsharp_shutdown(); grpcsharp_shutdown();
isClosed = true; isClosed = true;
debugStats.CheckOK();
// TODO: use proper logging here // TODO: use proper logging here
Console.WriteLine("GRPC shutdown."); Console.WriteLine("GRPC shutdown.");
} }
private static void CheckDebugStats() /// <summary>
/// Shuts down this environment asynchronously.
/// </summary>
private Task CloseAsync()
{ {
var remainingClientCalls = DebugStats.ActiveClientCalls.Count; return Task.Run(() =>
if (remainingClientCalls != 0)
{
DebugWarning(string.Format("Detected {0} client calls that weren't disposed properly.", remainingClientCalls));
}
var remainingServerCalls = DebugStats.ActiveServerCalls.Count;
if (remainingServerCalls != 0)
{
DebugWarning(string.Format("Detected {0} server calls that weren't disposed properly.", remainingServerCalls));
}
var pendingBatchCompletions = DebugStats.PendingBatchCompletions.Count;
if (pendingBatchCompletions != 0)
{ {
DebugWarning(string.Format("Detected {0} pending batch completions.", pendingBatchCompletions)); try
} {
} Close();
}
private static void DebugWarning(string message) catch (Exception e)
{ {
throw new Exception("Shutdown check: " + message); Console.WriteLine("Error occured while shutting down GrpcEnvironment: " + e);
}
});
} }
} }
} }

@ -47,6 +47,8 @@ namespace Grpc.Core.Internal
/// </summary> /// </summary>
internal class AsyncCall<TRequest, TResponse> : AsyncCallBase<TRequest, TResponse> internal class AsyncCall<TRequest, TResponse> : AsyncCallBase<TRequest, TResponse>
{ {
Channel channel;
// Completion of a pending unary response if not null. // Completion of a pending unary response if not null.
TaskCompletionSource<TResponse> unaryResponseTcs; TaskCompletionSource<TResponse> unaryResponseTcs;
@ -61,8 +63,9 @@ namespace Grpc.Core.Internal
public void Initialize(Channel channel, CompletionQueueSafeHandle cq, string methodName) public void Initialize(Channel channel, CompletionQueueSafeHandle cq, string methodName)
{ {
var call = CallSafeHandle.Create(channel.Handle, cq, methodName, channel.Target, Timespec.InfFuture); this.channel = channel;
DebugStats.ActiveClientCalls.Increment(); var call = CallSafeHandle.Create(channel.Handle, channel.CompletionRegistry, cq, methodName, channel.Target, Timespec.InfFuture);
channel.Environment.DebugStats.ActiveClientCalls.Increment();
InitializeInternal(call); InitializeInternal(call);
} }
@ -277,7 +280,7 @@ namespace Grpc.Core.Internal
protected override void OnReleaseResources() protected override void OnReleaseResources()
{ {
DebugStats.ActiveClientCalls.Decrement(); channel.Environment.DebugStats.ActiveClientCalls.Decrement();
} }
/// <summary> /// <summary>

@ -48,14 +48,17 @@ namespace Grpc.Core.Internal
internal class AsyncCallServer<TRequest, TResponse> : AsyncCallBase<TResponse, TRequest> internal class AsyncCallServer<TRequest, TResponse> : AsyncCallBase<TResponse, TRequest>
{ {
readonly TaskCompletionSource<object> finishedServersideTcs = new TaskCompletionSource<object>(); readonly TaskCompletionSource<object> finishedServersideTcs = new TaskCompletionSource<object>();
readonly GrpcEnvironment environment;
public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer) : base(serializer, deserializer) public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer, GrpcEnvironment environment) : base(serializer, deserializer)
{ {
this.environment = Preconditions.CheckNotNull(environment);
} }
public void Initialize(CallSafeHandle call) public void Initialize(CallSafeHandle call)
{ {
DebugStats.ActiveServerCalls.Increment(); call.SetCompletionRegistry(environment.CompletionRegistry);
environment.DebugStats.ActiveServerCalls.Increment();
InitializeInternal(call); InitializeInternal(call);
} }
@ -114,7 +117,7 @@ namespace Grpc.Core.Internal
protected override void OnReleaseResources() protected override void OnReleaseResources()
{ {
DebugStats.ActiveServerCalls.Decrement(); environment.DebugStats.ActiveServerCalls.Decrement();
} }
/// <summary> /// <summary>

@ -43,6 +43,7 @@ namespace Grpc.Core.Internal
internal class CallSafeHandle : SafeHandleZeroIsInvalid internal class CallSafeHandle : SafeHandleZeroIsInvalid
{ {
const uint GRPC_WRITE_BUFFER_HINT = 1; const uint GRPC_WRITE_BUFFER_HINT = 1;
CompletionRegistry completionRegistry;
[DllImport("grpc_csharp_ext.dll")] [DllImport("grpc_csharp_ext.dll")]
static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline); static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline);
@ -97,15 +98,22 @@ namespace Grpc.Core.Internal
{ {
} }
public static CallSafeHandle Create(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline) public static CallSafeHandle Create(ChannelSafeHandle channel, CompletionRegistry registry, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline)
{ {
return grpcsharp_channel_create_call(channel, cq, method, host, deadline); var result = grpcsharp_channel_create_call(channel, cq, method, host, deadline);
result.SetCompletionRegistry(registry);
return result;
}
public void SetCompletionRegistry(CompletionRegistry completionRegistry)
{
this.completionRegistry = completionRegistry;
} }
public void StartUnary(byte[] payload, BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray) public void StartUnary(byte[] payload, BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
{ {
var ctx = BatchContextSafeHandle.Create(); var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback); completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray) grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray)
.CheckOk(); .CheckOk();
} }
@ -119,56 +127,56 @@ namespace Grpc.Core.Internal
public void StartClientStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray) public void StartClientStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
{ {
var ctx = BatchContextSafeHandle.Create(); var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback); completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_start_client_streaming(this, ctx, metadataArray).CheckOk(); grpcsharp_call_start_client_streaming(this, ctx, metadataArray).CheckOk();
} }
public void StartServerStreaming(byte[] payload, BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray) public void StartServerStreaming(byte[] payload, BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
{ {
var ctx = BatchContextSafeHandle.Create(); var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback); completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray).CheckOk(); grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray).CheckOk();
} }
public void StartDuplexStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray) public void StartDuplexStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
{ {
var ctx = BatchContextSafeHandle.Create(); var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback); completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray).CheckOk(); grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray).CheckOk();
} }
public void StartSendMessage(byte[] payload, BatchCompletionDelegate callback) public void StartSendMessage(byte[] payload, BatchCompletionDelegate callback)
{ {
var ctx = BatchContextSafeHandle.Create(); var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback); completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_send_message(this, ctx, payload, new UIntPtr((ulong)payload.Length)).CheckOk(); grpcsharp_call_send_message(this, ctx, payload, new UIntPtr((ulong)payload.Length)).CheckOk();
} }
public void StartSendCloseFromClient(BatchCompletionDelegate callback) public void StartSendCloseFromClient(BatchCompletionDelegate callback)
{ {
var ctx = BatchContextSafeHandle.Create(); var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback); completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_send_close_from_client(this, ctx).CheckOk(); grpcsharp_call_send_close_from_client(this, ctx).CheckOk();
} }
public void StartSendStatusFromServer(Status status, BatchCompletionDelegate callback) public void StartSendStatusFromServer(Status status, BatchCompletionDelegate callback)
{ {
var ctx = BatchContextSafeHandle.Create(); var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback); completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail).CheckOk(); grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail).CheckOk();
} }
public void StartReceiveMessage(BatchCompletionDelegate callback) public void StartReceiveMessage(BatchCompletionDelegate callback)
{ {
var ctx = BatchContextSafeHandle.Create(); var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback); completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_recv_message(this, ctx).CheckOk(); grpcsharp_call_recv_message(this, ctx).CheckOk();
} }
public void StartServerSide(BatchCompletionDelegate callback) public void StartServerSide(BatchCompletionDelegate callback)
{ {
var ctx = BatchContextSafeHandle.Create(); var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback); completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_start_serverside(this, ctx).CheckOk(); grpcsharp_call_start_serverside(this, ctx).CheckOk();
} }

@ -45,11 +45,17 @@ namespace Grpc.Core.Internal
internal class CompletionRegistry internal class CompletionRegistry
{ {
readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>(); readonly GrpcEnvironment environment;
readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>();
public CompletionRegistry(GrpcEnvironment environment)
{
this.environment = environment;
}
public void Register(IntPtr key, OpCompletionDelegate callback) public void Register(IntPtr key, OpCompletionDelegate callback)
{ {
DebugStats.PendingBatchCompletions.Increment(); environment.DebugStats.PendingBatchCompletions.Increment();
Preconditions.CheckState(dict.TryAdd(key, callback)); Preconditions.CheckState(dict.TryAdd(key, callback));
} }
@ -63,7 +69,7 @@ namespace Grpc.Core.Internal
{ {
OpCompletionDelegate value; OpCompletionDelegate value;
Preconditions.CheckState(dict.TryRemove(key, out value)); Preconditions.CheckState(dict.TryRemove(key, out value));
DebugStats.PendingBatchCompletions.Decrement(); environment.DebugStats.PendingBatchCompletions.Decrement();
return value; return value;
} }

@ -36,12 +36,39 @@ using System.Threading;
namespace Grpc.Core.Internal namespace Grpc.Core.Internal
{ {
internal static class DebugStats internal class DebugStats
{ {
public static readonly AtomicCounter ActiveClientCalls = new AtomicCounter(); public readonly AtomicCounter ActiveClientCalls = new AtomicCounter();
public static readonly AtomicCounter ActiveServerCalls = new AtomicCounter(); public readonly AtomicCounter ActiveServerCalls = new AtomicCounter();
public static readonly AtomicCounter PendingBatchCompletions = new AtomicCounter(); public readonly AtomicCounter PendingBatchCompletions = new AtomicCounter();
/// <summary>
/// Checks the debug stats and take action for any inconsistency found.
/// </summary>
public void CheckOK()
{
var remainingClientCalls = ActiveClientCalls.Count;
if (remainingClientCalls != 0)
{
DebugWarning(string.Format("Detected {0} client calls that weren't disposed properly.", remainingClientCalls));
}
var remainingServerCalls = ActiveServerCalls.Count;
if (remainingServerCalls != 0)
{
DebugWarning(string.Format("Detected {0} server calls that weren't disposed properly.", remainingServerCalls));
}
var pendingBatchCompletions = PendingBatchCompletions.Count;
if (pendingBatchCompletions != 0)
{
DebugWarning(string.Format("Detected {0} pending batch completions.", pendingBatchCompletions));
}
}
private void DebugWarning(string message)
{
throw new Exception("Shutdown check: " + message);
}
} }
} }

@ -45,14 +45,16 @@ namespace Grpc.Core.Internal
/// </summary> /// </summary>
internal class GrpcThreadPool internal class GrpcThreadPool
{ {
readonly GrpcEnvironment environment;
readonly object myLock = new object(); readonly object myLock = new object();
readonly List<Thread> threads = new List<Thread>(); readonly List<Thread> threads = new List<Thread>();
readonly int poolSize; readonly int poolSize;
CompletionQueueSafeHandle cq; CompletionQueueSafeHandle cq;
public GrpcThreadPool(int poolSize) public GrpcThreadPool(GrpcEnvironment environment, int poolSize)
{ {
this.environment = environment;
this.poolSize = poolSize; this.poolSize = poolSize;
} }
@ -80,7 +82,7 @@ namespace Grpc.Core.Internal
{ {
cq.Shutdown(); cq.Shutdown();
Console.WriteLine("Waiting for GPRC threads to finish."); Console.WriteLine("Waiting for GRPC threads to finish.");
foreach (var thread in threads) foreach (var thread in threads)
{ {
thread.Join(); thread.Join();
@ -122,7 +124,7 @@ namespace Grpc.Core.Internal
IntPtr tag = ev.tag; IntPtr tag = ev.tag;
try try
{ {
var callback = GrpcEnvironment.CompletionRegistry.Extract(tag); var callback = environment.CompletionRegistry.Extract(tag);
callback(success); callback(success);
} }
catch (Exception e) catch (Exception e)

@ -42,7 +42,7 @@ namespace Grpc.Core.Internal
{ {
internal interface IServerCallHandler internal interface IServerCallHandler
{ {
Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq); Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment);
} }
internal class UnaryServerCallHandler<TRequest, TResponse> : IServerCallHandler internal class UnaryServerCallHandler<TRequest, TResponse> : IServerCallHandler
@ -58,11 +58,12 @@ namespace Grpc.Core.Internal
this.handler = handler; this.handler = handler;
} }
public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq) public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
{ {
var asyncCall = new AsyncCallServer<TRequest, TResponse>( var asyncCall = new AsyncCallServer<TRequest, TResponse>(
method.ResponseMarshaller.Serializer, method.ResponseMarshaller.Serializer,
method.RequestMarshaller.Deserializer); method.RequestMarshaller.Deserializer,
environment);
asyncCall.Initialize(call); asyncCall.Initialize(call);
var finishedTask = asyncCall.ServerSideCallAsync(); var finishedTask = asyncCall.ServerSideCallAsync();
@ -110,11 +111,12 @@ namespace Grpc.Core.Internal
this.handler = handler; this.handler = handler;
} }
public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq) public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
{ {
var asyncCall = new AsyncCallServer<TRequest, TResponse>( var asyncCall = new AsyncCallServer<TRequest, TResponse>(
method.ResponseMarshaller.Serializer, method.ResponseMarshaller.Serializer,
method.RequestMarshaller.Deserializer); method.RequestMarshaller.Deserializer,
environment);
asyncCall.Initialize(call); asyncCall.Initialize(call);
var finishedTask = asyncCall.ServerSideCallAsync(); var finishedTask = asyncCall.ServerSideCallAsync();
@ -163,11 +165,12 @@ namespace Grpc.Core.Internal
this.handler = handler; this.handler = handler;
} }
public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq) public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
{ {
var asyncCall = new AsyncCallServer<TRequest, TResponse>( var asyncCall = new AsyncCallServer<TRequest, TResponse>(
method.ResponseMarshaller.Serializer, method.ResponseMarshaller.Serializer,
method.RequestMarshaller.Deserializer); method.RequestMarshaller.Deserializer,
environment);
asyncCall.Initialize(call); asyncCall.Initialize(call);
var finishedTask = asyncCall.ServerSideCallAsync(); var finishedTask = asyncCall.ServerSideCallAsync();
@ -219,11 +222,12 @@ namespace Grpc.Core.Internal
this.handler = handler; this.handler = handler;
} }
public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq) public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
{ {
var asyncCall = new AsyncCallServer<TRequest, TResponse>( var asyncCall = new AsyncCallServer<TRequest, TResponse>(
method.ResponseMarshaller.Serializer, method.ResponseMarshaller.Serializer,
method.RequestMarshaller.Deserializer); method.RequestMarshaller.Deserializer,
environment);
asyncCall.Initialize(call); asyncCall.Initialize(call);
var finishedTask = asyncCall.ServerSideCallAsync(); var finishedTask = asyncCall.ServerSideCallAsync();
@ -255,11 +259,11 @@ namespace Grpc.Core.Internal
internal class NoSuchMethodCallHandler : IServerCallHandler internal class NoSuchMethodCallHandler : IServerCallHandler
{ {
public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq) public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
{ {
// We don't care about the payload type here. // We don't care about the payload type here.
var asyncCall = new AsyncCallServer<byte[], byte[]>( var asyncCall = new AsyncCallServer<byte[], byte[]>(
(payload) => payload, (payload) => payload); (payload) => payload, (payload) => payload, environment);
asyncCall.Initialize(call); asyncCall.Initialize(call);
var finishedTask = asyncCall.ServerSideCallAsync(); var finishedTask = asyncCall.ServerSideCallAsync();

@ -91,19 +91,19 @@ namespace Grpc.Core.Internal
{ {
grpcsharp_server_start(this); grpcsharp_server_start(this);
} }
public void ShutdownAndNotify(CompletionQueueSafeHandle cq, BatchCompletionDelegate callback) public void ShutdownAndNotify(BatchCompletionDelegate callback, GrpcEnvironment environment)
{ {
var ctx = BatchContextSafeHandle.Create(); var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback); environment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_server_shutdown_and_notify_callback(this, cq, ctx); grpcsharp_server_shutdown_and_notify_callback(this, environment.CompletionQueue, ctx);
} }
public void RequestCall(CompletionQueueSafeHandle cq, BatchCompletionDelegate callback) public void RequestCall(BatchCompletionDelegate callback, GrpcEnvironment environment)
{ {
var ctx = BatchContextSafeHandle.Create(); var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback); environment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_server_request_call(this, cq, ctx).CheckOk(); grpcsharp_server_request_call(this, environment.CompletionQueue, ctx).CheckOk();
} }
protected override bool ReleaseHandle() protected override bool ReleaseHandle()

@ -52,6 +52,7 @@ namespace Grpc.Core
/// </summary> /// </summary>
public const int PickUnusedPort = 0; public const int PickUnusedPort = 0;
readonly GrpcEnvironment environment;
readonly ServerSafeHandle handle; readonly ServerSafeHandle handle;
readonly object myLock = new object(); readonly object myLock = new object();
@ -67,9 +68,10 @@ namespace Grpc.Core
/// <param name="options">Channel options.</param> /// <param name="options">Channel options.</param>
public Server(IEnumerable<ChannelOption> options = null) public Server(IEnumerable<ChannelOption> options = null)
{ {
this.environment = GrpcEnvironment.GetInstance();
using (var channelArgs = ChannelOptions.CreateChannelArgs(options)) using (var channelArgs = ChannelOptions.CreateChannelArgs(options))
{ {
this.handle = ServerSafeHandle.NewServer(GetCompletionQueue(), channelArgs); this.handle = ServerSafeHandle.NewServer(environment.CompletionQueue, channelArgs);
} }
} }
@ -144,7 +146,7 @@ namespace Grpc.Core
shutdownRequested = true; shutdownRequested = true;
} }
handle.ShutdownAndNotify(GetCompletionQueue(), HandleServerShutdown); handle.ShutdownAndNotify(HandleServerShutdown, environment);
await shutdownTcs.Task; await shutdownTcs.Task;
handle.Dispose(); handle.Dispose();
} }
@ -173,7 +175,7 @@ namespace Grpc.Core
shutdownRequested = true; shutdownRequested = true;
} }
handle.ShutdownAndNotify(GetCompletionQueue(), HandleServerShutdown); handle.ShutdownAndNotify(HandleServerShutdown, environment);
handle.CancelAllCalls(); handle.CancelAllCalls();
await shutdownTcs.Task; await shutdownTcs.Task;
handle.Dispose(); handle.Dispose();
@ -208,7 +210,7 @@ namespace Grpc.Core
{ {
if (!shutdownRequested) if (!shutdownRequested)
{ {
handle.RequestCall(GetCompletionQueue(), HandleNewServerRpc); handle.RequestCall(HandleNewServerRpc, environment);
} }
} }
} }
@ -225,7 +227,7 @@ namespace Grpc.Core
{ {
callHandler = new NoSuchMethodCallHandler(); callHandler = new NoSuchMethodCallHandler();
} }
await callHandler.HandleCall(method, call, GetCompletionQueue()); await callHandler.HandleCall(method, call, environment);
} }
catch (Exception e) catch (Exception e)
{ {
@ -259,10 +261,5 @@ namespace Grpc.Core
{ {
shutdownTcs.SetResult(null); shutdownTcs.SetResult(null);
} }
private static CompletionQueueSafeHandle GetCompletionQueue()
{
return GrpcEnvironment.ThreadPool.CompletionQueue;
}
} }
} }

@ -39,8 +39,6 @@ namespace math
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
GrpcEnvironment.Initialize();
using (Channel channel = new Channel("127.0.0.1", 23456)) using (Channel channel = new Channel("127.0.0.1", 23456))
{ {
Math.IMathClient stub = new Math.MathClient(channel); Math.IMathClient stub = new Math.MathClient(channel);

@ -42,8 +42,6 @@ namespace math
{ {
string host = "0.0.0.0"; string host = "0.0.0.0";
GrpcEnvironment.Initialize();
Server server = new Server(); Server server = new Server();
server.AddServiceDefinition(Math.BindService(new MathServiceImpl())); server.AddServiceDefinition(Math.BindService(new MathServiceImpl()));
int port = server.AddListeningPort(host, 23456); int port = server.AddListeningPort(host, 23456);

@ -54,8 +54,6 @@ namespace math.Tests
[TestFixtureSetUp] [TestFixtureSetUp]
public void Init() public void Init()
{ {
GrpcEnvironment.Initialize();
server = new Server(); server = new Server();
server.AddServiceDefinition(Math.BindService(new MathServiceImpl())); server.AddServiceDefinition(Math.BindService(new MathServiceImpl()));
int port = server.AddListeningPort(host, Server.PickUnusedPort); int port = server.AddListeningPort(host, Server.PickUnusedPort);
@ -75,7 +73,6 @@ namespace math.Tests
public void Cleanup() public void Cleanup()
{ {
channel.Dispose(); channel.Dispose();
server.ShutdownAsync().Wait(); server.ShutdownAsync().Wait();
GrpcEnvironment.Shutdown(); GrpcEnvironment.Shutdown();
} }

@ -102,8 +102,6 @@ namespace Grpc.IntegrationTesting
private void Run() private void Run()
{ {
GrpcEnvironment.Initialize();
Credentials credentials = null; Credentials credentials = null;
if (options.useTls) if (options.useTls)
{ {
@ -135,7 +133,6 @@ namespace Grpc.IntegrationTesting
TestService.ITestServiceClient client = new TestService.TestServiceClient(channel, stubConfig); TestService.ITestServiceClient client = new TestService.TestServiceClient(channel, stubConfig);
RunTestCase(options.testCase, client); RunTestCase(options.testCase, client);
} }
GrpcEnvironment.Shutdown(); GrpcEnvironment.Shutdown();
} }

@ -55,8 +55,6 @@ namespace Grpc.IntegrationTesting
[TestFixtureSetUp] [TestFixtureSetUp]
public void Init() public void Init()
{ {
GrpcEnvironment.Initialize();
server = new Server(); server = new Server();
server.AddServiceDefinition(TestService.BindService(new TestServiceImpl())); server.AddServiceDefinition(TestService.BindService(new TestServiceImpl()));
int port = server.AddListeningPort(host, Server.PickUnusedPort, TestCredentials.CreateTestServerCredentials()); int port = server.AddListeningPort(host, Server.PickUnusedPort, TestCredentials.CreateTestServerCredentials());
@ -74,7 +72,6 @@ namespace Grpc.IntegrationTesting
public void Cleanup() public void Cleanup()
{ {
channel.Dispose(); channel.Dispose();
server.ShutdownAsync().Wait(); server.ShutdownAsync().Wait();
GrpcEnvironment.Shutdown(); GrpcEnvironment.Shutdown();
} }

@ -88,8 +88,6 @@ namespace Grpc.IntegrationTesting
private void Run() private void Run()
{ {
GrpcEnvironment.Initialize();
var server = new Server(); var server = new Server();
server.AddServiceDefinition(TestService.BindService(new TestServiceImpl())); server.AddServiceDefinition(TestService.BindService(new TestServiceImpl()));

Loading…
Cancel
Save