From 8b9caa6cc297ad61c36a11e7184bb60f9fc610ce Mon Sep 17 00:00:00 2001 From: baldurk Date: Sun, 29 Mar 2015 19:59:40 +0100 Subject: [PATCH] When executing python scripts temporarily catch exceptions in renderer * Errors like syntax and runtime errors in python are thrown as exceptions. So for when we invoke onto the renderer thread to do some work, we need to be able to catch those exceptions otherwise the whole program dies. So over the execute, temporarily switch the thread into a catching-exception mode, which then gets rethrown on the invoker's thread. * Note that BeginInvoke shouldn't be used by python since the callback might happen after the execution has finished (there's no way to wait at the moment). --- renderdocui/Code/RenderManager.cs | 30 +++++++++++++++++++++- renderdocui/Windows/Dialogs/PythonShell.cs | 4 +++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/renderdocui/Code/RenderManager.cs b/renderdocui/Code/RenderManager.cs index 5c8aaafdb..256d0fa7c 100644 --- a/renderdocui/Code/RenderManager.cs +++ b/renderdocui/Code/RenderManager.cs @@ -52,6 +52,7 @@ namespace renderdocui.Code public InvokeMethod method; volatile public bool processed; + public Exception ex = null; }; //////////////////////////////////////////// @@ -113,6 +114,14 @@ namespace renderdocui.Code public float LoadProgress; + [ThreadStatic] + private bool CatchExceptions = false; + + public void SetExceptionCatching(bool catching) + { + CatchExceptions = catching; + } + public void BeginInvoke(InvokeMethod m) { InvokeHandle cmd = new InvokeHandle(m); @@ -127,6 +136,9 @@ namespace renderdocui.Code PushInvoke(cmd); while (!cmd.processed) ; + + if (cmd.ex != null) + throw cmd.ex; } private void PushInvoke(InvokeHandle cmd) @@ -204,7 +216,23 @@ namespace renderdocui.Code foreach (var cmd in queue) { if (cmd.method != null) - cmd.method(renderer); + { + if (CatchExceptions) + { + try + { + cmd.method(renderer); + } + catch (Exception ex) + { + cmd.ex = ex; + } + } + else + { + cmd.method(renderer); + } + } cmd.processed = true; } diff --git a/renderdocui/Windows/Dialogs/PythonShell.cs b/renderdocui/Windows/Dialogs/PythonShell.cs index 8db9a5aec..ef11fa78e 100644 --- a/renderdocui/Windows/Dialogs/PythonShell.cs +++ b/renderdocui/Windows/Dialogs/PythonShell.cs @@ -128,7 +128,9 @@ namespace renderdocui.Windows.Dialogs try { + m_Core.Renderer.SetExceptionCatching(true); dynamic ret = engine.CreateScriptSourceFromString(script).Execute(scope); + m_Core.Renderer.SetExceptionCatching(false); if (ret != null) { stdoutwriter.Write(ret.ToString() + Environment.NewLine); @@ -137,6 +139,8 @@ namespace renderdocui.Windows.Dialogs } catch (Exception ex) { + m_Core.Renderer.SetExceptionCatching(false); + // IronPython throws so many exceptions, we don't want to kill the application // so we just swallow Exception to cover all the bases string exstr = engine.GetService().FormatException(ex);