|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
//
// <OWNER>AlfreMen</OWNER>
//
using System;
using System.Security;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
#if FEATURE_COMINTEROP
using System.Runtime.InteropServices.WindowsRuntime;
using WFD = Windows.Foundation.Diagnostics;
#endif
namespace System.Threading.Tasks
{
[FriendAccessAllowed]
internal enum CausalityTraceLevel
{
#if FEATURE_COMINTEROP
Required = WFD.CausalityTraceLevel.Required,
Important = WFD.CausalityTraceLevel.Important,
Verbose = WFD.CausalityTraceLevel.Verbose
#else
Required,
Important,
Verbose
#endif
}
[FriendAccessAllowed]
internal enum AsyncCausalityStatus
{
#if FEATURE_COMINTEROP
Canceled = WFD.AsyncCausalityStatus.Canceled,
Completed = WFD.AsyncCausalityStatus.Completed,
Error = WFD.AsyncCausalityStatus.Error,
Started = WFD.AsyncCausalityStatus.Started
#else
Started,
Completed,
Canceled,
Error
#endif
}
internal enum CausalityRelation
{
#if FEATURE_COMINTEROP
AssignDelegate = WFD.CausalityRelation.AssignDelegate,
Join = WFD.CausalityRelation.Join,
Choice = WFD.CausalityRelation.Choice,
Cancel = WFD.CausalityRelation.Cancel,
Error = WFD.CausalityRelation.Error
#else
AssignDelegate,
Join,
Choice,
Cancel,
Error
#endif
}
internal enum CausalitySynchronousWork
{
#if FEATURE_COMINTEROP
CompletionNotification = WFD.CausalitySynchronousWork.CompletionNotification,
ProgressNotification = WFD.CausalitySynchronousWork.ProgressNotification,
Execution = WFD.CausalitySynchronousWork.Execution
#else
CompletionNotification,
ProgressNotification,
Execution
#endif
}
[FriendAccessAllowed]
internal static class AsyncCausalityTracer
{
static internal void EnableToETW(bool enabled)
{
if (enabled)
f_LoggingOn |= Loggers.ETW;
else
f_LoggingOn &= ~Loggers.ETW;
}
[FriendAccessAllowed]
internal static bool LoggingOn
{
[FriendAccessAllowed]
get
{
#if FEATURE_COMINTEROP
return f_LoggingOn != 0;
#else
return false;
#endif
}
}
#if FEATURE_COMINTEROP
//s_PlatformId = {4B0171A6-F3D0-41A0-9B33-02550652B995}
private static readonly Guid s_PlatformId = new Guid(0x4B0171A6, 0xF3D0, 0x41A0, 0x9B, 0x33, 0x02, 0x55, 0x06, 0x52, 0xB9, 0x95);
//Indicates this information comes from the BCL Library
private const WFD.CausalitySource s_CausalitySource = WFD.CausalitySource.Library;
//Lazy initialize the actual factory
private static WFD.IAsyncCausalityTracerStatics s_TracerFactory;
// The loggers that this Tracer knows about.
[Flags]
private enum Loggers : byte {
CausalityTracer = 1,
ETW = 2
}
//We receive the actual value for these as a callback
private static Loggers f_LoggingOn; //assumes false by default
// The precise static constructor will run first time somebody attempts to access this class
[SecuritySafeCritical]
static AsyncCausalityTracer()
{
if (!Environment.IsWinRTSupported) return;
//COM Class Id
string ClassId = "Windows.Foundation.Diagnostics.AsyncCausalityTracer";
//COM Interface GUID {50850B26-267E-451B-A890-AB6A370245EE}
Guid guid = new Guid(0x50850B26, 0x267E, 0x451B, 0xA8, 0x90, 0XAB, 0x6A, 0x37, 0x02, 0x45, 0xEE);
Object factory = null;
try
{
int hresult = Microsoft.Win32.UnsafeNativeMethods.RoGetActivationFactory(ClassId, ref guid, out factory);
if (hresult < 0 || factory == null) return; //This prevents having an exception thrown in case IAsyncCausalityTracerStatics isn't registered.
s_TracerFactory = (WFD.IAsyncCausalityTracerStatics)factory;
EventRegistrationToken token = s_TracerFactory.add_TracingStatusChanged(new EventHandler<WFD.TracingStatusChangedEventArgs>(TracingStatusChangedHandler));
Contract.Assert(token != default(EventRegistrationToken), "EventRegistrationToken is null");
}
catch (Exception ex)
{
// Although catching generic Exception is not recommended, this file is one exception
// since we don't want to propagate any kind of exception to the user since all we are
// doing here depends on internal state.
LogAndDisable(ex);
}
}
[SecuritySafeCritical]
private static void TracingStatusChangedHandler(Object sender, WFD.TracingStatusChangedEventArgs args)
{
if (args.Enabled)
f_LoggingOn |= Loggers.CausalityTracer;
else
f_LoggingOn &= ~Loggers.CausalityTracer;
}
#endif
//
// The TraceXXX methods should be called only if LoggingOn property returned true
//
[FriendAccessAllowed]
[MethodImplAttribute(MethodImplOptions.NoInlining)] // Tracking is slow path. Disable inlining for it.
internal static void TraceOperationCreation(CausalityTraceLevel traceLevel, int taskId, string operationName, ulong relatedContext)
{
#if FEATURE_COMINTEROP
try
{
if ((f_LoggingOn & Loggers.ETW) != 0)
TplEtwProvider.Log.TraceOperationBegin(taskId, operationName, (long) relatedContext);
if ((f_LoggingOn & Loggers.CausalityTracer) != 0)
s_TracerFactory.TraceOperationCreation((WFD.CausalityTraceLevel)traceLevel, s_CausalitySource, s_PlatformId, GetOperationId((uint)taskId), operationName, relatedContext);
}
catch(Exception ex)
{
//view function comment
LogAndDisable(ex);
}
#endif
}
[FriendAccessAllowed]
[MethodImplAttribute(MethodImplOptions.NoInlining)]
internal static void TraceOperationCompletion(CausalityTraceLevel traceLevel, int taskId, AsyncCausalityStatus status)
{
#if FEATURE_COMINTEROP
try
{
if ((f_LoggingOn & Loggers.ETW) != 0)
TplEtwProvider.Log.TraceOperationEnd(taskId, status);
if ((f_LoggingOn & Loggers.CausalityTracer) != 0)
s_TracerFactory.TraceOperationCompletion((WFD.CausalityTraceLevel)traceLevel, s_CausalitySource, s_PlatformId, GetOperationId((uint)taskId), (WFD.AsyncCausalityStatus)status);
}
catch(Exception ex)
{
//view function comment
LogAndDisable(ex);
}
#endif
}
[MethodImplAttribute(MethodImplOptions.NoInlining)]
internal static void TraceOperationRelation(CausalityTraceLevel traceLevel, int taskId, CausalityRelation relation)
{
#if FEATURE_COMINTEROP
try
{
if ((f_LoggingOn & Loggers.ETW) != 0)
TplEtwProvider.Log.TraceOperationRelation(taskId, relation);
if ((f_LoggingOn & Loggers.CausalityTracer) != 0)
s_TracerFactory.TraceOperationRelation((WFD.CausalityTraceLevel)traceLevel, s_CausalitySource, s_PlatformId, GetOperationId((uint)taskId), (WFD.CausalityRelation)relation);
}
catch(Exception ex)
{
//view function comment
LogAndDisable(ex);
}
#endif
}
[MethodImplAttribute(MethodImplOptions.NoInlining)]
internal static void TraceSynchronousWorkStart(CausalityTraceLevel traceLevel, int taskId, CausalitySynchronousWork work)
{
#if FEATURE_COMINTEROP
try
{
if ((f_LoggingOn & Loggers.ETW) != 0)
TplEtwProvider.Log.TraceSynchronousWorkBegin(taskId, work);
if ((f_LoggingOn & Loggers.CausalityTracer) != 0)
s_TracerFactory.TraceSynchronousWorkStart((WFD.CausalityTraceLevel)traceLevel, s_CausalitySource, s_PlatformId, GetOperationId((uint)taskId), (WFD.CausalitySynchronousWork)work);
}
catch(Exception ex)
{
//view function comment
LogAndDisable(ex);
}
#endif
}
[MethodImplAttribute(MethodImplOptions.NoInlining)]
internal static void TraceSynchronousWorkCompletion(CausalityTraceLevel traceLevel, CausalitySynchronousWork work)
{
#if FEATURE_COMINTEROP
try
{
if ((f_LoggingOn & Loggers.ETW) != 0)
TplEtwProvider.Log.TraceSynchronousWorkEnd(work);
if ((f_LoggingOn & Loggers.CausalityTracer) != 0)
s_TracerFactory.TraceSynchronousWorkCompletion((WFD.CausalityTraceLevel)traceLevel, s_CausalitySource, (WFD.CausalitySynchronousWork)work);
}
catch(Exception ex)
{
//view function comment
LogAndDisable(ex);
}
#endif
}
#if FEATURE_COMINTEROP
//fix for 796185: leaking internal exceptions to customers,
//we should catch and log exceptions but never propagate them.
private static void LogAndDisable(Exception ex)
{
f_LoggingOn = 0;
Debugger.Log(0, "AsyncCausalityTracer", ex.ToString());
}
#endif
private static ulong GetOperationId(uint taskId)
{
return (((ulong)AppDomain.CurrentDomain.Id) << 32) + taskId;
}
}
}
|