Skip to content

Commit 3afab70

Browse files
committed
fix: added mutexes to delegate marshalling
1 parent 9ebc99a commit 3afab70

File tree

1 file changed

+55
-33
lines changed

1 file changed

+55
-33
lines changed

managed/Plugify/Marshalling.cs

+55-33
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ public static class Marshalling
99
{
1010
internal static readonly Dictionary<Delegate, JitCallback?> CachedDelegates = new();
1111
internal static readonly Dictionary<nint, Delegate> CachedFunctions = new();
12+
private static readonly Mutex MutexDelegates = new();
13+
private static readonly Mutex MutexFunctions = new();
1214

1315
internal static unsafe object?[]? MarshalParameterArray(nint paramsPtr, int parameterCount, MethodBase methodInfo)
1416
{
@@ -547,28 +549,38 @@ internal static void MarshalFieldAddress(object obj, FieldInfo fieldInfo, nint o
547549

548550
public static Delegate GetDelegateForFunctionPointer(nint funcAddress, Type? delegateType)
549551
{
550-
if (CachedFunctions.TryGetValue(funcAddress, out var d))
551-
{
552-
return d;
553-
}
552+
MutexFunctions.WaitOne();
554553

555-
if (delegateType == null)
554+
try
556555
{
557-
throw new Exception("Type required to properly generate delegate at runtime");
558-
}
556+
if (CachedFunctions.TryGetValue(funcAddress, out var d))
557+
{
558+
return d;
559+
}
559560

560-
MethodInfo methodInfo = delegateType.GetMethod("Invoke")!;
561-
if (IsNeedMarshal(methodInfo.ReturnType) || methodInfo.GetParameters().Any(p => IsNeedMarshal(p.ParameterType)))
562-
{
563-
d = MethodUtils.CreateObjectArrayDelegate(delegateType, ExternalInvoke(funcAddress, methodInfo));
561+
if (delegateType == null)
562+
{
563+
throw new Exception("Type required to properly generate delegate at runtime");
564+
}
565+
566+
MethodInfo methodInfo = delegateType.GetMethod("Invoke")!;
567+
if (IsNeedMarshal(methodInfo.ReturnType) ||
568+
methodInfo.GetParameters().Any(p => IsNeedMarshal(p.ParameterType)))
569+
{
570+
d = MethodUtils.CreateObjectArrayDelegate(delegateType, ExternalInvoke(funcAddress, methodInfo));
571+
}
572+
else
573+
{
574+
d = Marshal.GetDelegateForFunctionPointer(funcAddress, delegateType);
575+
}
576+
577+
CachedFunctions.Add(funcAddress, d);
578+
return d;
564579
}
565-
else
580+
finally
566581
{
567-
d = Marshal.GetDelegateForFunctionPointer(funcAddress, delegateType);
582+
MutexFunctions.ReleaseMutex();
568583
}
569-
570-
CachedFunctions.Add(funcAddress, d);
571-
return d;
572584
}
573585

574586
private static unsafe nint RCast<T>(T primitive) where T : struct
@@ -1564,29 +1576,39 @@ private static unsafe void DestroyStorage((nint, ValueType)* handlers, int count
15641576

15651577
public static nint GetFunctionPointerForDelegate(Delegate d)
15661578
{
1567-
if (CachedDelegates.TryGetValue(d, out var callback))
1568-
{
1569-
return callback?.Function ?? Marshal.GetFunctionPointerForDelegate(d);
1570-
}
1579+
MutexDelegates.WaitOne();
15711580

1572-
MethodInfo methodInfo = d.Method;
1573-
if (IsNeedMarshal(methodInfo.ReturnType) || methodInfo.GetParameters().Any(p => IsNeedMarshal(p.ParameterType)))
1581+
try
15741582
{
1575-
callback = new JitCallback(d);
1583+
if (CachedDelegates.TryGetValue(d, out var callback))
1584+
{
1585+
return callback?.Function ?? Marshal.GetFunctionPointerForDelegate(d);
1586+
}
15761587

1577-
nint function = callback.Function;
1578-
if (function == nint.Zero)
1588+
MethodInfo methodInfo = d.Method;
1589+
if (IsNeedMarshal(methodInfo.ReturnType) ||
1590+
methodInfo.GetParameters().Any(p => IsNeedMarshal(p.ParameterType)))
15791591
{
1580-
throw new InvalidOperationException($"{methodInfo.Name} (jit error: {callback.Error})");
1592+
callback = new JitCallback(d);
1593+
1594+
nint function = callback.Function;
1595+
if (function == nint.Zero)
1596+
{
1597+
throw new InvalidOperationException($"{methodInfo.Name} (jit error: {callback.Error})");
1598+
}
1599+
1600+
CachedDelegates.Add(d, callback);
1601+
return function;
15811602
}
1582-
1583-
CachedDelegates.Add(d, callback);
1584-
return function;
1585-
}
15861603

1587-
// We must manually keep the delegate from being collected by the garbage collector from managed code.
1588-
CachedDelegates.Add(d, null);
1589-
return Marshal.GetFunctionPointerForDelegate(d);
1604+
// We must manually keep the delegate from being collected by the garbage collector from managed code.
1605+
CachedDelegates.Add(d, null);
1606+
return Marshal.GetFunctionPointerForDelegate(d);
1607+
}
1608+
finally
1609+
{
1610+
MutexDelegates.ReleaseMutex();
1611+
}
15901612
}
15911613

15921614
private static bool IsNeedMarshal(Type paramType)

0 commit comments

Comments
 (0)