Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Threading / Tasks / TaskExceptionHolder.cs / 1305376 / TaskExceptionHolder.cs
// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // TaskExceptionHolder.cs // //[....] // // An abstraction for holding and aggregating exceptions. // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- // Disable the "reference to volatile field not treated as volatile" error. #pragma warning disable 0420 namespace System.Threading.Tasks { using System; using System.Collections.Generic; using System.Diagnostics.Contracts; ////// An exception holder manages a list of exceptions for one particular task. /// It offers the ability to aggregate, but more importantly, also offers intrinsic /// support for propagating unhandled exceptions that are never observed. It does /// this by aggregating and throwing if the holder is ever GC'd without the holder's /// contents ever having been requested (e.g. by a Task.Wait, Task.get_Exception, etc). /// internal class TaskExceptionHolder { private Listm_exceptions; // One or more exceptions to be aggregated. private bool m_isHandled; // Whether the holder was observed. private Task m_task; // The task to which these exceptions belong. /// /// Creates a new holder; it will be registered for finalization. /// /// The task this holder belongs to. internal TaskExceptionHolder(Task task) { Contract.Assert(task != null, "Expected a non-null task."); EnsureADUnloadCallbackRegistered(); m_exceptions = new List(1); m_task = task; } private static volatile bool s_domainUnloadStarted; private static volatile EventHandler s_adUnloadEventHandler; private static void EnsureADUnloadCallbackRegistered() { if (s_adUnloadEventHandler == null && Interlocked.CompareExchange( ref s_adUnloadEventHandler, new EventHandler(AppDomainUnloadCallback), null) == null) { AppDomain.CurrentDomain.DomainUnload += s_adUnloadEventHandler; } } private static void AppDomainUnloadCallback(object sender, EventArgs e) { s_domainUnloadStarted = true; } /// /// A finalizer that repropagates unhandled exceptions. /// ~TaskExceptionHolder() { // Raise unhandled exceptions only when we know that neither the process or nor the appdomain is being torn down. // We need to do this filtering because all TaskExceptionHolders will be finalized during shutdown or unload // regardles of reachability of the task (i.e. even if the user code was about to observe the task's exception), // which can otherwise lead to spurious crashes during shutdown. if (!m_isHandled && !Environment.HasShutdownStarted && !AppDomain.CurrentDomain.IsFinalizingForUnload() && !s_domainUnloadStarted) { // We don't want to crash the finalizer thread if any ThreadAbortExceptions // occur in the list or in any nested AggregateExceptions. // (Don't rethrow ThreadAbortExceptions.) foreach (Exception exp in m_exceptions) { AggregateException aggExp = exp as AggregateException; if (aggExp != null) { AggregateException flattenedAggExp = aggExp.Flatten(); foreach (Exception innerExp in flattenedAggExp.InnerExceptions) { if (innerExp is ThreadAbortException) return; } } else if (exp is ThreadAbortException) { return; } } // We will only propagate if this is truly unhandled. The reason this could // ever occur is somewhat subtle: if a Task's exceptions are observed in some // other finalizer, and the Task was finalized before the holder, the holder // will have been marked as handled before even getting here. // Give users a chance to keep this exception from crashing the process // First, publish the unobserved exception and allow users to observe it AggregateException exceptionToThrow = new AggregateException( Environment.GetResourceString("TaskExceptionHolder_UnhandledException"), m_exceptions); UnobservedTaskExceptionEventArgs ueea = new UnobservedTaskExceptionEventArgs(exceptionToThrow); TaskScheduler.PublishUnobservedTaskException(m_task, ueea); // Now, if we are still unobserved, throw the exception if (!ueea.m_observed) { throw exceptionToThrow; } } } ////// Add an exception to the internal list. This will ensure the holder is /// in the proper state (handled/unhandled) depending on the list's contents. /// /// An exception object (either an Exception or an /// IEnumerable{Exception}) to add to the list. internal void Add(object exceptionObject) { Contract.Assert(exceptionObject != null); Contract.Assert(m_exceptions != null); Contract.Assert(exceptionObject is Exception || exceptionObject is IEnumerable, "TaskExceptionHolder.Add(): Expected Exception or IEnumerable "); Exception exception = exceptionObject as Exception; if (exception != null) m_exceptions.Add(exception); else { IEnumerable exColl = exceptionObject as IEnumerable ; if (exColl != null) m_exceptions.AddRange(exColl); else { throw new ArgumentException(Environment.GetResourceString("TaskExceptionHolder_UnknownExceptionType"), "exceptionObject"); } } // If all of the exceptions are ThreadAbortExceptions and/or // AppDomainUnloadExceptions, we do not want the finalization // probe to propagate them, so we consider the holder to be // handled. If a subsequent exception comes in of a different // kind, we will reactivate the holder. for (int i = 0; i < m_exceptions.Count; i++) { if (m_exceptions[i].GetType() != typeof(ThreadAbortException) && m_exceptions[i].GetType() != typeof(AppDomainUnloadedException)) { MarkAsUnhandled(); break; } else if (i == m_exceptions.Count - 1) { MarkAsHandled(false); } } } /// /// A private helper method that ensures the holder is considered /// unhandled, i.e. it is registered for finalization. /// private void MarkAsUnhandled() { // If a thread partially observed this thread's exceptions, we // should revert back to "not handled" so that subsequent exceptions // must also be seen. Otherwise, some could go missing. We also need // to reregister for finalization. if (m_isHandled) { GC.ReRegisterForFinalize(this); m_isHandled = false; } } ////// A private helper method that ensures the holder is considered /// handled, i.e. it is not registered for finalization. /// /// Whether this is called from the finalizer thread. internal void MarkAsHandled(bool calledFromFinalizer) { if (!m_isHandled) { if (!calledFromFinalizer) { GC.SuppressFinalize(this); } m_isHandled = true; } } ////// Allocates a new aggregate exception and adds the contents of the list to /// it. By calling this method, the holder assumes exceptions to have been /// "observed", such that the finalization check will be subsequently skipped. /// /// Whether this is being called from a finalizer. /// An extra exception to be included (optionally). ///The aggregate exception to throw. internal AggregateException CreateExceptionObject(bool calledFromFinalizer, Exception includeThisException) { Contract.Assert(m_exceptions.Count > 0, "Expected at least one exception."); // Mark as handled and aggregate the exceptions. MarkAsHandled(calledFromFinalizer); Listexceptions = m_exceptions; // If the caller wants a specific exception to be included, add it now. if (includeThisException != null) { exceptions = new List (exceptions); exceptions.Add(includeThisException); } // Manufacture the aggregate. return new AggregateException(exceptions); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // TaskExceptionHolder.cs // // [....] // // An abstraction for holding and aggregating exceptions. // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- // Disable the "reference to volatile field not treated as volatile" error. #pragma warning disable 0420 namespace System.Threading.Tasks { using System; using System.Collections.Generic; using System.Diagnostics.Contracts; ////// An exception holder manages a list of exceptions for one particular task. /// It offers the ability to aggregate, but more importantly, also offers intrinsic /// support for propagating unhandled exceptions that are never observed. It does /// this by aggregating and throwing if the holder is ever GC'd without the holder's /// contents ever having been requested (e.g. by a Task.Wait, Task.get_Exception, etc). /// internal class TaskExceptionHolder { private Listm_exceptions; // One or more exceptions to be aggregated. private bool m_isHandled; // Whether the holder was observed. private Task m_task; // The task to which these exceptions belong. /// /// Creates a new holder; it will be registered for finalization. /// /// The task this holder belongs to. internal TaskExceptionHolder(Task task) { Contract.Assert(task != null, "Expected a non-null task."); EnsureADUnloadCallbackRegistered(); m_exceptions = new List(1); m_task = task; } private static volatile bool s_domainUnloadStarted; private static volatile EventHandler s_adUnloadEventHandler; private static void EnsureADUnloadCallbackRegistered() { if (s_adUnloadEventHandler == null && Interlocked.CompareExchange( ref s_adUnloadEventHandler, new EventHandler(AppDomainUnloadCallback), null) == null) { AppDomain.CurrentDomain.DomainUnload += s_adUnloadEventHandler; } } private static void AppDomainUnloadCallback(object sender, EventArgs e) { s_domainUnloadStarted = true; } /// /// A finalizer that repropagates unhandled exceptions. /// ~TaskExceptionHolder() { // Raise unhandled exceptions only when we know that neither the process or nor the appdomain is being torn down. // We need to do this filtering because all TaskExceptionHolders will be finalized during shutdown or unload // regardles of reachability of the task (i.e. even if the user code was about to observe the task's exception), // which can otherwise lead to spurious crashes during shutdown. if (!m_isHandled && !Environment.HasShutdownStarted && !AppDomain.CurrentDomain.IsFinalizingForUnload() && !s_domainUnloadStarted) { // We don't want to crash the finalizer thread if any ThreadAbortExceptions // occur in the list or in any nested AggregateExceptions. // (Don't rethrow ThreadAbortExceptions.) foreach (Exception exp in m_exceptions) { AggregateException aggExp = exp as AggregateException; if (aggExp != null) { AggregateException flattenedAggExp = aggExp.Flatten(); foreach (Exception innerExp in flattenedAggExp.InnerExceptions) { if (innerExp is ThreadAbortException) return; } } else if (exp is ThreadAbortException) { return; } } // We will only propagate if this is truly unhandled. The reason this could // ever occur is somewhat subtle: if a Task's exceptions are observed in some // other finalizer, and the Task was finalized before the holder, the holder // will have been marked as handled before even getting here. // Give users a chance to keep this exception from crashing the process // First, publish the unobserved exception and allow users to observe it AggregateException exceptionToThrow = new AggregateException( Environment.GetResourceString("TaskExceptionHolder_UnhandledException"), m_exceptions); UnobservedTaskExceptionEventArgs ueea = new UnobservedTaskExceptionEventArgs(exceptionToThrow); TaskScheduler.PublishUnobservedTaskException(m_task, ueea); // Now, if we are still unobserved, throw the exception if (!ueea.m_observed) { throw exceptionToThrow; } } } ////// Add an exception to the internal list. This will ensure the holder is /// in the proper state (handled/unhandled) depending on the list's contents. /// /// An exception object (either an Exception or an /// IEnumerable{Exception}) to add to the list. internal void Add(object exceptionObject) { Contract.Assert(exceptionObject != null); Contract.Assert(m_exceptions != null); Contract.Assert(exceptionObject is Exception || exceptionObject is IEnumerable, "TaskExceptionHolder.Add(): Expected Exception or IEnumerable "); Exception exception = exceptionObject as Exception; if (exception != null) m_exceptions.Add(exception); else { IEnumerable exColl = exceptionObject as IEnumerable ; if (exColl != null) m_exceptions.AddRange(exColl); else { throw new ArgumentException(Environment.GetResourceString("TaskExceptionHolder_UnknownExceptionType"), "exceptionObject"); } } // If all of the exceptions are ThreadAbortExceptions and/or // AppDomainUnloadExceptions, we do not want the finalization // probe to propagate them, so we consider the holder to be // handled. If a subsequent exception comes in of a different // kind, we will reactivate the holder. for (int i = 0; i < m_exceptions.Count; i++) { if (m_exceptions[i].GetType() != typeof(ThreadAbortException) && m_exceptions[i].GetType() != typeof(AppDomainUnloadedException)) { MarkAsUnhandled(); break; } else if (i == m_exceptions.Count - 1) { MarkAsHandled(false); } } } /// /// A private helper method that ensures the holder is considered /// unhandled, i.e. it is registered for finalization. /// private void MarkAsUnhandled() { // If a thread partially observed this thread's exceptions, we // should revert back to "not handled" so that subsequent exceptions // must also be seen. Otherwise, some could go missing. We also need // to reregister for finalization. if (m_isHandled) { GC.ReRegisterForFinalize(this); m_isHandled = false; } } ////// A private helper method that ensures the holder is considered /// handled, i.e. it is not registered for finalization. /// /// Whether this is called from the finalizer thread. internal void MarkAsHandled(bool calledFromFinalizer) { if (!m_isHandled) { if (!calledFromFinalizer) { GC.SuppressFinalize(this); } m_isHandled = true; } } ////// Allocates a new aggregate exception and adds the contents of the list to /// it. By calling this method, the holder assumes exceptions to have been /// "observed", such that the finalization check will be subsequently skipped. /// /// Whether this is being called from a finalizer. /// An extra exception to be included (optionally). ///The aggregate exception to throw. internal AggregateException CreateExceptionObject(bool calledFromFinalizer, Exception includeThisException) { Contract.Assert(m_exceptions.Count > 0, "Expected at least one exception."); // Mark as handled and aggregate the exceptions. MarkAsHandled(calledFromFinalizer); Listexceptions = m_exceptions; // If the caller wants a specific exception to be included, add it now. if (includeThisException != null) { exceptions = new List (exceptions); exceptions.Add(includeThisException); } // Manufacture the aggregate. return new AggregateException(exceptions); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ClientSession.cs
- Italic.cs
- PlainXmlDeserializer.cs
- XamlHostingConfiguration.cs
- DataBinder.cs
- CursorConverter.cs
- Int16AnimationBase.cs
- Path.cs
- ConnectionPoint.cs
- CommentEmitter.cs
- ManagementScope.cs
- CustomTypeDescriptor.cs
- DrawingImage.cs
- Types.cs
- CompilationUtil.cs
- ParagraphResult.cs
- ProvidersHelper.cs
- AppSettingsExpressionBuilder.cs
- InvalidOleVariantTypeException.cs
- BitmapEffectState.cs
- DataControlButton.cs
- ResourceAssociationTypeEnd.cs
- HScrollBar.cs
- HasCopySemanticsAttribute.cs
- Utils.cs
- _OSSOCK.cs
- StaticSiteMapProvider.cs
- Schema.cs
- SqlCachedBuffer.cs
- SoapHeaders.cs
- InternalTransaction.cs
- InkCollectionBehavior.cs
- SettingsPropertyWrongTypeException.cs
- PerformanceCounterPermissionAttribute.cs
- AlignmentYValidation.cs
- RSAOAEPKeyExchangeDeformatter.cs
- ColumnHeaderConverter.cs
- ObjectKeyFrameCollection.cs
- BuildTopDownAttribute.cs
- ListViewSortEventArgs.cs
- WebRequestModulesSection.cs
- EntityTypeEmitter.cs
- BrowserCapabilitiesCompiler.cs
- PrefixQName.cs
- WrapperSecurityCommunicationObject.cs
- ExpandableObjectConverter.cs
- CodeTypeDeclaration.cs
- HtmlInputSubmit.cs
- Application.cs
- BevelBitmapEffect.cs
- Clause.cs
- SystemIPGlobalStatistics.cs
- MenuCommand.cs
- SqlErrorCollection.cs
- EnumMemberAttribute.cs
- CompositionDesigner.cs
- XmlDataSourceNodeDescriptor.cs
- FacetValues.cs
- Evidence.cs
- GeometryHitTestResult.cs
- UnmanagedMemoryStreamWrapper.cs
- DataBoundLiteralControl.cs
- SessionState.cs
- DispatcherSynchronizationContext.cs
- DbParameterCollection.cs
- CaseDesigner.xaml.cs
- TableLayoutStyle.cs
- TextDocumentView.cs
- HttpPostProtocolReflector.cs
- MethodCallTranslator.cs
- BrowserCapabilitiesFactory.cs
- SchemaElementLookUpTable.cs
- DNS.cs
- NamespaceCollection.cs
- InkCanvasFeedbackAdorner.cs
- ToolboxItemCollection.cs
- SmtpNetworkElement.cs
- MediaTimeline.cs
- XmlSchemaIdentityConstraint.cs
- TypeUnloadedException.cs
- DataGridViewLayoutData.cs
- WebPartTracker.cs
- MatrixCamera.cs
- SoundPlayer.cs
- MonitorWrapper.cs
- DocumentViewerBase.cs
- HostVisual.cs
- RangeValueProviderWrapper.cs
- PropertyDescriptorComparer.cs
- NullableDecimalMinMaxAggregationOperator.cs
- Msmq3PoisonHandler.cs
- ClosableStream.cs
- IconEditor.cs
- _SingleItemRequestCache.cs
- SchemaMapping.cs
- DataSvcMapFileSerializer.cs
- PropertyDescriptorCollection.cs
- UrlPath.cs
- HwndProxyElementProvider.cs
- XhtmlConformanceSection.cs