internal static RubyExceptionData /*!*/ AssociateInstance(Exception /*!*/ e) { RubyExceptionData result; Exception visibleException = RubyUtils.GetVisibleException(e); if (e == visibleException || visibleException == null) { result = new RubyExceptionData(e); } else { // Async exception Debug.Assert(e is ThreadAbortException); result = GetInstance(visibleException); if (result._exception == visibleException) { // A different instance of ThreadAbortException is thrown at the end of every catch block (as long as // Thread.ResetAbort is not called). However, we only want to remember the first one // as it will have the most complete stack trace. result._exception = e; } } e.Data[_DataKey] = result; return(result); }
public static void ActiveExceptionHandled(Exception visibleException) { Debug.Assert(RubyUtils.GetVisibleException(visibleException) == visibleException); RubyExceptionData data = RubyExceptionData.GetInstance(visibleException); if (data._exception != visibleException) { // The exception was raised asynchronously with Thread.Abort. We can not just catch and ignore // the ThreadAbortException as the CLR keeps trying to re-raise it unless ResetAbort is called. // // Note that ResetAbort can cause ThreadAbortException.ExceptionState to be cleared (though it may // not be cleared under some circustances), and we use that to squirrel away the Ruby exception // that the user is expecting. Hence, ResetAbort should only be called when // ThreadAbortException.ExceptionState no longer needs to be accessed. if ((Thread.CurrentThread.ThreadState & System.Threading.ThreadState.AbortRequested) != 0) { Thread.ResetAbort(); } } }