|
|
|
@ -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(); |
|
|
|
|