1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
10 using System.Diagnostics;
11 using System.Runtime.CompilerServices;
12 using System.Runtime.InteropServices;
14 #if FEATURE_COMINTEROP
15 using System.Runtime.InteropServices.WindowsRuntime;
17 using WFD = Windows.Foundation.Diagnostics;
21 namespace System.Threading.Tasks
23 // [FriendAccessAllowed]
24 internal enum CausalityTraceLevel
26 #if FEATURE_COMINTEROP
27 Required = WFD.CausalityTraceLevel.Required,
28 Important = WFD.CausalityTraceLevel.Important,
29 Verbose = WFD.CausalityTraceLevel.Verbose
37 // [FriendAccessAllowed]
38 internal enum AsyncCausalityStatus
40 #if FEATURE_COMINTEROP
41 Canceled = WFD.AsyncCausalityStatus.Canceled,
42 Completed = WFD.AsyncCausalityStatus.Completed,
43 Error = WFD.AsyncCausalityStatus.Error,
44 Started = WFD.AsyncCausalityStatus.Started
53 internal enum CausalityRelation
55 #if FEATURE_COMINTEROP
56 AssignDelegate = WFD.CausalityRelation.AssignDelegate,
57 Join = WFD.CausalityRelation.Join,
58 Choice = WFD.CausalityRelation.Choice,
59 Cancel = WFD.CausalityRelation.Cancel,
60 Error = WFD.CausalityRelation.Error
70 internal enum CausalitySynchronousWork
72 #if FEATURE_COMINTEROP
73 CompletionNotification = WFD.CausalitySynchronousWork.CompletionNotification,
74 ProgressNotification = WFD.CausalitySynchronousWork.ProgressNotification,
75 Execution = WFD.CausalitySynchronousWork.Execution
77 CompletionNotification,
83 // [FriendAccessAllowed]
84 internal static class AsyncCausalityTracer
86 static internal void EnableToETW(bool enabled)
88 #if FEATURE_COMINTEROP
90 f_LoggingOn |= Loggers.ETW;
92 f_LoggingOn &= ~Loggers.ETW;
96 internal static bool LoggingOn
98 // [FriendAccessAllowed]
101 #if FEATURE_COMINTEROP
102 return f_LoggingOn != 0;
109 #if FEATURE_COMINTEROP
110 //s_PlatformId = {4B0171A6-F3D0-41A0-9B33-02550652B995}
111 private static readonly Guid s_PlatformId = new Guid(0x4B0171A6, 0xF3D0, 0x41A0, 0x9B, 0x33, 0x02, 0x55, 0x06, 0x52, 0xB9, 0x95);
113 //Indicates this information comes from the BCL Library
114 private const WFD.CausalitySource s_CausalitySource = WFD.CausalitySource.Library;
116 //Lazy initialize the actual factory
117 private static WFD.IAsyncCausalityTracerStatics s_TracerFactory;
119 // The loggers that this Tracer knows about.
121 private enum Loggers : byte
128 //We receive the actual value for these as a callback
129 private static Loggers f_LoggingOn; //assumes false by default
131 // The precise static constructor will run first time somebody attempts to access this class
132 static AsyncCausalityTracer()
134 if (!Environment.IsWinRTSupported) return;
137 string ClassId = "Windows.Foundation.Diagnostics.AsyncCausalityTracer";
139 //COM Interface GUID {50850B26-267E-451B-A890-AB6A370245EE}
140 Guid guid = new Guid(0x50850B26, 0x267E, 0x451B, 0xA8, 0x90, 0XAB, 0x6A, 0x37, 0x02, 0x45, 0xEE);
142 Object factory = null;
146 int hresult = Microsoft.Win32.UnsafeNativeMethods.RoGetActivationFactory(ClassId, ref guid, out factory);
148 if (hresult < 0 || factory == null) return; //This prevents having an exception thrown in case IAsyncCausalityTracerStatics isn't registered.
150 s_TracerFactory = (WFD.IAsyncCausalityTracerStatics)factory;
152 EventRegistrationToken token = s_TracerFactory.add_TracingStatusChanged(new EventHandler<WFD.TracingStatusChangedEventArgs>(TracingStatusChangedHandler));
153 Debug.Assert(token != default(EventRegistrationToken), "EventRegistrationToken is null");
157 // Although catching generic Exception is not recommended, this file is one exception
158 // since we don't want to propagate any kind of exception to the user since all we are
159 // doing here depends on internal state.
164 private static void TracingStatusChangedHandler(Object sender, WFD.TracingStatusChangedEventArgs args)
167 f_LoggingOn |= Loggers.CausalityTracer;
169 f_LoggingOn &= ~Loggers.CausalityTracer;
174 // The TraceXXX methods should be called only if LoggingOn property returned true
177 // [FriendAccessAllowed]
178 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Tracking is slow path. Disable inlining for it.
179 internal static void TraceOperationCreation(CausalityTraceLevel traceLevel, int taskId, string operationName, ulong relatedContext)
181 #if FEATURE_COMINTEROP
184 if ((f_LoggingOn & Loggers.ETW) != 0)
185 TplEtwProvider.Log.TraceOperationBegin(taskId, operationName, (long)relatedContext);
186 if ((f_LoggingOn & Loggers.CausalityTracer) != 0)
187 s_TracerFactory.TraceOperationCreation((WFD.CausalityTraceLevel)traceLevel, s_CausalitySource, s_PlatformId, GetOperationId((uint)taskId), operationName, relatedContext);
191 //view function comment
197 // [FriendAccessAllowed]
198 [MethodImplAttribute(MethodImplOptions.NoInlining)]
199 internal static void TraceOperationCompletion(CausalityTraceLevel traceLevel, int taskId, AsyncCausalityStatus status)
201 #if FEATURE_COMINTEROP
204 if ((f_LoggingOn & Loggers.ETW) != 0)
205 TplEtwProvider.Log.TraceOperationEnd(taskId, status);
206 if ((f_LoggingOn & Loggers.CausalityTracer) != 0)
207 s_TracerFactory.TraceOperationCompletion((WFD.CausalityTraceLevel)traceLevel, s_CausalitySource, s_PlatformId, GetOperationId((uint)taskId), (WFD.AsyncCausalityStatus)status);
211 //view function comment
217 [MethodImplAttribute(MethodImplOptions.NoInlining)]
218 internal static void TraceOperationRelation(CausalityTraceLevel traceLevel, int taskId, CausalityRelation relation)
220 #if FEATURE_COMINTEROP
223 if ((f_LoggingOn & Loggers.ETW) != 0)
224 TplEtwProvider.Log.TraceOperationRelation(taskId, relation);
225 if ((f_LoggingOn & Loggers.CausalityTracer) != 0)
226 s_TracerFactory.TraceOperationRelation((WFD.CausalityTraceLevel)traceLevel, s_CausalitySource, s_PlatformId, GetOperationId((uint)taskId), (WFD.CausalityRelation)relation);
230 //view function comment
236 [MethodImplAttribute(MethodImplOptions.NoInlining)]
237 internal static void TraceSynchronousWorkStart(CausalityTraceLevel traceLevel, int taskId, CausalitySynchronousWork work)
239 #if FEATURE_COMINTEROP
242 if ((f_LoggingOn & Loggers.ETW) != 0)
243 TplEtwProvider.Log.TraceSynchronousWorkBegin(taskId, work);
244 if ((f_LoggingOn & Loggers.CausalityTracer) != 0)
245 s_TracerFactory.TraceSynchronousWorkStart((WFD.CausalityTraceLevel)traceLevel, s_CausalitySource, s_PlatformId, GetOperationId((uint)taskId), (WFD.CausalitySynchronousWork)work);
249 //view function comment
255 [MethodImplAttribute(MethodImplOptions.NoInlining)]
256 internal static void TraceSynchronousWorkCompletion(CausalityTraceLevel traceLevel, CausalitySynchronousWork work)
258 #if FEATURE_COMINTEROP
261 if ((f_LoggingOn & Loggers.ETW) != 0)
262 TplEtwProvider.Log.TraceSynchronousWorkEnd(work);
263 if ((f_LoggingOn & Loggers.CausalityTracer) != 0)
264 s_TracerFactory.TraceSynchronousWorkCompletion((WFD.CausalityTraceLevel)traceLevel, s_CausalitySource, (WFD.CausalitySynchronousWork)work);
268 //view function comment
274 #if FEATURE_COMINTEROP
275 //fix for 796185: leaking internal exceptions to customers,
276 //we should catch and log exceptions but never propagate them.
277 private static void LogAndDisable(Exception ex)
280 Debugger.Log(0, "AsyncCausalityTracer", ex.ToString());
284 private static ulong GetOperationId(uint taskId)
286 return (((ulong)AppDomain.CurrentDomain.Id) << 32) + taskId;