diff options
author | Marek Safar <marek.safar@gmail.com> | 2019-01-22 04:28:13 +0100 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2019-01-21 19:28:13 -0800 |
commit | 5c9febf6346f90c06e70b3cb9e002300e50fa54b (patch) | |
tree | 9f589c28bba076725c51def4d189b7fc814dd4a5 /src/System.Private.CoreLib/shared/System/Threading/Tasks | |
parent | edffbd9c545aa9c1f6cb7ae048efdf5db13d3991 (diff) | |
download | coreclr-5c9febf6346f90c06e70b3cb9e002300e50fa54b.tar.gz coreclr-5c9febf6346f90c06e70b3cb9e002300e50fa54b.tar.bz2 coreclr-5c9febf6346f90c06e70b3cb9e002300e50fa54b.zip |
Move TplEtwProvider to shared partition (#22120)
Diffstat (limited to 'src/System.Private.CoreLib/shared/System/Threading/Tasks')
-rw-r--r-- | src/System.Private.CoreLib/shared/System/Threading/Tasks/TplEtwProvider.cs | 584 |
1 files changed, 584 insertions, 0 deletions
diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TplEtwProvider.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TplEtwProvider.cs new file mode 100644 index 0000000000..311445ec28 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TplEtwProvider.cs @@ -0,0 +1,584 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; +using System.Diagnostics.Tracing; +using Internal.Runtime.CompilerServices; + +namespace System.Threading.Tasks +{ + /// <summary>Provides an event source for tracing TPL information.</summary> + [EventSource( + Name = "System.Threading.Tasks.TplEventSource", + Guid = "2e5dba47-a3d2-4d16-8ee0-6671ffdcd7b5" +#if CORECLR + ,LocalizationResources = "FxResources.System.Private.CoreLib.SR" +#endif + )] + internal sealed class TplEtwProvider : EventSource + { + /// Used to determine if tasks should generate Activity IDs for themselves + internal bool TasksSetActivityIds; // This keyword is set + internal bool Debug; + private bool DebugActivityId; + + private const int DefaultAppDomainID = 1; + + /// <summary> + /// Get callbacks when the ETW sends us commands` + /// </summary> + protected override void OnEventCommand(EventCommandEventArgs command) + { + // To get the AsyncCausality events, we need to inform the AsyncCausalityTracer + if (command.Command == EventCommand.Enable) + AsyncCausalityTracer.EnableToETW(true); + else if (command.Command == EventCommand.Disable) + AsyncCausalityTracer.EnableToETW(false); + + if (IsEnabled(EventLevel.Informational, Keywords.TasksFlowActivityIds)) + ActivityTracker.Instance.Enable(); + else + TasksSetActivityIds = IsEnabled(EventLevel.Informational, Keywords.TasksSetActivityIds); + + Debug = IsEnabled(EventLevel.Informational, Keywords.Debug); + DebugActivityId = IsEnabled(EventLevel.Informational, Keywords.DebugActivityId); + } + + /// <summary> + /// Defines the singleton instance for the TPL ETW provider. + /// The TPL Event provider GUID is {2e5dba47-a3d2-4d16-8ee0-6671ffdcd7b5}. + /// </summary> + public static readonly TplEtwProvider Log = new TplEtwProvider(); + + /// <summary>Prevent external instantiation. All logging should go through the Log instance.</summary> + private TplEtwProvider() : base(new Guid(0x2e5dba47, 0xa3d2, 0x4d16, 0x8e, 0xe0, 0x66, 0x71, 0xff, 0xdc, 0xd7, 0xb5), "System.Threading.Tasks.TplEventSource") { } + + /// <summary>Configured behavior of a task wait operation.</summary> + public enum TaskWaitBehavior : int + { + /// <summary>A synchronous wait.</summary> + Synchronous = 1, + /// <summary>An asynchronous await.</summary> + Asynchronous = 2 + } + + /// <summary>ETW tasks that have start/stop events.</summary> + public class Tasks // this name is important for EventSource + { + /// <summary>A parallel loop.</summary> + public const EventTask Loop = (EventTask)1; + /// <summary>A parallel invoke.</summary> + public const EventTask Invoke = (EventTask)2; + /// <summary>Executing a Task.</summary> + public const EventTask TaskExecute = (EventTask)3; + /// <summary>Waiting on a Task.</summary> + public const EventTask TaskWait = (EventTask)4; + /// <summary>A fork/join task within a loop or invoke.</summary> + public const EventTask ForkJoin = (EventTask)5; + /// <summary>A task is scheduled to execute.</summary> + public const EventTask TaskScheduled = (EventTask)6; + /// <summary>An await task continuation is scheduled to execute.</summary> + public const EventTask AwaitTaskContinuationScheduled = (EventTask)7; + + /// <summary>AsyncCausalityFunctionality.</summary> + public const EventTask TraceOperation = (EventTask)8; + public const EventTask TraceSynchronousWork = (EventTask)9; + } + + public class Keywords // thisname is important for EventSource + { + /// <summary> + /// Only the most basic information about the workings of the task library + /// This sets activity IDS and logs when tasks are schedules (or waits begin) + /// But are otherwise silent + /// </summary> + public const EventKeywords TaskTransfer = (EventKeywords)1; + /// <summary> + /// TaskTranser events plus events when tasks start and stop + /// </summary> + public const EventKeywords Tasks = (EventKeywords)2; + /// <summary> + /// Events associted with the higher level parallel APIs + /// </summary> + public const EventKeywords Parallel = (EventKeywords)4; + /// <summary> + /// These are relatively verbose events that effectively just redirect + /// the windows AsyncCausalityTracer to ETW + /// </summary> + public const EventKeywords AsyncCausalityOperation = (EventKeywords)8; + public const EventKeywords AsyncCausalityRelation = (EventKeywords)0x10; + public const EventKeywords AsyncCausalitySynchronousWork = (EventKeywords)0x20; + + /// <summary> + /// Emit the stops as well as the schedule/start events + /// </summary> + public const EventKeywords TaskStops = (EventKeywords)0x40; + + /// <summary> + /// TasksFlowActivityIds indicate that activity ID flow from one task + /// to any task created by it. + /// </summary> + public const EventKeywords TasksFlowActivityIds = (EventKeywords)0x80; + + /// <summary> + /// Events related to the happenings of async methods. + /// </summary> + public const EventKeywords AsyncMethod = (EventKeywords)0x100; + + /// <summary> + /// TasksSetActivityIds will cause the task operations to set Activity Ids + /// This option is incompatible with TasksFlowActivityIds flow is ignored + /// if that keyword is set. This option is likely to be removed in the future + /// </summary> + public const EventKeywords TasksSetActivityIds = (EventKeywords)0x10000; + + /// <summary> + /// Relatively Verbose logging meant for debugging the Task library itself. Will probably be removed in the future + /// </summary> + public const EventKeywords Debug = (EventKeywords)0x20000; + /// <summary> + /// Relatively Verbose logging meant for debugging the Task library itself. Will probably be removed in the future + /// </summary> + public const EventKeywords DebugActivityId = (EventKeywords)0x40000; + } + + /// <summary>Enabled for all keywords.</summary> + private const EventKeywords ALL_KEYWORDS = (EventKeywords)(-1); + + //----------------------------------------------------------------------------------- + // + // TPL Event IDs (must be unique) + // + + /// <summary>The beginning of a parallel loop.</summary> + private const int PARALLELLOOPBEGIN_ID = 1; + /// <summary>The ending of a parallel loop.</summary> + private const int PARALLELLOOPEND_ID = 2; + /// <summary>The beginning of a parallel invoke.</summary> + private const int PARALLELINVOKEBEGIN_ID = 3; + /// <summary>The ending of a parallel invoke.</summary> + private const int PARALLELINVOKEEND_ID = 4; + /// <summary>A task entering a fork/join construct.</summary> + private const int PARALLELFORK_ID = 5; + /// <summary>A task leaving a fork/join construct.</summary> + private const int PARALLELJOIN_ID = 6; + + /// <summary>A task is scheduled to a task scheduler.</summary> + private const int TASKSCHEDULED_ID = 7; + /// <summary>A task is about to execute.</summary> + private const int TASKSTARTED_ID = 8; + /// <summary>A task has finished executing.</summary> + private const int TASKCOMPLETED_ID = 9; + /// <summary>A wait on a task is beginning.</summary> + private const int TASKWAITBEGIN_ID = 10; + /// <summary>A wait on a task is ending.</summary> + private const int TASKWAITEND_ID = 11; + /// <summary>A continuation of a task is scheduled.</summary> + private const int AWAITTASKCONTINUATIONSCHEDULED_ID = 12; + /// <summary>A continuation of a taskWaitEnd is complete </summary> + private const int TASKWAITCONTINUATIONCOMPLETE_ID = 13; + /// <summary>A continuation of a taskWaitEnd is complete </summary> + private const int TASKWAITCONTINUATIONSTARTED_ID = 19; + + private const int TRACEOPERATIONSTART_ID = 14; + private const int TRACEOPERATIONSTOP_ID = 15; + private const int TRACEOPERATIONRELATION_ID = 16; + private const int TRACESYNCHRONOUSWORKSTART_ID = 17; + private const int TRACESYNCHRONOUSWORKSTOP_ID = 18; + + + //----------------------------------------------------------------------------------- + // + // Task Events + // + + // These are all verbose events, so we need to call IsEnabled(EventLevel.Verbose, ALL_KEYWORDS) + // call. However since the IsEnabled(l,k) call is more expensive than IsEnabled(), we only want + // to incur this cost when instrumentation is enabled. So the Task codepaths that call these + // event functions still do the check for IsEnabled() + + #region TaskScheduled + /// <summary> + /// Fired when a task is queued to a TaskScheduler. + /// </summary> + /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param> + /// <param name="OriginatingTaskID">The task ID.</param> + /// <param name="TaskID">The task ID.</param> + /// <param name="CreatingTaskID">The task ID</param> + /// <param name="TaskCreationOptions">The options used to create the task.</param> + [Event(TASKSCHEDULED_ID, Task = Tasks.TaskScheduled, Version = 1, Opcode = EventOpcode.Send, + Level = EventLevel.Informational, Keywords = Keywords.TaskTransfer | Keywords.Tasks)] + public void TaskScheduled( + int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER + int TaskID, int CreatingTaskID, int TaskCreationOptions, int appDomain = DefaultAppDomainID) + { + // IsEnabled() call is an inlined quick check that makes this very fast when provider is off + if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer | Keywords.Tasks)) + { + unsafe + { + EventData* eventPayload = stackalloc EventData[6]; + eventPayload[0].Size = sizeof(int); + eventPayload[0].DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID)); + eventPayload[0].Reserved = 0; + eventPayload[1].Size = sizeof(int); + eventPayload[1].DataPointer = ((IntPtr)(&OriginatingTaskID)); + eventPayload[1].Reserved = 0; + eventPayload[2].Size = sizeof(int); + eventPayload[2].DataPointer = ((IntPtr)(&TaskID)); + eventPayload[2].Reserved = 0; + eventPayload[3].Size = sizeof(int); + eventPayload[3].DataPointer = ((IntPtr)(&CreatingTaskID)); + eventPayload[3].Reserved = 0; + eventPayload[4].Size = sizeof(int); + eventPayload[4].DataPointer = ((IntPtr)(&TaskCreationOptions)); + eventPayload[4].Reserved = 0; + eventPayload[5].Size = sizeof(int); + eventPayload[5].DataPointer = ((IntPtr)(&appDomain)); + eventPayload[5].Reserved = 0; + if (TasksSetActivityIds) + { + Guid childActivityId = CreateGuidForTaskID(TaskID); + WriteEventWithRelatedActivityIdCore(TASKSCHEDULED_ID, &childActivityId, 6, eventPayload); + } + else + WriteEventCore(TASKSCHEDULED_ID, 6, eventPayload); + } + } + } + #endregion + + #region TaskStarted + /// <summary> + /// Fired just before a task actually starts executing. + /// </summary> + /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param> + /// <param name="OriginatingTaskID">The task ID.</param> + /// <param name="TaskID">The task ID.</param> + [Event(TASKSTARTED_ID, + Level = EventLevel.Informational, Keywords = Keywords.Tasks)] + public void TaskStarted( + int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER + int TaskID) + { + if (IsEnabled(EventLevel.Informational, Keywords.Tasks)) + WriteEvent(TASKSTARTED_ID, OriginatingTaskSchedulerID, OriginatingTaskID, TaskID); + } + #endregion + + #region TaskCompleted + /// <summary> + /// Fired right after a task finished executing. + /// </summary> + /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param> + /// <param name="OriginatingTaskID">The task ID.</param> + /// <param name="TaskID">The task ID.</param> + /// <param name="IsExceptional">Whether the task completed due to an error.</param> + [Event(TASKCOMPLETED_ID, Version = 1, + Level = EventLevel.Informational, Keywords = Keywords.TaskStops)] + public void TaskCompleted( + int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER + int TaskID, bool IsExceptional) + { + if (IsEnabled(EventLevel.Informational, Keywords.Tasks)) + { + unsafe + { + EventData* eventPayload = stackalloc EventData[4]; + int isExceptionalInt = IsExceptional ? 1 : 0; + eventPayload[0].Size = sizeof(int); + eventPayload[0].DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID)); + eventPayload[0].Reserved = 0; + eventPayload[1].Size = sizeof(int); + eventPayload[1].DataPointer = ((IntPtr)(&OriginatingTaskID)); + eventPayload[1].Reserved = 0; + eventPayload[2].Size = sizeof(int); + eventPayload[2].DataPointer = ((IntPtr)(&TaskID)); + eventPayload[2].Reserved = 0; + eventPayload[3].Size = sizeof(int); + eventPayload[3].DataPointer = ((IntPtr)(&isExceptionalInt)); + eventPayload[3].Reserved = 0; + WriteEventCore(TASKCOMPLETED_ID, 4, eventPayload); + } + } + } + #endregion + + #region TaskWaitBegin + /// <summary> + /// Fired when starting to wait for a taks's completion explicitly or implicitly. + /// </summary> + /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param> + /// <param name="OriginatingTaskID">The task ID.</param> + /// <param name="TaskID">The task ID.</param> + /// <param name="Behavior">Configured behavior for the wait.</param> + /// <param name="ContinueWithTaskID"> + /// If known, if 'TaskID' has a 'continueWith' task, mention give its ID here. + /// 0 means unknown. This allows better visualization of the common sequential chaining case. + /// </param> + [Event(TASKWAITBEGIN_ID, Version = 3, Task = TplEtwProvider.Tasks.TaskWait, Opcode = EventOpcode.Send, + Level = EventLevel.Informational, Keywords = Keywords.TaskTransfer | Keywords.Tasks)] + public void TaskWaitBegin( + int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER + int TaskID, TaskWaitBehavior Behavior, int ContinueWithTaskID) + { + if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer | Keywords.Tasks)) + { + unsafe + { + EventData* eventPayload = stackalloc EventData[5]; + eventPayload[0].Size = sizeof(int); + eventPayload[0].DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID)); + eventPayload[0].Reserved = 0; + eventPayload[1].Size = sizeof(int); + eventPayload[1].DataPointer = ((IntPtr)(&OriginatingTaskID)); + eventPayload[1].Reserved = 0; + eventPayload[2].Size = sizeof(int); + eventPayload[2].DataPointer = ((IntPtr)(&TaskID)); + eventPayload[2].Reserved = 0; + eventPayload[3].Size = sizeof(int); + eventPayload[3].DataPointer = ((IntPtr)(&Behavior)); + eventPayload[3].Reserved = 0; + eventPayload[4].Size = sizeof(int); + eventPayload[4].DataPointer = ((IntPtr)(&ContinueWithTaskID)); + eventPayload[4].Reserved = 0; + if (TasksSetActivityIds) + { + Guid childActivityId = CreateGuidForTaskID(TaskID); + WriteEventWithRelatedActivityIdCore(TASKWAITBEGIN_ID, &childActivityId, 5, eventPayload); + } + else + { + WriteEventCore(TASKWAITBEGIN_ID, 5, eventPayload); + } + } + } + } + #endregion + + /// <summary> + /// Fired when the wait for a tasks completion returns. + /// </summary> + /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param> + /// <param name="OriginatingTaskID">The task ID.</param> + /// <param name="TaskID">The task ID.</param> + [Event(TASKWAITEND_ID, + Level = EventLevel.Verbose, Keywords = Keywords.Tasks)] + public void TaskWaitEnd( + int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER + int TaskID) + { + // Log an event if indicated. + if (IsEnabled() && IsEnabled(EventLevel.Verbose, Keywords.Tasks)) + WriteEvent(TASKWAITEND_ID, OriginatingTaskSchedulerID, OriginatingTaskID, TaskID); + } + + /// <summary> + /// Fired when the work (method) associated with a TaskWaitEnd completes + /// </summary> + /// <param name="TaskID">The task ID.</param> + [Event(TASKWAITCONTINUATIONCOMPLETE_ID, + Level = EventLevel.Verbose, Keywords = Keywords.TaskStops)] + public void TaskWaitContinuationComplete(int TaskID) + { + // Log an event if indicated. + if (IsEnabled() && IsEnabled(EventLevel.Verbose, Keywords.Tasks)) + WriteEvent(TASKWAITCONTINUATIONCOMPLETE_ID, TaskID); + } + + /// <summary> + /// Fired when the work (method) associated with a TaskWaitEnd completes + /// </summary> + /// <param name="TaskID">The task ID.</param> + [Event(TASKWAITCONTINUATIONSTARTED_ID, + Level = EventLevel.Verbose, Keywords = Keywords.TaskStops)] + public void TaskWaitContinuationStarted(int TaskID) + { + // Log an event if indicated. + if (IsEnabled() && IsEnabled(EventLevel.Verbose, Keywords.Tasks)) + WriteEvent(TASKWAITCONTINUATIONSTARTED_ID, TaskID); + } + + /// <summary> + /// Fired when the an asynchronous continuation for a task is scheduled + /// </summary> + /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param> + /// <param name="OriginatingTaskID">The task ID.</param> + [Event(AWAITTASKCONTINUATIONSCHEDULED_ID, Task = Tasks.AwaitTaskContinuationScheduled, Opcode = EventOpcode.Send, + Level = EventLevel.Informational, Keywords = Keywords.TaskTransfer | Keywords.Tasks)] + public void AwaitTaskContinuationScheduled( + int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER + int ContinuwWithTaskId) + { + if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer | Keywords.Tasks)) + { + unsafe + { + EventData* eventPayload = stackalloc EventData[3]; + eventPayload[0].Size = sizeof(int); + eventPayload[0].DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID)); + eventPayload[0].Reserved = 0; + eventPayload[1].Size = sizeof(int); + eventPayload[1].DataPointer = ((IntPtr)(&OriginatingTaskID)); + eventPayload[1].Reserved = 0; + eventPayload[2].Size = sizeof(int); + eventPayload[2].DataPointer = ((IntPtr)(&ContinuwWithTaskId)); + eventPayload[2].Reserved = 0; + if (TasksSetActivityIds) + { + Guid continuationActivityId = CreateGuidForTaskID(ContinuwWithTaskId); + WriteEventWithRelatedActivityIdCore(AWAITTASKCONTINUATIONSCHEDULED_ID, &continuationActivityId, 3, eventPayload); + } + else + WriteEventCore(AWAITTASKCONTINUATIONSCHEDULED_ID, 3, eventPayload); + } + } + } + + [Event(TRACEOPERATIONSTART_ID, Version = 1, + Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalityOperation)] + public void TraceOperationBegin(int TaskID, string OperationName, long RelatedContext) + { + if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalityOperation)) + { + unsafe + { + fixed (char* operationNamePtr = OperationName) + { + EventData* eventPayload = stackalloc EventData[3]; + eventPayload[0].Size = sizeof(int); + eventPayload[0].DataPointer = ((IntPtr)(&TaskID)); + eventPayload[0].Reserved = 0; + + eventPayload[1].Size = ((OperationName.Length + 1) * 2); + eventPayload[1].DataPointer = ((IntPtr)operationNamePtr); + eventPayload[1].Reserved = 0; + + eventPayload[2].Size = sizeof(long); + eventPayload[2].DataPointer = ((IntPtr)(&RelatedContext)); + eventPayload[2].Reserved = 0; + WriteEventCore(TRACEOPERATIONSTART_ID, 3, eventPayload); + } + } + } + } + + [Event(TRACEOPERATIONRELATION_ID, Version = 1, + Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalityRelation)] + public void TraceOperationRelation(int TaskID, CausalityRelation Relation) + { + if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalityRelation)) + WriteEvent(TRACEOPERATIONRELATION_ID, TaskID, (int)Relation); // optmized overload for this exists + } + + [Event(TRACEOPERATIONSTOP_ID, Version = 1, + Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalityOperation)] + public void TraceOperationEnd(int TaskID, AsyncCausalityStatus Status) + { + if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalityOperation)) + WriteEvent(TRACEOPERATIONSTOP_ID, TaskID, (int)Status); // optmized overload for this exists + } + + [Event(TRACESYNCHRONOUSWORKSTART_ID, Version = 1, + Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalitySynchronousWork)] + public void TraceSynchronousWorkBegin(int TaskID, CausalitySynchronousWork Work) + { + if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalitySynchronousWork)) + WriteEvent(TRACESYNCHRONOUSWORKSTART_ID, TaskID, (int)Work); // optmized overload for this exists + } + + [Event(TRACESYNCHRONOUSWORKSTOP_ID, Version = 1, + Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalitySynchronousWork)] + public void TraceSynchronousWorkEnd(CausalitySynchronousWork Work) + { + if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalitySynchronousWork)) + { + unsafe + { + EventData* eventPayload = stackalloc EventData[1]; + eventPayload[0].Size = sizeof(int); + eventPayload[0].DataPointer = ((IntPtr)(&Work)); + eventPayload[0].Reserved = 0; + + WriteEventCore(TRACESYNCHRONOUSWORKSTOP_ID, 1, eventPayload); + } + } + } + + [NonEvent] + public unsafe void RunningContinuation(int TaskID, object Object) { RunningContinuation(TaskID, (long)*((void**)Unsafe.AsPointer(ref Object))); } + [Event(20, Keywords = Keywords.Debug)] + private void RunningContinuation(int TaskID, long Object) + { + if (Debug) + WriteEvent(20, TaskID, Object); + } + + [NonEvent] + public unsafe void RunningContinuationList(int TaskID, int Index, object Object) { RunningContinuationList(TaskID, Index, (long)*((void**)Unsafe.AsPointer(ref Object))); } + + [Event(21, Keywords = Keywords.Debug)] + public void RunningContinuationList(int TaskID, int Index, long Object) + { + if (Debug) + WriteEvent(21, TaskID, Index, Object); + } + + [Event(23, Keywords = Keywords.Debug)] + public void DebugFacilityMessage(string Facility, string Message) { WriteEvent(23, Facility, Message); } + + [Event(24, Keywords = Keywords.Debug)] + public void DebugFacilityMessage1(string Facility, string Message, string Value1) { WriteEvent(24, Facility, Message, Value1); } + + [Event(25, Keywords = Keywords.DebugActivityId)] + public void SetActivityId(Guid NewId) + { + if (DebugActivityId) + WriteEvent(25, NewId); + } + + [Event(26, Keywords = Keywords.Debug)] + public void NewID(int TaskID) + { + if (Debug) + WriteEvent(26, TaskID); + } + + [NonEvent] + public void IncompleteAsyncMethod(IAsyncStateMachineBox stateMachineBox) + { + System.Diagnostics.Debug.Assert(stateMachineBox != null); + if (IsEnabled(EventLevel.Warning, Keywords.AsyncMethod)) + { + IAsyncStateMachine stateMachine = stateMachineBox.GetStateMachineObject(); + if (stateMachine != null) + { + string description = AsyncMethodBuilderCore.GetAsyncStateMachineDescription(stateMachine); + IncompleteAsyncMethod(description); + } + } + } + + [Event(27, Level = EventLevel.Warning, Keywords = Keywords.AsyncMethod)] + private void IncompleteAsyncMethod(string stateMachineDescription) => + WriteEvent(27, stateMachineDescription); + + /// <summary> + /// Activity IDs are GUIDS but task IDS are integers (and are not unique across appdomains + /// This routine creates a process wide unique GUID given a task ID + /// </summary> + internal static Guid CreateGuidForTaskID(int taskID) + { + // The thread pool generated a process wide unique GUID from a task GUID by + // using the taskGuid, the appdomain ID, and 8 bytes of 'randomization' chosen by + // using the last 8 bytes as the provider GUID for this provider. + // These were generated by CreateGuid, and are reasonably random (and thus unlikley to collide + uint pid = EventSource.s_currentPid; + return new Guid(taskID, + (short)DefaultAppDomainID, (short)(DefaultAppDomainID >> 16), + (byte)pid, (byte)(pid >> 8), (byte)(pid >> 16), (byte)(pid >> 24), + 0xff, 0xdc, 0xd7, 0xb5); + } + } +} |