1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*=============================================================================
**
** File: ExceptionServicesCommon.cs
**
**
** Purpose: Contains common usage support entities for advanced exception
** handling/processing scenarios.
**
** Created: 11/2/2010
**
** <owner>Microsoft</owner>
**
=============================================================================*/
#if FEATURE_EXCEPTIONDISPATCHINFO
namespace System.Runtime.ExceptionServices {
using System;
// This class defines support for seperating the exception dispatch details
// (like stack trace, watson buckets, etc) from the actual managed exception
// object. This allows us to track error (via the exception object) independent
// of the path the error takes.
//
// This is particularly useful for frameworks like PFX, APM, etc that wish to
// propagate exceptions (i.e. errors to be precise) across threads.
public sealed class ExceptionDispatchInfo
{
// Private members that will hold the relevant details.
private Exception m_Exception;
#if !MONO
private string m_remoteStackTrace;
#endif
private object m_stackTrace;
#if !MONO
private object m_dynamicMethods;
private UIntPtr m_IPForWatsonBuckets;
private Object m_WatsonBuckets;
#endif
private ExceptionDispatchInfo(Exception exception)
{
// Copy over the details we need to save.
m_Exception = exception;
#if MONO
var traces = exception.captured_traces;
var count = traces == null ? 0 : traces.Length;
var stack_traces = new System.Diagnostics.StackTrace [count + 1];
if (count != 0)
Array.Copy (traces, 0, stack_traces, 0, count);
stack_traces [count] = new System.Diagnostics.StackTrace (exception, 0, true);
m_stackTrace = stack_traces;
#else
m_remoteStackTrace = exception.RemoteStackTrace;
// NOTE: don't be tempted to pass the fields for the out params; the containing object
// might be relocated during the call so the pointers will no longer be valid.
object stackTrace;
object dynamicMethods;
m_Exception.GetStackTracesDeepCopy(out stackTrace, out dynamicMethods);
m_stackTrace = stackTrace;
m_dynamicMethods = dynamicMethods;
m_IPForWatsonBuckets = exception.IPForWatsonBuckets;
m_WatsonBuckets = exception.WatsonBuckets;
#endif
}
#if !MONO
internal UIntPtr IPForWatsonBuckets
{
get
{
return m_IPForWatsonBuckets;
}
}
internal object WatsonBuckets
{
get
{
return m_WatsonBuckets;
}
}
#endif
internal object BinaryStackTraceArray
{
get
{
return m_stackTrace;
}
}
#if !MONO
internal object DynamicMethodArray
{
get
{
return m_dynamicMethods;
}
}
internal string RemoteStackTrace
{
get
{
return m_remoteStackTrace;
}
}
#endif
// This static method is used to create an instance of ExceptionDispatchInfo for
// the specified exception object and save all the required details that maybe
// needed to be propagated when the exception is "rethrown" on a different thread.
public static ExceptionDispatchInfo Capture(Exception source)
{
if (source == null)
{
throw new ArgumentNullException("source", Environment.GetResourceString("ArgumentNull_Obj"));
}
return new ExceptionDispatchInfo(source);
}
// Return the exception object represented by this ExceptionDispatchInfo instance
public Exception SourceException
{
get
{
return m_Exception;
}
}
// When a framework needs to "Rethrow" an exception on a thread different (but not necessarily so) from
// where it was thrown, it should invoke this method against the ExceptionDispatchInfo (EDI)
// created for the exception in question.
//
// This method will restore the original stack trace and bucketing details before throwing
// the exception so that it is easy, from debugging standpoint, to understand what really went wrong on
// the original thread.
public void Throw()
{
// Restore the exception dispatch details before throwing the exception.
m_Exception.RestoreExceptionDispatchInfo(this);
throw m_Exception;
}
#if MONO
public static void Throw (Exception source) => Capture (source).Throw ();
#endif
}
}
#endif // FEATURE_EXCEPTIONDISPATCHINFO
|