|  | @@ -35,8 +35,6 @@ namespace Grpc.Core.Internal
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<NativeCallbackDispatcher>();
 | 
	
		
			
				|  |  |          static readonly object staticLock = new object();
 | 
	
		
			
				|  |  | -        static readonly AtomicCounter atomicCounter = new AtomicCounter();
 | 
	
		
			
				|  |  | -        static readonly ConcurrentDictionary<IntPtr, UniversalNativeCallback> registry = new ConcurrentDictionary<IntPtr, UniversalNativeCallback>();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          static NativeCallbackDispatcherCallback dispatcherCallback;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -54,30 +52,14 @@ namespace Grpc.Core.Internal
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          public static NativeCallbackRegistration RegisterCallback(UniversalNativeCallback callback)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            while (true)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                // TODO: retries might not work well on 32-bit
 | 
	
		
			
				|  |  | -                var tag = NextTag();
 | 
	
		
			
				|  |  | -                if (registry.TryAdd(tag, callback))
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    return new NativeCallbackRegistration(tag);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        public static void UnregisterCallback(IntPtr tag)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            registry.TryRemove(tag, out UniversalNativeCallback callback);
 | 
	
		
			
				|  |  | +            var gcHandle = GCHandle.Alloc(callback);
 | 
	
		
			
				|  |  | +            return new NativeCallbackRegistration(gcHandle);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        private static bool TryGetCallback(IntPtr tag, out UniversalNativeCallback callback)
 | 
	
		
			
				|  |  | +        private static UniversalNativeCallback GetCallback(IntPtr tag)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            return registry.TryGetValue(tag, out callback);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        private static IntPtr NextTag()
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            return (IntPtr) atomicCounter.Increment();
 | 
	
		
			
				|  |  | +            var gcHandle = GCHandle.FromIntPtr(tag);
 | 
	
		
			
				|  |  | +            return (UniversalNativeCallback) gcHandle.Target;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          [MonoPInvokeCallback(typeof(NativeCallbackDispatcherCallback))]
 | 
	
	
		
			
				|  | @@ -85,12 +67,7 @@ namespace Grpc.Core.Internal
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              try
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                UniversalNativeCallback callback;
 | 
	
		
			
				|  |  | -                if (!TryGetCallback(tag, out callback))
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    Logger.Error("No native callback handler registered for tag {0}.", tag);
 | 
	
		
			
				|  |  | -                    return 0;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | +                var callback = GetCallback(tag);
 | 
	
		
			
				|  |  |                  return callback(arg0, arg1, arg2, arg3, arg4, arg5);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              catch (Exception e)
 | 
	
	
		
			
				|  | @@ -104,18 +81,21 @@ namespace Grpc.Core.Internal
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      internal class NativeCallbackRegistration : IDisposable
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  | -        readonly IntPtr tag;
 | 
	
		
			
				|  |  | +        readonly GCHandle handle;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        public NativeCallbackRegistration(IntPtr tag)
 | 
	
		
			
				|  |  | +        public NativeCallbackRegistration(GCHandle handle)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            this.tag = tag;
 | 
	
		
			
				|  |  | +            this.handle = handle;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        public IntPtr Tag => tag;
 | 
	
		
			
				|  |  | +        public IntPtr Tag => GCHandle.ToIntPtr(handle);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          public void Dispose()
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            NativeCallbackDispatcher.UnregisterCallback(tag);
 | 
	
		
			
				|  |  | +            if (handle.IsAllocated)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                handle.Free();
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |