From f7020d98c49d8c89fdad41aae64c018be63c623a Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Tue, 16 Apr 2019 15:52:53 +0200 Subject: [PATCH] Move EventSource to shared CoreLib partition (#23925) * Move most of EventSource to shared CoreLib partition * Reenable some code that can be shared with Microsoft.Diagnostics.Tracing.EventSource.Redist in CoreFX * Remove unused functions * Fix placement of #endregion * Clean up P/Invoke prototypes * Move remaining code from EventSource_CoreCLR to shared partition (guarded by !CORERT) * Remove more unnecessary marshalling attributes * Move remaining CoreRT/ProjectN code to shared partition * Avoid using Windows errors on non-Windows platforms --- .../System.Private.CoreLib.csproj | 1 - .../Windows/Advapi32/Interop.ActivityControl.cs | 21 ++ .../Windows/Advapi32/Interop.EVENT_INFO_CLASS.cs | 19 ++ .../Windows/Advapi32/Interop.EtwEnableCallback.cs | 33 +++ .../Advapi32/Interop.EventActivityIdControl.cs | 15 + .../Windows/Advapi32/Interop.EventRegister.cs | 19 ++ .../Advapi32/Interop.EventSetInformation.cs | 19 ++ .../Windows/Advapi32/Interop.EventTraceGuidsEx.cs | 59 ++++ .../Windows/Advapi32/Interop.EventUnregister.cs | 15 + .../Windows/Advapi32/Interop.EventWriteString.cs | 19 ++ .../Windows/Advapi32/Interop.EventWriteTransfer.cs | 49 ++++ .../shared/Interop/Windows/Interop.Errors.cs | 1 + .../shared/System.Private.CoreLib.Shared.projitems | 10 + .../System/Diagnostics/Tracing/EventProvider.cs | 157 ++++++----- .../System/Diagnostics/Tracing/EventSource.cs | 305 ++++++++++++++++++++- .../System/Diagnostics/Tracing/IEventProvider.cs | 8 +- .../src/Microsoft/Win32/UnsafeNativeMethods.cs | 175 ------------ .../src/System/Diagnostics/Eventing/EventPipe.cs | 2 +- .../Diagnostics/Eventing/EventPipeEventProvider.cs | 12 +- .../Diagnostics/Eventing/EventSource_CoreCLR.cs | 230 ---------------- 20 files changed, 682 insertions(+), 487 deletions(-) create mode 100644 src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.ActivityControl.cs create mode 100644 src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EVENT_INFO_CLASS.cs create mode 100644 src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EtwEnableCallback.cs create mode 100644 src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventActivityIdControl.cs create mode 100644 src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventRegister.cs create mode 100644 src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventSetInformation.cs create mode 100644 src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventTraceGuidsEx.cs create mode 100644 src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventUnregister.cs create mode 100644 src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventWriteString.cs create mode 100644 src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventWriteTransfer.cs delete mode 100644 src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventSource_CoreCLR.cs diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj index f7df61d..c012ba5 100644 --- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -150,7 +150,6 @@ - diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.ActivityControl.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.ActivityControl.cs new file mode 100644 index 0000000..34df748 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.ActivityControl.cs @@ -0,0 +1,21 @@ +// 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; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Advapi32 + { + internal enum ActivityControl : uint + { + EVENT_ACTIVITY_CTRL_GET_ID = 1, + EVENT_ACTIVITY_CTRL_SET_ID = 2, + EVENT_ACTIVITY_CTRL_CREATE_ID = 3, + EVENT_ACTIVITY_CTRL_GET_SET_ID = 4, + EVENT_ACTIVITY_CTRL_CREATE_SET_ID = 5 + } + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EVENT_INFO_CLASS.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EVENT_INFO_CLASS.cs new file mode 100644 index 0000000..a122002 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EVENT_INFO_CLASS.cs @@ -0,0 +1,19 @@ +// 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; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Advapi32 + { + internal enum EVENT_INFO_CLASS + { + BinaryTrackInfo, + SetEnableAllKeywords, + SetTraits, + } + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EtwEnableCallback.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EtwEnableCallback.cs new file mode 100644 index 0000000..6bb1575 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EtwEnableCallback.cs @@ -0,0 +1,33 @@ +// 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; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Advapi32 + { + internal const int EVENT_CONTROL_CODE_DISABLE_PROVIDER = 0; + internal const int EVENT_CONTROL_CODE_ENABLE_PROVIDER = 1; + internal const int EVENT_CONTROL_CODE_CAPTURE_STATE = 2; + + [StructLayout(LayoutKind.Sequential)] + internal struct EVENT_FILTER_DESCRIPTOR + { + public long Ptr; + public int Size; + public int Type; + } + + internal unsafe delegate void EtwEnableCallback( + in Guid sourceId, + int isEnabled, + byte level, + long matchAnyKeywords, + long matchAllKeywords, + EVENT_FILTER_DESCRIPTOR* filterData, + void* callbackContext); + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventActivityIdControl.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventActivityIdControl.cs new file mode 100644 index 0000000..886ff37 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventActivityIdControl.cs @@ -0,0 +1,15 @@ +// 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; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Advapi32 + { + [DllImport(Libraries.Advapi32, ExactSpelling = true)] + internal static extern int EventActivityIdControl(ActivityControl ControlCode, ref Guid ActivityId); + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventRegister.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventRegister.cs new file mode 100644 index 0000000..f5d245e --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventRegister.cs @@ -0,0 +1,19 @@ +// 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; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Advapi32 + { + [DllImport(Libraries.Advapi32, ExactSpelling = true)] + internal static extern unsafe uint EventRegister( + in Guid providerId, + EtwEnableCallback enableCallback, + void* callbackContext, + ref long registrationHandle); + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventSetInformation.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventSetInformation.cs new file mode 100644 index 0000000..381cb66 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventSetInformation.cs @@ -0,0 +1,19 @@ +// 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; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Advapi32 + { + [DllImport(Libraries.Advapi32, ExactSpelling = true)] + internal static unsafe extern int EventSetInformation( + long registrationHandle, + EVENT_INFO_CLASS informationClass, + void* eventInformation, + int informationLength); + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventTraceGuidsEx.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventTraceGuidsEx.cs new file mode 100644 index 0000000..c5f6f3b --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventTraceGuidsEx.cs @@ -0,0 +1,59 @@ +// 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; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Advapi32 + { + internal enum TRACE_QUERY_INFO_CLASS + { + TraceGuidQueryList, + TraceGuidQueryInfo, + TraceGuidQueryProcess, + TraceStackTracingInfo, + MaxTraceSetInfoClass + } + + [StructLayout(LayoutKind.Sequential)] + internal struct TRACE_GUID_INFO + { + public int InstanceCount; + public int Reserved; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct TRACE_PROVIDER_INSTANCE_INFO + { + public int NextOffset; + public int EnableCount; + public int Pid; + public int Flags; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct TRACE_ENABLE_INFO + { + public int IsEnabled; + public byte Level; + public byte Reserved1; + public ushort LoggerId; + public int EnableProperty; + public int Reserved2; + public long MatchAnyKeyword; + public long MatchAllKeyword; + } + + [DllImport(Interop.Libraries.Advapi32, ExactSpelling = true)] + internal static unsafe extern int EnumerateTraceGuidsEx( + TRACE_QUERY_INFO_CLASS TraceQueryInfoClass, + void* InBuffer, + int InBufferSize, + void* OutBuffer, + int OutBufferSize, + out int ReturnLength); + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventUnregister.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventUnregister.cs new file mode 100644 index 0000000..f387b3a --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventUnregister.cs @@ -0,0 +1,15 @@ +// 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; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Advapi32 + { + [DllImport(Libraries.Advapi32, ExactSpelling = true)] + internal static extern uint EventUnregister(long registrationHandle); + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventWriteString.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventWriteString.cs new file mode 100644 index 0000000..a00a2f3 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventWriteString.cs @@ -0,0 +1,19 @@ +// 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; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Advapi32 + { + [DllImport(Libraries.Advapi32, ExactSpelling = true)] + internal static extern int EventWriteString( + long registrationHandle, + byte level, + long keyword, + string msg); + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventWriteTransfer.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventWriteTransfer.cs new file mode 100644 index 0000000..2d3f45e --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.EventWriteTransfer.cs @@ -0,0 +1,49 @@ +// 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; +using System.Runtime.InteropServices; +#if ES_BUILD_STANDALONE +using Microsoft.Diagnostics.Tracing; +#else +using System.Diagnostics.Tracing; +#endif + +internal partial class Interop +{ + internal partial class Advapi32 + { + /// + /// Call the ETW native API EventWriteTransfer and checks for invalid argument error. + /// The implementation of EventWriteTransfer on some older OSes (Windows 2008) does not accept null relatedActivityId. + /// So, for these cases we will retry the call with an empty Guid. + /// + internal static unsafe int EventWriteTransfer( + long registrationHandle, + in EventDescriptor eventDescriptor, + Guid* activityId, + Guid* relatedActivityId, + int userDataCount, + EventProvider.EventData* userData) + { + int HResult = EventWriteTransfer_PInvoke(registrationHandle, in eventDescriptor, activityId, relatedActivityId, userDataCount, userData); + if (HResult == Errors.ERROR_INVALID_PARAMETER && relatedActivityId == null) + { + Guid emptyGuid = Guid.Empty; + HResult = EventWriteTransfer_PInvoke(registrationHandle, in eventDescriptor, activityId, &emptyGuid, userDataCount, userData); + } + + return HResult; + } + + [DllImport(Interop.Libraries.Advapi32, ExactSpelling = true, EntryPoint = "EventWriteTransfer")] + private static unsafe extern int EventWriteTransfer_PInvoke( + long registrationHandle, + in EventDescriptor eventDescriptor, + Guid* activityId, + Guid* relatedActivityId, + int userDataCount, + EventProvider.EventData* userData); + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Interop.Errors.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Interop.Errors.cs index 1a95db3..2e4683d 100644 --- a/src/System.Private.CoreLib/shared/Interop/Windows/Interop.Errors.cs +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Interop.Errors.cs @@ -18,6 +18,7 @@ internal partial class Interop internal const int ERROR_NOT_READY = 0x15; internal const int ERROR_SHARING_VIOLATION = 0x20; internal const int ERROR_HANDLE_EOF = 0x26; + internal const int ERROR_NOT_SUPPORTED = 0x32; internal const int ERROR_FILE_EXISTS = 0x50; internal const int ERROR_INVALID_PARAMETER = 0x57; internal const int ERROR_BROKEN_PIPE = 0x6D; diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index 716dc56..e51a210 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -914,6 +914,9 @@ + + + @@ -994,6 +997,13 @@ + + + + + + + diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs index 345a9cf..a8622a8 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs @@ -63,7 +63,7 @@ namespace System.Diagnostics.Tracing #if ES_BUILD_STANDALONE [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] #endif - internal partial class EventProvider : IDisposable + internal class EventProvider : IDisposable { // This is the windows EVENT_DATA_DESCRIPTOR structure. We expose it because this is what // subclasses of EventProvider use when creating efficient (but unsafe) version of @@ -92,10 +92,8 @@ namespace System.Diagnostics.Tracing { sessionIdBit = sessionIdBit_; etwSessionId = etwSessionId_; } } - private static bool m_setInformationMissing; - internal IEventProvider m_eventProvider; // The interface that implements the specific logging mechanism functions. - UnsafeNativeMethods.ManifestEtw.EtwEnableCallback m_etwCallback; // Trace Callback function + Interop.Advapi32.EtwEnableCallback m_etwCallback; // Trace Callback function private long m_regHandle; // Trace Registration Handle private byte m_level; // Tracing Level private long m_anyKeywordMask; // Trace Enable Flags @@ -165,14 +163,14 @@ namespace System.Diagnostics.Tracing /// reason the ETW Register call failed a NotSupported exception will be thrown. /// // - // + // // // // internal unsafe void Register(EventSource eventSource) { uint status; - m_etwCallback = new UnsafeNativeMethods.ManifestEtw.EtwEnableCallback(EtwEnableCallBack); + m_etwCallback = new Interop.Advapi32.EtwEnableCallback(EtwEnableCallBack); status = EventRegister(eventSource, m_etwCallback); if (status != 0) @@ -264,13 +262,13 @@ namespace System.Diagnostics.Tracing // // unsafe void EtwEnableCallBack( - [In] ref System.Guid sourceId, - [In] int controlCode, - [In] byte setLevel, - [In] long anyKeyword, - [In] long allKeyword, - [In] UnsafeNativeMethods.ManifestEtw.EVENT_FILTER_DESCRIPTOR* filterData, - [In] void* callbackContext + in System.Guid sourceId, + int controlCode, + byte setLevel, + long anyKeyword, + long allKeyword, + Interop.Advapi32.EVENT_FILTER_DESCRIPTOR* filterData, + void* callbackContext ) { // This is an optional callback API. We will therefore ignore any failures that happen as a @@ -281,7 +279,7 @@ namespace System.Diagnostics.Tracing ControllerCommand command = ControllerCommand.Update; IDictionary args = null; bool skipFinalOnControllerCommand = false; - if (controlCode == UnsafeNativeMethods.ManifestEtw.EVENT_CONTROL_CODE_ENABLE_PROVIDER) + if (controlCode == Interop.Advapi32.EVENT_CONTROL_CODE_ENABLE_PROVIDER) { m_enabled = true; m_level = setLevel; @@ -342,7 +340,7 @@ namespace System.Diagnostics.Tracing OnControllerCommand(command, args, (bEnabling ? sessionChanged : -sessionChanged), etwSessionId); } } - else if (controlCode == UnsafeNativeMethods.ManifestEtw.EVENT_CONTROL_CODE_DISABLE_PROVIDER) + else if (controlCode == Interop.Advapi32.EVENT_CONTROL_CODE_DISABLE_PROVIDER) { m_enabled = false; m_level = 0; @@ -350,7 +348,7 @@ namespace System.Diagnostics.Tracing m_allKeywordMask = 0; m_liveSessions = null; } - else if (controlCode == UnsafeNativeMethods.ManifestEtw.EVENT_CONTROL_CODE_CAPTURE_STATE) + else if (controlCode == Interop.Advapi32.EVENT_CONTROL_CODE_CAPTURE_STATE) { command = ControllerCommand.SendManifest; } @@ -491,24 +489,24 @@ namespace System.Diagnostics.Tracing fixed (Guid* provider = &m_providerId) { - hr = UnsafeNativeMethods.ManifestEtw.EnumerateTraceGuidsEx(UnsafeNativeMethods.ManifestEtw.TRACE_QUERY_INFO_CLASS.TraceGuidQueryInfo, - provider, sizeof(Guid), buffer, buffSize, ref buffSize); + hr = Interop.Advapi32.EnumerateTraceGuidsEx(Interop.Advapi32.TRACE_QUERY_INFO_CLASS.TraceGuidQueryInfo, + provider, sizeof(Guid), buffer, buffSize, out buffSize); } if (hr == 0) break; - if (hr != 122 /* ERROR_INSUFFICIENT_BUFFER */) + if (hr != Interop.Errors.ERROR_INSUFFICIENT_BUFFER) return; } - var providerInfos = (UnsafeNativeMethods.ManifestEtw.TRACE_GUID_INFO*)buffer; - var providerInstance = (UnsafeNativeMethods.ManifestEtw.TRACE_PROVIDER_INSTANCE_INFO*)&providerInfos[1]; + var providerInfos = (Interop.Advapi32.TRACE_GUID_INFO*)buffer; + var providerInstance = (Interop.Advapi32.TRACE_PROVIDER_INSTANCE_INFO*)&providerInfos[1]; int processId = unchecked((int)Interop.Kernel32.GetCurrentProcessId()); // iterate over the instances of the EventProvider in all processes for (int i = 0; i < providerInfos->InstanceCount; i++) { if (providerInstance->Pid == processId) { - var enabledInfos = (UnsafeNativeMethods.ManifestEtw.TRACE_ENABLE_INFO*)&providerInstance[1]; + var enabledInfos = (Interop.Advapi32.TRACE_ENABLE_INFO*)&providerInstance[1]; // iterate over the list of active ETW sessions "listening" to the current provider for (int j = 0; j < providerInstance->EnableCount; j++) action(enabledInfos[j].LoggerId, enabledInfos[j].MatchAllKeyword, ref sessionList); @@ -517,7 +515,7 @@ namespace System.Diagnostics.Tracing break; Debug.Assert(0 <= providerInstance->NextOffset && providerInstance->NextOffset < buffSize); var structBase = (byte*)providerInstance; - providerInstance = (UnsafeNativeMethods.ManifestEtw.TRACE_PROVIDER_INSTANCE_INFO*)&structBase[providerInstance->NextOffset]; + providerInstance = (Interop.Advapi32.TRACE_PROVIDER_INSTANCE_INFO*)&structBase[providerInstance->NextOffset]; } #else #if !ES_BUILD_PCL && PLATFORM_WINDOWS // TODO command arguments don't work on PCL builds... @@ -602,7 +600,7 @@ namespace System.Diagnostics.Tracing /// starts, and the command being issued associated with that data. /// private unsafe bool GetDataFromController(int etwSessionId, - UnsafeNativeMethods.ManifestEtw.EVENT_FILTER_DESCRIPTOR* filterData, out ControllerCommand command, out byte[] data, out int dataStart) + Interop.Advapi32.EVENT_FILTER_DESCRIPTOR* filterData, out ControllerCommand command, out byte[] data, out int dataStart) { data = null; dataStart = 0; @@ -704,18 +702,9 @@ namespace System.Diagnostics.Tracing // // Helper function to set the last error on the thread // - private static void SetLastError(int error) + private static void SetLastError(WriteEventErrorCode error) { - switch (error) - { - case UnsafeNativeMethods.ManifestEtw.ERROR_ARITHMETIC_OVERFLOW: - case UnsafeNativeMethods.ManifestEtw.ERROR_MORE_DATA: - s_returnCode = WriteEventErrorCode.EventTooBig; - break; - case UnsafeNativeMethods.ManifestEtw.ERROR_NOT_ENOUGH_MEMORY: - s_returnCode = WriteEventErrorCode.NoFreeBuffers; - break; - } + s_returnCode = error; } // @@ -961,7 +950,7 @@ namespace System.Diagnostics.Tracing /// Payload for the ETW event. /// // - // + // // // // @@ -981,7 +970,7 @@ namespace System.Diagnostics.Tracing [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")] internal unsafe bool WriteEvent(ref EventDescriptor eventDescriptor, IntPtr eventHandle, Guid* activityID, Guid* childActivityID, params object[] eventPayload) { - int status = 0; + WriteEventErrorCode status = WriteEventErrorCode.NoError; if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords)) { @@ -1109,7 +1098,7 @@ namespace System.Diagnostics.Tracing userDataPtr[refObjPosition[7]].Ptr = (ulong)v7; } - status = m_eventProvider.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, eventHandle, activityID, childActivityID, argCount, userData); + status = m_eventProvider.EventWriteTransfer(m_regHandle, in eventDescriptor, eventHandle, activityID, childActivityID, argCount, userData); } } else @@ -1135,7 +1124,7 @@ namespace System.Diagnostics.Tracing } } - status = m_eventProvider.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, eventHandle, activityID, childActivityID, argCount, userData); + status = m_eventProvider.EventWriteTransfer(m_regHandle, in eventDescriptor, eventHandle, activityID, childActivityID, argCount, userData); for (int i = 0; i < refObjIndex; ++i) { @@ -1145,9 +1134,9 @@ namespace System.Diagnostics.Tracing } } - if (status != 0) + if (status != WriteEventErrorCode.NoError) { - SetLastError((int)status); + SetLastError(status); return false; } @@ -1174,7 +1163,7 @@ namespace System.Diagnostics.Tracing /// pointer do the event data /// // - // + // // [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")] internal protected unsafe bool WriteEvent(ref EventDescriptor eventDescriptor, IntPtr eventHandle, Guid* activityID, Guid* childActivityID, int dataCount, IntPtr data) @@ -1188,7 +1177,7 @@ namespace System.Diagnostics.Tracing (EventOpcode)eventDescriptor.Opcode == EventOpcode.Stop); } - int status = m_eventProvider.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, eventHandle, activityID, childActivityID, dataCount, (EventData*)data); + WriteEventErrorCode status = m_eventProvider.EventWriteTransfer(m_regHandle, in eventDescriptor, eventHandle, activityID, childActivityID, dataCount, (EventData*)data); if (status != 0) { @@ -1207,29 +1196,30 @@ namespace System.Diagnostics.Tracing int dataCount, IntPtr data) { - int status; + WriteEventErrorCode status; - status = m_eventProvider.EventWriteTransferWrapper( + status = m_eventProvider.EventWriteTransfer( m_regHandle, - ref eventDescriptor, + in eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, (EventData*)data); - if (status != 0) + if (status != WriteEventErrorCode.NoError) { SetLastError(status); return false; } + return true; } // These are look-alikes to the Manifest based ETW OS APIs that have been shimmed to work // either with Manifest ETW or Classic ETW (if Manifest based ETW is not available). - private unsafe uint EventRegister(EventSource eventSource, UnsafeNativeMethods.ManifestEtw.EtwEnableCallback enableCallback) + private unsafe uint EventRegister(EventSource eventSource, Interop.Advapi32.EtwEnableCallback enableCallback) { m_providerName = eventSource.Name; m_providerId = eventSource.Guid; @@ -1241,6 +1231,36 @@ namespace System.Diagnostics.Tracing { return m_eventProvider.EventUnregister(registrationHandle); } + +#if PLATFORM_WINDOWS + private static bool m_setInformationMissing; + + internal unsafe int SetInformation( + Interop.Advapi32.EVENT_INFO_CLASS eventInfoClass, + IntPtr data, + uint dataSize) + { + int status = Interop.Errors.ERROR_NOT_SUPPORTED; + + if (!m_setInformationMissing) + { + try + { + status = Interop.Advapi32.EventSetInformation( + m_regHandle, + eventInfoClass, + (void*)data, + (int)dataSize); + } + catch (TypeLoadException) + { + m_setInformationMissing = true; + } + } + + return status; + } +#endif } #if PLATFORM_WINDOWS @@ -1251,13 +1271,13 @@ namespace System.Diagnostics.Tracing // Register an event provider. unsafe uint IEventProvider.EventRegister( EventSource eventSource, - UnsafeNativeMethods.ManifestEtw.EtwEnableCallback enableCallback, + Interop.Advapi32.EtwEnableCallback enableCallback, void* callbackContext, ref long registrationHandle) { Guid providerId = eventSource.Guid; - return UnsafeNativeMethods.ManifestEtw.EventRegister( - ref providerId, + return Interop.Advapi32.EventRegister( + in providerId, enableCallback, callbackContext, ref registrationHandle); @@ -1266,32 +1286,43 @@ namespace System.Diagnostics.Tracing // Unregister an event provider. uint IEventProvider.EventUnregister(long registrationHandle) { - return UnsafeNativeMethods.ManifestEtw.EventUnregister(registrationHandle); + return Interop.Advapi32.EventUnregister(registrationHandle); } // Write an event. - unsafe int IEventProvider.EventWriteTransferWrapper( + unsafe EventProvider.WriteEventErrorCode IEventProvider.EventWriteTransfer( long registrationHandle, - ref EventDescriptor eventDescriptor, + in EventDescriptor eventDescriptor, IntPtr eventHandle, Guid* activityId, Guid* relatedActivityId, int userDataCount, EventProvider.EventData* userData) { - return UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper( + int error = Interop.Advapi32.EventWriteTransfer( registrationHandle, - ref eventDescriptor, + in eventDescriptor, activityId, relatedActivityId, userDataCount, userData); + + switch (error) + { + case Interop.Errors.ERROR_ARITHMETIC_OVERFLOW: + case Interop.Errors.ERROR_MORE_DATA: + return EventProvider.WriteEventErrorCode.EventTooBig; + case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY: + return EventProvider.WriteEventErrorCode.NoFreeBuffers; + } + + return EventProvider.WriteEventErrorCode.NoError; } // Get or set the per-thread activity ID. - int IEventProvider.EventActivityIdControl(UnsafeNativeMethods.ManifestEtw.ActivityControl ControlCode, ref Guid ActivityId) + int IEventProvider.EventActivityIdControl(Interop.Advapi32.ActivityControl ControlCode, ref Guid ActivityId) { - return UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( + return Interop.Advapi32.EventActivityIdControl( ControlCode, ref ActivityId); } @@ -1308,7 +1339,7 @@ namespace System.Diagnostics.Tracing { unsafe uint IEventProvider.EventRegister( EventSource eventSource, - UnsafeNativeMethods.ManifestEtw.EtwEnableCallback enableCallback, + Interop.Advapi32.EtwEnableCallback enableCallback, void* callbackContext, ref long registrationHandle) { @@ -1320,19 +1351,19 @@ namespace System.Diagnostics.Tracing return 0; } - unsafe int IEventProvider.EventWriteTransferWrapper( + unsafe EventProvider.WriteEventErrorCode IEventProvider.EventWriteTransfer( long registrationHandle, - ref EventDescriptor eventDescriptor, + in EventDescriptor eventDescriptor, IntPtr eventHandle, Guid* activityId, Guid* relatedActivityId, int userDataCount, EventProvider.EventData* userData) { - return 0; + return EventProvider.WriteEventErrorCode.NoError; } - int IEventProvider.EventActivityIdControl(UnsafeNativeMethods.ManifestEtw.ActivityControl ControlCode, ref Guid ActivityId) + int IEventProvider.EventActivityIdControl(Interop.Advapi32.ActivityControl ControlCode, ref Guid ActivityId) { return 0; } diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs index 95ac1da..50343b4 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs @@ -132,8 +132,7 @@ // where it will write it to // // All ETW writes eventually call -// EventWriteTransfer (native PINVOKE wrapper) -// EventWriteTransferWrapper (fixes compat problem if you pass null as the related activityID) +// EventWriteTransfer // EventProvider.WriteEventRaw - sets last error // EventSource.WriteEventRaw - Does EventSource exception handling logic // WriteMultiMerge @@ -499,6 +498,123 @@ namespace System.Diagnostics.Tracing } } +#region ActivityID + + /// + /// When a thread starts work that is on behalf of 'something else' (typically another + /// thread or network request) it should mark the thread as working on that other work. + /// This API marks the current thread as working on activity 'activityID'. This API + /// should be used when the caller knows the thread's current activity (the one being + /// overwritten) has completed. Otherwise, callers should prefer the overload that + /// return the oldActivityThatWillContinue (below). + /// + /// All events created with the EventSource on this thread are also tagged with the + /// activity ID of the thread. + /// + /// It is common, and good practice after setting the thread to an activity to log an event + /// with a 'start' opcode to indicate that precise time/thread where the new activity + /// started. + /// + /// A Guid that represents the new activity with which to mark + /// the current thread + public static void SetCurrentThreadActivityId(Guid activityId) + { + if (TplEventSource.Log != null) + TplEventSource.Log.SetActivityId(activityId); + + // We ignore errors to keep with the convention that EventSources do not throw errors. + // Note we can't access m_throwOnWrites because this is a static method. +#if FEATURE_MANAGED_ETW +#if FEATURE_PERFTRACING + // Set the activity id via EventPipe. + EventPipeInternal.EventActivityIdControl( + (uint)Interop.Advapi32.ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID, + ref activityId); +#endif // FEATURE_PERFTRACING +#if PLATFORM_WINDOWS + // Set the activity id via ETW. + Interop.Advapi32.EventActivityIdControl( + Interop.Advapi32.ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID, + ref activityId); +#endif // PLATFORM_WINDOWS +#endif // FEATURE_MANAGED_ETW + } + + /// + /// Retrieves the ETW activity ID associated with the current thread. + /// + public static Guid CurrentThreadActivityId + { + get + { + // We ignore errors to keep with the convention that EventSources do not throw + // errors. Note we can't access m_throwOnWrites because this is a static method. + Guid retVal = new Guid(); +#if FEATURE_MANAGED_ETW +#if PLATFORM_WINDOWS + Interop.Advapi32.EventActivityIdControl( + Interop.Advapi32.ActivityControl.EVENT_ACTIVITY_CTRL_GET_ID, + ref retVal); +#elif FEATURE_PERFTRACING + EventPipeInternal.EventActivityIdControl( + (uint)Interop.Advapi32.ActivityControl.EVENT_ACTIVITY_CTRL_GET_ID, + ref retVal); +#endif // PLATFORM_WINDOWS +#endif // FEATURE_MANAGED_ETW + return retVal; + } + } + + /// + /// When a thread starts work that is on behalf of 'something else' (typically another + /// thread or network request) it should mark the thread as working on that other work. + /// This API marks the current thread as working on activity 'activityID'. It returns + /// whatever activity the thread was previously marked with. There is a convention that + /// callers can assume that callees restore this activity mark before the callee returns. + /// To encourage this, this API returns the old activity, so that it can be restored later. + /// + /// All events created with the EventSource on this thread are also tagged with the + /// activity ID of the thread. + /// + /// It is common, and good practice after setting the thread to an activity to log an event + /// with a 'start' opcode to indicate that precise time/thread where the new activity + /// started. + /// + /// A Guid that represents the new activity with which to mark + /// the current thread + /// The Guid that represents the current activity + /// which will continue at some point in the future, on the current thread + public static void SetCurrentThreadActivityId(Guid activityId, out Guid oldActivityThatWillContinue) + { + oldActivityThatWillContinue = activityId; +#if FEATURE_MANAGED_ETW + // We ignore errors to keep with the convention that EventSources do not throw errors. + // Note we can't access m_throwOnWrites because this is a static method. + +#if FEATURE_PERFTRACING && PLATFORM_WINDOWS + EventPipeInternal.EventActivityIdControl( + (uint)Interop.Advapi32.ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID, + ref oldActivityThatWillContinue); +#elif FEATURE_PERFTRACING + EventPipeInternal.EventActivityIdControl( + (uint)Interop.Advapi32.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID, + ref oldActivityThatWillContinue); +#endif // FEATURE_PERFTRACING && PLATFORM_WINDOWS + +#if PLATFORM_WINDOWS + Interop.Advapi32.EventActivityIdControl( + Interop.Advapi32.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID, + ref oldActivityThatWillContinue); +#endif // PLATFORM_WINDOWS +#endif // FEATURE_MANAGED_ETW + + // We don't call the activityDying callback here because the caller has declared that + // it is not dying. + if (TplEventSource.Log != null) + TplEventSource.Log.SetActivityId(activityId); + } +#endregion + #region protected /// /// This is the constructor that most users will use to create their eventSource. It takes @@ -1390,7 +1506,7 @@ namespace System.Diagnostics.Tracing IntPtr providerMetadata = metadataHandle.AddrOfPinnedObject(); setInformationResult = m_etwProvider.SetInformation( - UnsafeNativeMethods.ManifestEtw.EVENT_INFO_CLASS.SetTraits, + Interop.Advapi32.EVENT_INFO_CLASS.SetTraits, providerMetadata, (uint)this.providerMetadata.Length); @@ -2321,12 +2437,40 @@ namespace System.Diagnostics.Tracing root them and modify shared library definition to force export them. */ #if ES_BUILD_PN - public + public #else - internal + internal #endif partial struct EventMetadata { +#if ES_BUILD_PN + public EventMetadata(EventDescriptor descriptor, + EventTags tags, + bool enabledForAnyListener, + bool enabledForETW, + string name, + string message, + EventParameterType[] parameterTypes) + { + this.Descriptor = descriptor; + this.Tags = tags; + this.EnabledForAnyListener = enabledForAnyListener; + this.EnabledForETW = enabledForETW; +#if FEATURE_PERFTRACING + this.EnabledForEventPipe = false; +#endif + this.TriggersActivityTracking = 0; + this.Name = name; + this.Message = message; + this.Parameters = null; + this.TraceLoggingEventTypes = null; + this.ActivityOptions = EventActivityOptions.None; + this.ParameterTypes = parameterTypes; + this.HasRelatedActivityID = false; + this.EventHandle = IntPtr.Zero; + } +#endif + public EventDescriptor Descriptor; public IntPtr EventHandle; // EventPipeEvent handle. public EventTags Tags; @@ -2352,6 +2496,114 @@ namespace System.Diagnostics.Tracing #endif }; +#if !ES_BUILD_PN + private int GetParameterCount(EventMetadata eventData) + { + return eventData.Parameters.Length; + } + + private Type GetDataType(EventMetadata eventData, int parameterId) + { + return eventData.Parameters[parameterId].ParameterType; + } + + private static readonly bool m_EventSourcePreventRecursion = false; +#else + private int GetParameterCount(EventMetadata eventData) + { + int paramCount; + if(eventData.Parameters == null) + { + paramCount = eventData.ParameterTypes.Length; + } + else + { + paramCount = eventData.Parameters.Length; + } + + return paramCount; + } + + private Type GetDataType(EventMetadata eventData, int parameterId) + { + Type dataType; + if(eventData.Parameters == null) + { + dataType = EventTypeToType(eventData.ParameterTypes[parameterId]); + } + else + { + dataType = eventData.Parameters[parameterId].ParameterType; + } + + return dataType; + } + + private static readonly bool m_EventSourcePreventRecursion = true; + + public enum EventParameterType + { + Boolean, + Byte, + SByte, + Char, + Int16, + UInt16, + Int32, + UInt32, + Int64, + UInt64, + IntPtr, + Single, + Double, + Decimal, + Guid, + String + } + + private Type EventTypeToType(EventParameterType type) + { + switch (type) + { + case EventParameterType.Boolean: + return typeof(bool); + case EventParameterType.Byte: + return typeof(byte); + case EventParameterType.SByte: + return typeof(sbyte); + case EventParameterType.Char: + return typeof(char); + case EventParameterType.Int16: + return typeof(short); + case EventParameterType.UInt16: + return typeof(ushort); + case EventParameterType.Int32: + return typeof(int); + case EventParameterType.UInt32: + return typeof(uint); + case EventParameterType.Int64: + return typeof(long); + case EventParameterType.UInt64: + return typeof(ulong); + case EventParameterType.IntPtr: + return typeof(IntPtr); + case EventParameterType.Single: + return typeof(float); + case EventParameterType.Double: + return typeof(double); + case EventParameterType.Decimal: + return typeof(decimal); + case EventParameterType.Guid: + return typeof(Guid); + case EventParameterType.String: + return typeof(string); + default: + // TODO: should I throw an exception here? + return null; + } + } +#endif + // This is the internal entry point that code:EventListeners call when wanting to send a command to a // eventSource. The logic is as follows // @@ -5102,7 +5354,7 @@ namespace System.Diagnostics.Tracing /// ManifestBuilder is designed to isolate the details of the message of the event from the /// rest of EventSource. This one happens to create XML. /// - internal partial class ManifestBuilder + internal class ManifestBuilder { /// /// Build a manifest for 'providerName' with the given GUID, which will be packaged into 'dllName'. @@ -5839,7 +6091,46 @@ namespace System.Diagnostics.Tracing return typeName.Replace("win:Int", "win:UInt"); // ETW requires enums to be unsigned. } - return GetTypeNameHelper(type); + switch (type.GetTypeCode()) + { + case TypeCode.Boolean: + return "win:Boolean"; + case TypeCode.Byte: + return "win:UInt8"; + case TypeCode.Char: + case TypeCode.UInt16: + return "win:UInt16"; + case TypeCode.UInt32: + return "win:UInt32"; + case TypeCode.UInt64: + return "win:UInt64"; + case TypeCode.SByte: + return "win:Int8"; + case TypeCode.Int16: + return "win:Int16"; + case TypeCode.Int32: + return "win:Int32"; + case TypeCode.Int64: + return "win:Int64"; + case TypeCode.String: + return "win:UnicodeString"; + case TypeCode.Single: + return "win:Float"; + case TypeCode.Double: + return "win:Double"; + case TypeCode.DateTime: + return "win:FILETIME"; + default: + if (type == typeof(Guid)) + return "win:GUID"; + else if (type == typeof(IntPtr)) + return "win:Pointer"; + else if ((type.IsArray || type.IsPointer) && type.GetElementType() == typeof(byte)) + return "win:Binary"; + + ManifestError(SR.Format(SR.EventSource_UnsupportedEventTypeInManifest, type.Name), true); + return string.Empty; + } } private static void UpdateStringBuilder(ref StringBuilder stringBuilder, string eventMessage, int startIndex, int count) diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IEventProvider.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IEventProvider.cs index 9bbebc7..bc7ab9a 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IEventProvider.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IEventProvider.cs @@ -17,7 +17,7 @@ namespace System.Diagnostics.Tracing // Register an event provider. unsafe uint EventRegister( EventSource eventSource, - UnsafeNativeMethods.ManifestEtw.EtwEnableCallback enableCallback, + Interop.Advapi32.EtwEnableCallback enableCallback, void* callbackContext, ref long registrationHandle); @@ -25,9 +25,9 @@ namespace System.Diagnostics.Tracing uint EventUnregister(long registrationHandle); // Write an event. - unsafe int EventWriteTransferWrapper( + unsafe EventProvider.WriteEventErrorCode EventWriteTransfer( long registrationHandle, - ref EventDescriptor eventDescriptor, + in EventDescriptor eventDescriptor, IntPtr eventHandle, Guid* activityId, Guid* relatedActivityId, @@ -35,7 +35,7 @@ namespace System.Diagnostics.Tracing EventProvider.EventData* userData); // Get or set the per-thread activity ID. - int EventActivityIdControl(UnsafeNativeMethods.ManifestEtw.ActivityControl ControlCode, ref Guid ActivityId); + int EventActivityIdControl(Interop.Advapi32.ActivityControl ControlCode, ref Guid ActivityId); // Define an EventPipeEvent handle. unsafe IntPtr DefineEventHandle(uint eventID, string eventName, long keywords, uint eventVersion, uint level, byte *pMetadata, uint metadataLength); diff --git a/src/System.Private.CoreLib/src/Microsoft/Win32/UnsafeNativeMethods.cs b/src/System.Private.CoreLib/src/Microsoft/Win32/UnsafeNativeMethods.cs index 2f69f63..25e382b 100644 --- a/src/System.Private.CoreLib/src/Microsoft/Win32/UnsafeNativeMethods.cs +++ b/src/System.Private.CoreLib/src/Microsoft/Win32/UnsafeNativeMethods.cs @@ -14,181 +14,6 @@ namespace Microsoft.Win32 internal static class UnsafeNativeMethods { - internal static unsafe class ManifestEtw - { - // - // Constants error coded returned by ETW APIs - // - - // The event size is larger than the allowed maximum (64k - header). - internal const int ERROR_ARITHMETIC_OVERFLOW = 534; - - // Occurs when filled buffers are trying to flush to disk, - // but disk IOs are not happening fast enough. - // This happens when the disk is slow and event traffic is heavy. - // Eventually, there are no more free (empty) buffers and the event is dropped. - internal const int ERROR_NOT_ENOUGH_MEMORY = 8; - - internal const int ERROR_MORE_DATA = 0xEA; - internal const int ERROR_NOT_SUPPORTED = 50; - internal const int ERROR_INVALID_PARAMETER = 0x57; - - // - // ETW Methods - // - - internal const int EVENT_CONTROL_CODE_DISABLE_PROVIDER = 0; - internal const int EVENT_CONTROL_CODE_ENABLE_PROVIDER = 1; - internal const int EVENT_CONTROL_CODE_CAPTURE_STATE = 2; - - // - // Callback - // - internal delegate void EtwEnableCallback( - [In] ref Guid sourceId, - [In] int isEnabled, - [In] byte level, - [In] long matchAnyKeywords, - [In] long matchAllKeywords, - [In] EVENT_FILTER_DESCRIPTOR* filterData, - [In] void* callbackContext - ); - - // - // Registration APIs - // - [DllImport(Interop.Libraries.Advapi32, ExactSpelling = true, EntryPoint = "EventRegister", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] - internal static extern unsafe uint EventRegister( - [In] ref Guid providerId, - [In]EtwEnableCallback enableCallback, - [In]void* callbackContext, - [In][Out]ref long registrationHandle - ); - - // - [DllImport(Interop.Libraries.Advapi32, ExactSpelling = true, EntryPoint = "EventUnregister", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] - internal static extern uint EventUnregister([In] long registrationHandle); - - [DllImport(Interop.Libraries.Advapi32, ExactSpelling = true, EntryPoint = "EventWriteString", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] - internal static extern int EventWriteString( - [In] long registrationHandle, - [In] byte level, - [In] long keyword, - [In] string msg - ); - - [StructLayout(LayoutKind.Sequential)] - internal struct EVENT_FILTER_DESCRIPTOR - { - public long Ptr; - public int Size; - public int Type; - }; - - /// - /// Call the ETW native API EventWriteTransfer and checks for invalid argument error. - /// The implementation of EventWriteTransfer on some older OSes (Windows 2008) does not accept null relatedActivityId. - /// So, for these cases we will retry the call with an empty Guid. - /// - internal static int EventWriteTransferWrapper(long registrationHandle, - ref EventDescriptor eventDescriptor, - Guid* activityId, - Guid* relatedActivityId, - int userDataCount, - EventProvider.EventData* userData) - { - int HResult = EventWriteTransfer(registrationHandle, ref eventDescriptor, activityId, relatedActivityId, userDataCount, userData); - if (HResult == ERROR_INVALID_PARAMETER && relatedActivityId == null) - { - Guid emptyGuid = Guid.Empty; - HResult = EventWriteTransfer(registrationHandle, ref eventDescriptor, activityId, &emptyGuid, userDataCount, userData); - } - - return HResult; - } - - [DllImport(Interop.Libraries.Advapi32, ExactSpelling = true, EntryPoint = "EventWriteTransfer", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] - private static extern int EventWriteTransfer( - [In] long registrationHandle, - [In] ref EventDescriptor eventDescriptor, - [In] Guid* activityId, - [In] Guid* relatedActivityId, - [In] int userDataCount, - [In] EventProvider.EventData* userData - ); - - internal enum ActivityControl : uint - { - EVENT_ACTIVITY_CTRL_GET_ID = 1, - EVENT_ACTIVITY_CTRL_SET_ID = 2, - EVENT_ACTIVITY_CTRL_CREATE_ID = 3, - EVENT_ACTIVITY_CTRL_GET_SET_ID = 4, - EVENT_ACTIVITY_CTRL_CREATE_SET_ID = 5 - }; - - [DllImport(Interop.Libraries.Advapi32, ExactSpelling = true, EntryPoint = "EventActivityIdControl", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] - internal static extern int EventActivityIdControl([In] ActivityControl ControlCode, [In][Out] ref Guid ActivityId); - - internal enum EVENT_INFO_CLASS - { - BinaryTrackInfo, - SetEnableAllKeywords, - SetTraits, - } - - [DllImport(Interop.Libraries.Advapi32, ExactSpelling = true, EntryPoint = "EventSetInformation", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] - internal static extern int EventSetInformation( - [In] long registrationHandle, - [In] EVENT_INFO_CLASS informationClass, - [In] void* eventInformation, - [In] int informationLength); - - // Support for EnumerateTraceGuidsEx - internal enum TRACE_QUERY_INFO_CLASS - { - TraceGuidQueryList, - TraceGuidQueryInfo, - TraceGuidQueryProcess, - TraceStackTracingInfo, - MaxTraceSetInfoClass - }; - - internal struct TRACE_GUID_INFO - { - public int InstanceCount; - public int Reserved; - }; - - internal struct TRACE_PROVIDER_INSTANCE_INFO - { - public int NextOffset; - public int EnableCount; - public int Pid; - public int Flags; - }; - - internal struct TRACE_ENABLE_INFO - { - public int IsEnabled; - public byte Level; - public byte Reserved1; - public ushort LoggerId; - public int EnableProperty; - public int Reserved2; - public long MatchAnyKeyword; - public long MatchAllKeyword; - }; - - [DllImport(Interop.Libraries.Advapi32, ExactSpelling = true, EntryPoint = "EnumerateTraceGuidsEx", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] - internal static extern int EnumerateTraceGuidsEx( - TRACE_QUERY_INFO_CLASS TraceQueryInfoClass, - void* InBuffer, - int InBufferSize, - void* OutBuffer, - int OutBufferSize, - ref int ReturnLength); - } - #if FEATURE_COMINTEROP [DllImport("api-ms-win-core-winrt-l1-1-0.dll", PreserveSig = true)] internal static extern int RoGetActivationFactory( diff --git a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs index 763e78c..d44ac64 100644 --- a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs +++ b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs @@ -216,7 +216,7 @@ namespace System.Diagnostics.Tracing // These PInvokes are used by EventSource to interact with the EventPipe. // [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] - internal static extern IntPtr CreateProvider(string providerName, UnsafeNativeMethods.ManifestEtw.EtwEnableCallback callbackFunc); + internal static extern IntPtr CreateProvider(string providerName, Interop.Advapi32.EtwEnableCallback callbackFunc); [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] internal static extern unsafe IntPtr DefineEvent(IntPtr provHandle, uint eventID, long keywords, uint eventVersion, uint level, void *pMetadata, uint metadataLength); diff --git a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeEventProvider.cs b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeEventProvider.cs index 214788e..16903c8 100644 --- a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeEventProvider.cs +++ b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeEventProvider.cs @@ -19,7 +19,7 @@ namespace System.Diagnostics.Tracing // Register an event provider. unsafe uint IEventProvider.EventRegister( EventSource eventSource, - UnsafeNativeMethods.ManifestEtw.EtwEnableCallback enableCallback, + Interop.Advapi32.EtwEnableCallback enableCallback, void* callbackContext, ref long registrationHandle) { @@ -48,9 +48,9 @@ namespace System.Diagnostics.Tracing } // Write an event. - unsafe int IEventProvider.EventWriteTransferWrapper( + unsafe EventProvider.WriteEventErrorCode IEventProvider.EventWriteTransfer( long registrationHandle, - ref EventDescriptor eventDescriptor, + in EventDescriptor eventDescriptor, IntPtr eventHandle, Guid* activityId, Guid* relatedActivityId, @@ -63,7 +63,7 @@ namespace System.Diagnostics.Tracing if (userDataCount == 0) { EventPipeInternal.WriteEventData(eventHandle, eventID, null, 0, activityId, relatedActivityId); - return 0; + return EventProvider.WriteEventErrorCode.NoError; } // If Channel == 11, this is a TraceLogging event. @@ -77,11 +77,11 @@ namespace System.Diagnostics.Tracing } EventPipeInternal.WriteEventData(eventHandle, eventID, userData, (uint) userDataCount, activityId, relatedActivityId); } - return 0; + return EventProvider.WriteEventErrorCode.NoError; } // Get or set the per-thread activity ID. - int IEventProvider.EventActivityIdControl(UnsafeNativeMethods.ManifestEtw.ActivityControl ControlCode, ref Guid ActivityId) + int IEventProvider.EventActivityIdControl(Interop.Advapi32.ActivityControl ControlCode, ref Guid ActivityId) { return EventPipeInternal.EventActivityIdControl((uint)ControlCode, ref ActivityId); } diff --git a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventSource_CoreCLR.cs b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventSource_CoreCLR.cs deleted file mode 100644 index ae8650e..0000000 --- a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventSource_CoreCLR.cs +++ /dev/null @@ -1,230 +0,0 @@ -// 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.InteropServices; -using System.Threading.Tasks; -using Microsoft.Reflection; -using Microsoft.Win32; - -namespace System.Diagnostics.Tracing -{ - public partial class EventSource - { - // ActivityID support (see also WriteEventWithRelatedActivityIdCore) - /// - /// When a thread starts work that is on behalf of 'something else' (typically another - /// thread or network request) it should mark the thread as working on that other work. - /// This API marks the current thread as working on activity 'activityID'. This API - /// should be used when the caller knows the thread's current activity (the one being - /// overwritten) has completed. Otherwise, callers should prefer the overload that - /// return the oldActivityThatWillContinue (below). - /// - /// All events created with the EventSource on this thread are also tagged with the - /// activity ID of the thread. - /// - /// It is common, and good practice after setting the thread to an activity to log an event - /// with a 'start' opcode to indicate that precise time/thread where the new activity - /// started. - /// - /// A Guid that represents the new activity with which to mark - /// the current thread - public static void SetCurrentThreadActivityId(Guid activityId) - { - if (TplEventSource.Log != null) - TplEventSource.Log.SetActivityId(activityId); - - // We ignore errors to keep with the convention that EventSources do not throw errors. - // Note we can't access m_throwOnWrites because this is a static method. -#if FEATURE_MANAGED_ETW -#if FEATURE_PERFTRACING - // Set the activity id via EventPipe. - EventPipeInternal.EventActivityIdControl( - (uint)UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID, - ref activityId); -#endif // FEATURE_PERFTRACING -#if PLATFORM_WINDOWS - // Set the activity id via ETW. - UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( - UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID, - ref activityId); -#endif // PLATFORM_WINDOWS -#endif // FEATURE_MANAGED_ETW - } - - /// - /// When a thread starts work that is on behalf of 'something else' (typically another - /// thread or network request) it should mark the thread as working on that other work. - /// This API marks the current thread as working on activity 'activityID'. It returns - /// whatever activity the thread was previously marked with. There is a convention that - /// callers can assume that callees restore this activity mark before the callee returns. - /// To encourage this, this API returns the old activity, so that it can be restored later. - /// - /// All events created with the EventSource on this thread are also tagged with the - /// activity ID of the thread. - /// - /// It is common, and good practice after setting the thread to an activity to log an event - /// with a 'start' opcode to indicate that precise time/thread where the new activity - /// started. - /// - /// A Guid that represents the new activity with which to mark - /// the current thread - /// The Guid that represents the current activity - /// which will continue at some point in the future, on the current thread - public static void SetCurrentThreadActivityId(Guid activityId, out Guid oldActivityThatWillContinue) - { - oldActivityThatWillContinue = activityId; -#if FEATURE_MANAGED_ETW - // We ignore errors to keep with the convention that EventSources do not throw errors. - // Note we can't access m_throwOnWrites because this is a static method. - -#if FEATURE_PERFTRACING && PLATFORM_WINDOWS - EventPipeInternal.EventActivityIdControl( - (uint)UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID, - ref oldActivityThatWillContinue); -#elif FEATURE_PERFTRACING - EventPipeInternal.EventActivityIdControl( - (uint)UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID, - ref oldActivityThatWillContinue); -#endif // FEATURE_PERFTRACING && PLATFORM_WINDOWS - -#if PLATFORM_WINDOWS - UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( - UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID, - ref oldActivityThatWillContinue); -#endif // PLATFORM_WINDOWS -#endif // FEATURE_MANAGED_ETW - - // We don't call the activityDying callback here because the caller has declared that - // it is not dying. - if (TplEventSource.Log != null) - TplEventSource.Log.SetActivityId(activityId); - } - - /// - /// Retrieves the ETW activity ID associated with the current thread. - /// - public static Guid CurrentThreadActivityId - { - get - { - // We ignore errors to keep with the convention that EventSources do not throw - // errors. Note we can't access m_throwOnWrites because this is a static method. - Guid retVal = new Guid(); -#if FEATURE_MANAGED_ETW -#if PLATFORM_WINDOWS - UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( - UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_ID, - ref retVal); -#elif FEATURE_PERFTRACING - EventPipeInternal.EventActivityIdControl( - (uint)UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_ID, - ref retVal); -#endif // PLATFORM_WINDOWS -#endif // FEATURE_MANAGED_ETW - return retVal; - } - } - - private int GetParameterCount(EventMetadata eventData) - { - return eventData.Parameters.Length; - } - - private Type GetDataType(EventMetadata eventData, int parameterId) - { - return eventData.Parameters[parameterId].ParameterType; - } - - private static string GetResourceString(string key, params object[] args) - { - return SR.Format(SR.GetResourceString(key), args); - } - - private static readonly bool m_EventSourcePreventRecursion = false; - } - - internal partial class ManifestBuilder - { - private string GetTypeNameHelper(Type type) - { - switch (type.GetTypeCode()) - { - case TypeCode.Boolean: - return "win:Boolean"; - case TypeCode.Byte: - return "win:UInt8"; - case TypeCode.Char: - case TypeCode.UInt16: - return "win:UInt16"; - case TypeCode.UInt32: - return "win:UInt32"; - case TypeCode.UInt64: - return "win:UInt64"; - case TypeCode.SByte: - return "win:Int8"; - case TypeCode.Int16: - return "win:Int16"; - case TypeCode.Int32: - return "win:Int32"; - case TypeCode.Int64: - return "win:Int64"; - case TypeCode.String: - return "win:UnicodeString"; - case TypeCode.Single: - return "win:Float"; - case TypeCode.Double: - return "win:Double"; - case TypeCode.DateTime: - return "win:FILETIME"; - default: - if (type == typeof(Guid)) - return "win:GUID"; - else if (type == typeof(IntPtr)) - return "win:Pointer"; - else if ((type.IsArray || type.IsPointer) && type.GetElementType() == typeof(byte)) - return "win:Binary"; - - ManifestError(Resources.GetResourceString("EventSource_UnsupportedEventTypeInManifest", type.Name), true); - return string.Empty; - } - } - } - - internal partial class EventProvider - { - internal unsafe int SetInformation( - UnsafeNativeMethods.ManifestEtw.EVENT_INFO_CLASS eventInfoClass, - IntPtr data, - uint dataSize) - { - int status = UnsafeNativeMethods.ManifestEtw.ERROR_NOT_SUPPORTED; - - if (!m_setInformationMissing) - { - try - { - status = UnsafeNativeMethods.ManifestEtw.EventSetInformation( - m_regHandle, - eventInfoClass, - (void*)data, - (int)dataSize); - } - catch (TypeLoadException) - { - m_setInformationMissing = true; - } - } - - return status; - } - } - - internal static class Resources - { - internal static string GetResourceString(string key, params object[] args) - { - return SR.Format(SR.GetResourceString(key), args); - } - } -} -- 2.7.4