diff options
author | Jan Tattermusch <jtattermusch@google.com> | 2018-08-10 11:21:35 +0200 |
---|---|---|
committer | Jan Tattermusch <jtattermusch@google.com> | 2018-08-10 11:22:12 +0200 |
commit | 69984f66823e67259f422c8ef425329bd52ce6db (patch) | |
tree | 61931625db0b8aef546cafc9a50221a26b67fa3a /src/csharp | |
parent | 753f4dccd60bdb4f5886a866b90fe283bd335e40 (diff) | |
download | grpc-grpc-69984f66823e67259f422c8ef425329bd52ce6db.tar.gz |
C#: avoid shutdown crash on iOS
Diffstat (limited to 'src/csharp')
-rw-r--r-- | src/csharp/Grpc.Core/GrpcEnvironment.cs | 25 |
1 files changed, 24 insertions, 1 deletions
diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs index a6a1d8af50..db0fbb17ad 100644 --- a/src/csharp/Grpc.Core/GrpcEnvironment.cs +++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs @@ -50,6 +50,7 @@ namespace Grpc.Core static int requestCallContextPoolThreadLocalCapacity = DefaultRequestCallContextPoolThreadLocalCapacity; static readonly HashSet<Channel> registeredChannels = new HashSet<Channel>(); static readonly HashSet<Server> registeredServers = new HashSet<Server>(); + volatile static bool alreadyInvokedNativeInit; static ILogger logger = new LogLevelFilterLogger(new ConsoleLogger(), LogLevel.Off, true); @@ -360,12 +361,26 @@ namespace Grpc.Core internal static void GrpcNativeInit() { + if (!IsNativeShutdownAllowed && alreadyInvokedNativeInit) + { + // Normally grpc_init and grpc_shutdown calls should come in pairs (C core does reference counting), + // but in case we avoid grpc_shutdown calls altogether, calling grpc_init has no effect + // besides incrementing an internal C core counter that could theoretically overflow. + // NOTE: synchronization not necessary here as we are only trying to avoid calling grpc_init + // so many times that it would causes an overflow, and thus "alreadyInvokedNativeInit" + // being eventually consistent is good enough. + return; + } NativeMethods.Get().grpcsharp_init(); + alreadyInvokedNativeInit = true; } internal static void GrpcNativeShutdown() { - NativeMethods.Get().grpcsharp_shutdown(); + if (IsNativeShutdownAllowed) + { + NativeMethods.Get().grpcsharp_shutdown(); + } } /// <summary> @@ -411,6 +426,14 @@ namespace Grpc.Core return GetThreadPoolSizeOrDefault(); } + // On some platforms (specifically iOS), thread local variables in native code + // require initialization/destruction. By skipping the grpc_shutdown() call, + // we avoid a potential crash where grpc_shutdown() has already destroyed + // the thread local variables, but some C core's *_destroy() methods still + // need to run (e.g. they may be run by finalizer thread which is out of our control) + // For more context, see https://github.com/grpc/grpc/issues/16294 + private static bool IsNativeShutdownAllowed => !PlatformApis.IsXamarinIOS && !PlatformApis.IsUnityIOS; + private static class ShutdownHooks { static object staticLock = new object(); |