From b574111d1157fc716690c7cdf590af22127ad09e Mon Sep 17 00:00:00 2001 From: Roger Barton Date: Fri, 1 May 2020 18:10:39 +0200 Subject: [PATCH 1/2] Small threading fix, delay to main thread Previously when calling a function on a worker thread and encountering a load error, pausing would trigger a exception as we use the Unity API on a worker thread. This is only for Lazy mode, where the thread safety is not yet fully implemented. --- scripts/DllManipulator.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/DllManipulator.cs b/scripts/DllManipulator.cs index e61840d..f614fe4 100644 --- a/scripts/DllManipulator.cs +++ b/scripts/DllManipulator.cs @@ -503,7 +503,10 @@ internal static void LoadTargetFunction(NativeFunction nativeFunction, bool igno if (!ignoreLoadError) { dll.loadingError = true; - Prop_EditorApplication_isPaused.Value?.SetValue(null, true); + if (Thread.CurrentThread.ManagedThreadId == _unityMainThreadId) // Pause directly if on main thread, else add to queue + Prop_EditorApplication_isPaused.Value?.SetValue(null, true); + else + DllManipulatorScript.MainThreadTriggerQueue.Enqueue(() => { Prop_EditorApplication_isPaused.Value?.SetValue(null, true); }); throw new NativeDllException($"Could not load DLL \"{dll.name}\" at path \"{dll.path}\"."); } @@ -529,7 +532,10 @@ internal static void LoadTargetFunction(NativeFunction nativeFunction, bool igno if (!ignoreLoadError) { dll.symbolError = true; - Prop_EditorApplication_isPaused.Value?.SetValue(null, true); + if (Thread.CurrentThread.ManagedThreadId == _unityMainThreadId) // Pause directly if on main thread, else add to queue + Prop_EditorApplication_isPaused.Value?.SetValue(null, true); + else + DllManipulatorScript.MainThreadTriggerQueue.Enqueue(() => { Prop_EditorApplication_isPaused.Value?.SetValue(null, true); }); throw new NativeDllException($"Could not get address of symbol \"{nativeFunction.identity.symbol}\" in DLL \"{dll.name}\" at path \"{dll.path}\"."); } From 91823c921fde8ad7b21a82342c02828adb79023b Mon Sep 17 00:00:00 2001 From: Roger Barton Date: Fri, 1 May 2020 19:21:39 +0200 Subject: [PATCH 2/2] Extract DispatchOnMainThread --- scripts/DllManipulator.cs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/scripts/DllManipulator.cs b/scripts/DllManipulator.cs index f614fe4..757574d 100644 --- a/scripts/DllManipulator.cs +++ b/scripts/DllManipulator.cs @@ -503,10 +503,7 @@ internal static void LoadTargetFunction(NativeFunction nativeFunction, bool igno if (!ignoreLoadError) { dll.loadingError = true; - if (Thread.CurrentThread.ManagedThreadId == _unityMainThreadId) // Pause directly if on main thread, else add to queue - Prop_EditorApplication_isPaused.Value?.SetValue(null, true); - else - DllManipulatorScript.MainThreadTriggerQueue.Enqueue(() => { Prop_EditorApplication_isPaused.Value?.SetValue(null, true); }); + DispatchOnMainThread(() => { Prop_EditorApplication_isPaused.Value?.SetValue(null, true); }); throw new NativeDllException($"Could not load DLL \"{dll.name}\" at path \"{dll.path}\"."); } @@ -532,10 +529,7 @@ internal static void LoadTargetFunction(NativeFunction nativeFunction, bool igno if (!ignoreLoadError) { dll.symbolError = true; - if (Thread.CurrentThread.ManagedThreadId == _unityMainThreadId) // Pause directly if on main thread, else add to queue - Prop_EditorApplication_isPaused.Value?.SetValue(null, true); - else - DllManipulatorScript.MainThreadTriggerQueue.Enqueue(() => { Prop_EditorApplication_isPaused.Value?.SetValue(null, true); }); + DispatchOnMainThread(() => { Prop_EditorApplication_isPaused.Value?.SetValue(null, true); }); throw new NativeDllException($"Could not get address of symbol \"{nativeFunction.identity.symbol}\" in DLL \"{dll.name}\" at path \"{dll.path}\"."); } @@ -574,6 +568,18 @@ private static void InvokeCustomTriggers(List> triggers, methodInfo.Invoke(null, args); } } + + /// + /// Ensure the action is executed on the main thread. Executes immediately if on the main thread already, + /// otherwise the action is added to a queue + /// + private static void DispatchOnMainThread(Action action) + { + if(Thread.CurrentThread.ManagedThreadId == _unityMainThreadId) + action(); + else + DllManipulatorScript.MainThreadTriggerQueue.Enqueue(action); + } /// /// Logs native function's call to file. If that file exists, it is overwritten. One file is maintained for each thread.