private void ActivityChanging(AsyncLocalValueChangedArgs <ActivityTracker.ActivityInfo> args) { if (args.PreviousValue == args.CurrentValue) { return; } if (args.CurrentValue != null) { EventSource.SetCurrentThreadActivityId(args.CurrentValue.ActivityId); } else { EventSource.SetCurrentThreadActivityId(Guid.Empty); } }
// Token: 0x06003320 RID: 13088 RVA: 0x000C2668 File Offset: 0x000C0868 private void ActivityChanging(AsyncLocalValueChangedArgs <ActivityTracker.ActivityInfo> args) { ActivityTracker.ActivityInfo activityInfo = args.CurrentValue; ActivityTracker.ActivityInfo previousValue = args.PreviousValue; if (previousValue != null && previousValue.m_creator == activityInfo && (activityInfo == null || previousValue.m_activityIdToRestore != activityInfo.ActivityId)) { EventSource.SetCurrentThreadActivityId(previousValue.m_activityIdToRestore); return; } while (activityInfo != null) { if (activityInfo.m_stopped == 0) { EventSource.SetCurrentThreadActivityId(activityInfo.ActivityId); return; } activityInfo = activityInfo.m_creator; } }
// This callback is used to initialize the m_current AsyncLocal Variable. // Its job is to keep the ETW Activity ID (part of thread local storage) in sync // with m_current.ActivityID // // WARNING: When mixing manual usage of EventSource.SetCurrentThreadActivityID // and Start/Stop EventSource events I can't identify a clear design how this // synchronization is intended to work. For example code that changes // SetCurrentThreadActivityID after a FooStart() event will not flow the // explicit ID with the async work, but if FooStart() event is called after // SetCurrentThreadActivityID then the explicit ID change does flow. // For now I've adopted the approach: // Priority 1: Make the API predictable/sensible when only Start/Stop events // are in use. // Priority 2: If users aren't complaining and it doesn't interfere with // goal #1, try to preserve the arbitrary/buggy? existing behavior // for mixed usage of SetActivityID + events. // // For scenarios that only use start/stop events this is what we expect: // calling start -> push new ID on stack and update thread-local to match new ID // calling stop -> pop ID from stack and update thread-local to match new topmost // still active ID. If there is none, set ID to zero // thread swap -> update thread-local to match topmost active ID. // If there is none, set ID to zero. private void ActivityChanging(AsyncLocalValueChangedArgs <ActivityInfo?> args) { ActivityInfo?cur = args.CurrentValue; ActivityInfo?prev = args.PreviousValue; // Special case only relevant for mixed SetActivityID usage: // // Are we MAYBE popping off a value? (we have a prev, and it creator is cur) // We can't be certain this is a pop because a thread swapping between two // ExecutionContexts can also appear the same way. // Then check if we should use the GUID at the time of the start event if (prev != null && prev.m_creator == cur) { // If the saved activity ID is not the same as the creator activity // that takes precedence (it means someone explicitly did a SetActivityID) // Set it to that and get out if (cur == null || prev.m_activityIdToRestore != cur.ActivityId) { EventSource.SetCurrentThreadActivityId(prev.m_activityIdToRestore); return; } } // Set the activity to current ActivityInfo. However that activity // might be dead, in which case we should skip it, so we never set // the ID to dead things. while (cur != null) { // We found a live activity (typically the first time), set it to that. if (cur.m_stopped == 0) { EventSource.SetCurrentThreadActivityId(cur.ActivityId); return; } cur = cur.m_creator; } // we can get here if there is no information on our activity stack (everything is dead) // Set ActivityID to zero EventSource.SetCurrentThreadActivityId(Guid.Empty); }