/// <summary>Interrupts script execution.</summary> /// <remarks>Interrupts script execution.</remarks> private void Interrupted(Context cx, Dim.StackFrame frame, Exception scriptException) { Dim.ContextData contextData = frame.ContextData(); bool eventThreadFlag = callback.IsGuiEventThread(); contextData.eventThreadFlag = eventThreadFlag; bool recursiveEventThreadCall = false; lock (eventThreadMonitor) { if (eventThreadFlag) { if (interruptedContextData != null) { recursiveEventThreadCall = true; goto interruptedCheck_break; } } else { while (interruptedContextData != null) { try { System.Threading.Monitor.Wait(eventThreadMonitor); } catch (Exception) { return; } } } interruptedContextData = contextData; } interruptedCheck_break: ; if (recursiveEventThreadCall) { // XXX: For now the following is commented out as on Linux // too deep recursion of dispatchNextGuiEvent causes GUI lockout. // Note: it can make GUI unresponsive if long-running script // will be called on GUI thread while processing another interrupt if (false) { // Run event dispatch until gui sets a flag to exit the initial // call to interrupted. while (this.returnValue == -1) { try { callback.DispatchNextGuiEvent(); } catch (Exception) { } } } return; } if (interruptedContextData == null) { Kit.CodeBug(); } try { do { int frameCount = contextData.FrameCount(); this.frameIndex = frameCount - 1; string threadTitle = Sharpen.Thread.CurrentThread().ToString(); string alertMessage; if (scriptException == null) { alertMessage = null; } else { alertMessage = scriptException.ToString(); } int returnValue = -1; if (!eventThreadFlag) { lock (monitor) { if (insideInterruptLoop) { Kit.CodeBug(); } this.insideInterruptLoop = true; this.evalRequest = null; this.returnValue = -1; callback.EnterInterrupt(frame, threadTitle, alertMessage); try { for (; ; ) { try { System.Threading.Monitor.Wait(monitor); } catch (Exception) { Sharpen.Thread.CurrentThread().Interrupt(); break; } if (evalRequest != null) { this.evalResult = null; try { evalResult = Do_eval(cx, evalFrame, evalRequest); } finally { evalRequest = null; evalFrame = null; System.Threading.Monitor.Pulse(monitor); } continue; } if (this.returnValue != -1) { returnValue = this.returnValue; break; } } } finally { insideInterruptLoop = false; } } } else { this.returnValue = -1; callback.EnterInterrupt(frame, threadTitle, alertMessage); while (this.returnValue == -1) { try { callback.DispatchNextGuiEvent(); } catch (Exception) { } } returnValue = this.returnValue; } switch (returnValue) { case STEP_OVER: { contextData.breakNextLine = true; contextData.stopAtFrameDepth = contextData.FrameCount(); break; } case STEP_INTO: { contextData.breakNextLine = true; contextData.stopAtFrameDepth = -1; break; } case STEP_OUT: { if (contextData.FrameCount() > 1) { contextData.breakNextLine = true; contextData.stopAtFrameDepth = contextData.FrameCount() - 1; } break; } } } while (false); } finally { lock (eventThreadMonitor) { interruptedContextData = null; System.Threading.Monitor.PulseAll(eventThreadMonitor); } } }
/// <summary>Called when a script exception has been thrown.</summary> /// <remarks>Called when a script exception has been thrown.</remarks> private void HandleExceptionThrown(Context cx, Exception ex, Dim.StackFrame frame) { if (breakOnExceptions) { Dim.ContextData cd = frame.ContextData(); if (cd.lastProcessedException != ex) { Interrupted(cx, frame, ex); cd.lastProcessedException = ex; } } }