File: src\libraries\System.Private.CoreLib\src\System\Diagnostics\Tracing\NativeRuntimeEventSource.cs
Web Access
Project: src\src\coreclr\System.Private.CoreLib\System.Private.CoreLib.csproj (System.Private.CoreLib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
namespace System.Diagnostics.Tracing
{
    /// <summary>
    /// NativeRuntimeEventSource is an EventSource that represents the ETW/EventPipe events emitted by the native runtime.
    /// Most of NativeRuntimeEventSource is auto-generated by NativeRuntimeEventSourceGenerator based on the contents of the
    /// Microsoft-Windows-DotNETRuntime provider and will throw a NotImplementedException without hand-written overloads of the Events.
    /// To have a runtime event be fired from the managed code, you need to add a managed definition for that event
    /// and call into the native runtime that invoke the appropriate native sinks for the platform (i.e. ETW, EventPipe, LTTng).
    /// To see some examples of this, refer to NativeRuntimeEventSource.Threading.NativeSinks.cs and NativeRuntimeEventSource.Threading.cs.
    /// Then, modify NativeRuntimeEventSourceGenerator.cs to skip over the event so that it doesn't generate the dummy method.
    ///
    /// The events in NativeRuntimeEventSource.*.NativeSinks.cs do not call into the typical WriteEvent* APIs unlike most EventSources because that results in the
    /// events to be forwarded to EventListeners twice, once directly from the managed WriteEvent API, and another time
    /// from the mechanism in NativeRuntimeEventSource.ProcessEvents that forwards native runtime events to EventListeners.
    /// To prevent this, these events call directly into QCalls provided by the runtime in NativeRuntimeEventSource.*.NativeSinks.Internal.cs which call
    /// FireEtw* methods auto-generated from ClrEtwAll.man. This ensures that corresponding event sinks are being used
    /// for the native platform.
    /// </summary>
    [EventSource(Guid = "E13C0D23-CCBC-4E12-931B-D9CC2EEE27E4", Name = EventSourceName)]
    internal sealed partial class NativeRuntimeEventSource : EventSource
    {
        internal const string EventSourceName = "Microsoft-Windows-DotNETRuntime";
        public static readonly NativeRuntimeEventSource Log = new NativeRuntimeEventSource();
 
        // This value does not seem to be used, leaving it as zero for now. It may be useful for a scenario that may involve
        // multiple instances of the runtime within the same process, but then it seems unlikely that both instances' thread
        // pools would be in moderate use.
        private const ushort DefaultClrInstanceId = 0;
 
#if FEATURE_PERFTRACING
        /// <summary>
        /// Dispatch a single event with the specified event ID and payload.
        /// </summary>
        /// <param name="eventID">The eventID corresponding to the event as defined in the auto-generated portion of the NativeRuntimeEventSource class.</param>
        /// <param name="osThreadID">The thread ID of the operating system thread.</param>
        /// <param name="timeStamp">The current timestamp.</param>
        /// <param name="activityId">The ID of the current activity.</param>
        /// <param name="childActivityId">The ID of the current child activity.</param>
        /// <param name="payload">A span pointing to the data payload for the event.</param>
        [NonEvent]
        internal unsafe void ProcessEvent(uint eventID, uint osThreadID, DateTime timeStamp, Guid activityId, Guid childActivityId, ReadOnlySpan<byte> payload)
        {
            // A simple fix to avoid dependencies brought by this method if event source is disabled via a feature switch.
            // Should be reconsidered when https://github.com/dotnet/runtime/issues/43657 is done.
            if (!IsSupported)
            {
                return;
            }
            // Make sure the eventID is valid.
            ref EventMetadata metadata = ref CollectionsMarshal.GetValueRefOrNullRef(m_eventData!, (int)eventID);
            if (Unsafe.IsNullRef(ref metadata))
            {
                return;
            }
            // Decode the payload.
            object[] decodedPayloadFields = EventPipePayloadDecoder.DecodePayload(ref metadata, payload);
 
            var eventCallbackArgs = new EventWrittenEventArgs(this, (int)eventID, &activityId, &childActivityId)
            {
                OSThreadId = (int)osThreadID,
                TimeStamp = timeStamp,
                Payload = new ReadOnlyCollection<object?>(decodedPayloadFields)
            };
 
            DispatchToAllListeners(eventCallbackArgs);
        }
#endif // FEATURE_PERFTRACING
    }
}