예제 #1
0
        /// <summary>
        /// Outputs a WaitBegin ETW event, and augments the continuation action to output a WaitEnd ETW event.
        /// </summary>
        /// <param name="task">The task being awaited.</param>
        /// <param name="continuation">The action to invoke when the await operation completes.</param>
        /// <returns>The action to use as the actual continuation.</returns>
        private static Action OutputWaitEtwEvents(Task task, Action continuation)
        {
            Debug.Assert(task != null, "Need a task to wait on");
            Debug.Assert(continuation != null, "Need a continuation to invoke when the wait completes");

            if (Task.s_asyncDebuggingEnabled)
            {
                Task.AddToActiveTasks(task);
            }

            TplEventSource log = TplEventSource.Log;

            if (log.IsEnabled())
            {
                // ETW event for Task Wait Begin
                Task?currentTaskAtBegin = Task.InternalCurrent;

                // If this task's continuation is another task, get it.
                Task?continuationTask = AsyncMethodBuilderCore.TryGetContinuationTask(continuation);
                log.TaskWaitBegin(
                    currentTaskAtBegin != null ? currentTaskAtBegin.m_taskScheduler !.Id : TaskScheduler.Default.Id,
                    currentTaskAtBegin != null ? currentTaskAtBegin.Id : 0,
                    task.Id, TplEventSource.TaskWaitBehavior.Asynchronous,
                    continuationTask != null ? continuationTask.Id : 0);
            }

            // Create a continuation action that outputs the end event and then invokes the user
            // provided delegate.  This incurs the allocations for the closure/delegate, but only if the event
            // is enabled, and in doing so it allows us to pass the awaited task's information into the end event
            // in a purely pay-for-play manner (the alternatively would be to increase the size of TaskAwaiter
            // just for this ETW purpose, not pay-for-play, since GetResult would need to know whether a real yield occurred).
            return(AsyncMethodBuilderCore.CreateContinuationWrapper(continuation, static (innerContinuation, innerTask) =>
예제 #2
0
        /// <summary>
        /// Outputs a WaitBegin ETW event, and augments the continuation action to output a WaitEnd ETW event.
        /// </summary>
        /// <param name="task">The task being awaited.</param>
        /// <param name="continuation">The action to invoke when the await operation completes.</param>
        /// <returns>The action to use as the actual continuation.</returns>
        private static Action OutputWaitEtwEvents(Task task, Action continuation)
        {
            Debug.Assert(task != null, "Need a task to wait on");
            Debug.Assert(continuation != null, "Need a continuation to invoke when the wait completes");

            if (Task.s_asyncDebuggingEnabled)
            {
                Task.AddToActiveTasks(task);
            }

            TplEventSource log = TplEventSource.Log;

            if (log.IsEnabled())
            {
                // ETW event for Task Wait Begin
                Task?currentTaskAtBegin = Task.InternalCurrent;

                // If this task's continuation is another task, get it.
                Task?continuationTask = AsyncMethodBuilderCore.TryGetContinuationTask(continuation);
                log.TaskWaitBegin(
                    currentTaskAtBegin != null ? currentTaskAtBegin.m_taskScheduler !.Id : TaskScheduler.Default.Id,
                    currentTaskAtBegin != null ? currentTaskAtBegin.Id : 0,
                    task.Id, TplEventSource.TaskWaitBehavior.Asynchronous,
                    continuationTask != null ? continuationTask.Id : 0);
            }

            // Create a continuation action that outputs the end event and then invokes the user
            // provided delegate.  This incurs the allocations for the closure/delegate, but only if the event
            // is enabled, and in doing so it allows us to pass the awaited task's information into the end event
            // in a purely pay-for-play manner (the alternatively would be to increase the size of TaskAwaiter
            // just for this ETW purpose, not pay-for-play, since GetResult would need to know whether a real yield occurred).
            return(AsyncMethodBuilderCore.CreateContinuationWrapper(continuation, (innerContinuation, innerTask) =>
            {
                if (Task.s_asyncDebuggingEnabled)
                {
                    Task.RemoveFromActiveTasks(innerTask);
                }

                TplEventSource innerEtwLog = TplEventSource.Log;

                // ETW event for Task Wait End.
                Guid prevActivityId = default;
                bool bEtwLogEnabled = innerEtwLog.IsEnabled();
                if (bEtwLogEnabled)
                {
                    Task?currentTaskAtEnd = Task.InternalCurrent;
                    innerEtwLog.TaskWaitEnd(
                        currentTaskAtEnd != null ? currentTaskAtEnd.m_taskScheduler !.Id : TaskScheduler.Default.Id,
                        currentTaskAtEnd != null ? currentTaskAtEnd.Id : 0,
                        innerTask.Id);

                    // Ensure the continuation runs under the activity ID of the task that completed for the
                    // case the antecedent is a promise (in the other cases this is already the case).
                    if (innerEtwLog.TasksSetActivityIds && (innerTask.Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0)
                    {
                        EventSource.SetCurrentThreadActivityId(TplEventSource.CreateGuidForTaskID(innerTask.Id), out prevActivityId);
                    }
                }