mirror of https://github.com/grpc/grpc.git
Merge pull request #18327 from jtattermusch/csharp_unified_native_callbacks
C#: Add NativeCallbackDispatcherpull/18591/head
commit
2780136fcf
9 changed files with 186 additions and 48 deletions
@ -0,0 +1,40 @@ |
|||||||
|
#region Copyright notice and license |
||||||
|
|
||||||
|
// Copyright 2019 The gRPC Authors |
||||||
|
// |
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
// you may not use this file except in compliance with the License. |
||||||
|
// You may obtain a copy of the License at |
||||||
|
// |
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
// |
||||||
|
// Unless required by applicable law or agreed to in writing, software |
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
// See the License for the specific language governing permissions and |
||||||
|
// limitations under the License. |
||||||
|
|
||||||
|
#endregion |
||||||
|
|
||||||
|
using System; |
||||||
|
|
||||||
|
namespace Grpc.Core.Internal |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Use this attribute to mark methods that will be called back from P/Invoke calls. |
||||||
|
/// iOS (and probably other AOT platforms) needs to have delegates registered. |
||||||
|
/// Instead of depending on Xamarin.iOS for this, we can just create our own, |
||||||
|
/// the iOS runtime just checks for the type name. |
||||||
|
/// See: https://docs.microsoft.com/en-gb/xamarin/ios/internals/limitations#reverse-callbacks |
||||||
|
/// </summary> |
||||||
|
[AttributeUsage(AttributeTargets.Method)] |
||||||
|
internal sealed class MonoPInvokeCallbackAttribute : Attribute |
||||||
|
{ |
||||||
|
public MonoPInvokeCallbackAttribute(Type type) |
||||||
|
{ |
||||||
|
Type = type; |
||||||
|
} |
||||||
|
|
||||||
|
public Type Type { get; private set; } |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,91 @@ |
|||||||
|
#region Copyright notice and license |
||||||
|
|
||||||
|
// Copyright 2019 The gRPC Authors |
||||||
|
// |
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
// you may not use this file except in compliance with the License. |
||||||
|
// You may obtain a copy of the License at |
||||||
|
// |
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
// |
||||||
|
// Unless required by applicable law or agreed to in writing, software |
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
// See the License for the specific language governing permissions and |
||||||
|
// limitations under the License. |
||||||
|
|
||||||
|
#endregion |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Concurrent; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.IO; |
||||||
|
using System.Runtime.InteropServices; |
||||||
|
using System.Threading; |
||||||
|
using System.Collections.Generic; |
||||||
|
using Grpc.Core.Logging; |
||||||
|
using Grpc.Core.Utils; |
||||||
|
|
||||||
|
namespace Grpc.Core.Internal |
||||||
|
{ |
||||||
|
internal delegate int UniversalNativeCallback(IntPtr arg0, IntPtr arg1, IntPtr arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5); |
||||||
|
|
||||||
|
internal delegate int NativeCallbackDispatcherCallback(IntPtr tag, IntPtr arg0, IntPtr arg1, IntPtr arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5); |
||||||
|
|
||||||
|
internal class NativeCallbackDispatcher |
||||||
|
{ |
||||||
|
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<NativeCallbackDispatcher>(); |
||||||
|
|
||||||
|
static NativeCallbackDispatcherCallback dispatcherCallback; |
||||||
|
|
||||||
|
public static void Init(NativeMethods native) |
||||||
|
{ |
||||||
|
GrpcPreconditions.CheckState(dispatcherCallback == null); |
||||||
|
dispatcherCallback = new NativeCallbackDispatcherCallback(HandleDispatcherCallback); |
||||||
|
native.grpcsharp_native_callback_dispatcher_init(dispatcherCallback); |
||||||
|
} |
||||||
|
|
||||||
|
public static NativeCallbackRegistration RegisterCallback(UniversalNativeCallback callback) |
||||||
|
{ |
||||||
|
var gcHandle = GCHandle.Alloc(callback); |
||||||
|
return new NativeCallbackRegistration(gcHandle); |
||||||
|
} |
||||||
|
|
||||||
|
[MonoPInvokeCallback(typeof(NativeCallbackDispatcherCallback))] |
||||||
|
private static int HandleDispatcherCallback(IntPtr tag, IntPtr arg0, IntPtr arg1, IntPtr arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
var gcHandle = GCHandle.FromIntPtr(tag); |
||||||
|
var callback = (UniversalNativeCallback) gcHandle.Target; |
||||||
|
return callback(arg0, arg1, arg2, arg3, arg4, arg5); |
||||||
|
} |
||||||
|
catch (Exception e) |
||||||
|
{ |
||||||
|
// eat the exception, we must not throw when inside callback from native code. |
||||||
|
Logger.Error(e, "Caught exception inside callback from native callback."); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal class NativeCallbackRegistration : IDisposable |
||||||
|
{ |
||||||
|
readonly GCHandle handle; |
||||||
|
|
||||||
|
public NativeCallbackRegistration(GCHandle handle) |
||||||
|
{ |
||||||
|
this.handle = handle; |
||||||
|
} |
||||||
|
|
||||||
|
public IntPtr Tag => GCHandle.ToIntPtr(handle); |
||||||
|
|
||||||
|
public void Dispose() |
||||||
|
{ |
||||||
|
if (handle.IsAllocated) |
||||||
|
{ |
||||||
|
handle.Free(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue