aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/csharp/Grpc.Core/GrpcEnvironment.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/csharp/Grpc.Core/GrpcEnvironment.cs')
-rw-r--r--src/csharp/Grpc.Core/GrpcEnvironment.cs24
1 files changed, 23 insertions, 1 deletions
diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index a6a1d8af50..6ca694e0e4 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>();
+ static readonly AtomicCounter nativeInitCounter = new AtomicCounter();
static ILogger logger = new LogLevelFilterLogger(new ConsoleLogger(), LogLevel.Off, true);
@@ -360,12 +361,25 @@ namespace Grpc.Core
internal static void GrpcNativeInit()
{
+ if (!IsNativeShutdownAllowed && nativeInitCounter.Count > 0)
+ {
+ // 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.
+ // To avoid this theoretical possibility we guard repeated calls to grpc_init()
+ // with a 64-bit atomic counter (that can't realistically overflow).
+ return;
+ }
NativeMethods.Get().grpcsharp_init();
+ nativeInitCounter.Increment();
}
internal static void GrpcNativeShutdown()
{
- NativeMethods.Get().grpcsharp_shutdown();
+ if (IsNativeShutdownAllowed)
+ {
+ NativeMethods.Get().grpcsharp_shutdown();
+ }
}
/// <summary>
@@ -411,6 +425,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();