|  | @@ -422,9 +422,32 @@ namespace Grpc.Core
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  |                      if (!hooksRegistered)
 | 
	
		
			
				|  |  |                      {
 | 
	
		
			
				|  |  | +                        // Under normal circumstances, the user is expected to shutdown all
 | 
	
		
			
				|  |  | +                        // the gRPC channels and servers before the application exits. The following
 | 
	
		
			
				|  |  | +                        // hooks provide some extra handling for cases when this is not the case,
 | 
	
		
			
				|  |  | +                        // in the effort to achieve a reasonable behavior on shutdown.
 | 
	
		
			
				|  |  |  #if NETSTANDARD1_5
 | 
	
		
			
				|  |  | -                        System.Runtime.Loader.AssemblyLoadContext.Default.Unloading += (assemblyLoadContext) => { HandleShutdown(); };
 | 
	
		
			
				|  |  | +                        // No action required at shutdown on .NET Core
 | 
	
		
			
				|  |  | +                        // - In-progress P/Invoke calls (such as grpc_completion_queue_next) don't seem
 | 
	
		
			
				|  |  | +                        //   to prevent a .NET core application from terminating, so no special handling
 | 
	
		
			
				|  |  | +                        //   is needed.
 | 
	
		
			
				|  |  | +                        // - .NET core doesn't run finalizers on shutdown, so there's no risk of getting
 | 
	
		
			
				|  |  | +                        //   a crash because grpc_*_destroy methods for native objects being invoked
 | 
	
		
			
				|  |  | +                        //   in wrong order.
 | 
	
		
			
				|  |  | +                        // TODO(jtattermusch): Verify that the shutdown hooks are still not needed
 | 
	
		
			
				|  |  | +                        // once we add support for new platforms using netstandard (e.g. Xamarin).
 | 
	
		
			
				|  |  |  #else
 | 
	
		
			
				|  |  | +                        // On desktop .NET framework and Mono, we need to register for a shutdown
 | 
	
		
			
				|  |  | +                        // event to explicitly shutdown the GrpcEnvironment.
 | 
	
		
			
				|  |  | +                        // - On Desktop .NET framework, we need to do a proper shutdown to prevent a crash
 | 
	
		
			
				|  |  | +                        //   when the framework attempts to run the finalizers for SafeHandle object representing the native
 | 
	
		
			
				|  |  | +                        //   grpc objects. The finalizers calls the native grpc_*_destroy methods (e.g. grpc_server_destroy)
 | 
	
		
			
				|  |  | +                        //   in a random order, which is not supported by gRPC.
 | 
	
		
			
				|  |  | +                        // - On Mono, the process would hang as the GrpcThreadPool threads are sleeping
 | 
	
		
			
				|  |  | +                        //   in grpc_completion_queue_next P/Invoke invocation and mono won't let the
 | 
	
		
			
				|  |  | +                        //   process shutdown until the P/Invoke calls return. We achieve that by shutting down
 | 
	
		
			
				|  |  | +                        //   the completion queue(s) which associated with the GrpcThreadPool, which will
 | 
	
		
			
				|  |  | +                        //   cause the grpc_completion_queue_next calls to return immediately.
 | 
	
		
			
				|  |  |                          AppDomain.CurrentDomain.ProcessExit += (sender, eventArgs) => { HandleShutdown(); };
 | 
	
		
			
				|  |  |                          AppDomain.CurrentDomain.DomainUnload += (sender, eventArgs) => { HandleShutdown(); };
 | 
	
		
			
				|  |  |  #endif
 |