diff --git a/external/corefx-bugfix/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventCounter.cs b/external/corefx-bugfix/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventCounter.cs new file mode 100644 index 000000000000..dcb69ca07712 --- /dev/null +++ b/external/corefx-bugfix/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventCounter.cs @@ -0,0 +1,506 @@ +// 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.Collections; +using System.Collections.Generic; +using System.Threading; +#if ES_BUILD_PCL + using System.Threading.Tasks; +#endif + +#if MONO +using System.Diagnostics.Private; +#endif + +#if ES_BUILD_STANDALONE +namespace Microsoft.Diagnostics.Tracing +#else +namespace System.Diagnostics.Tracing +#endif +{ + /// + /// Provides the ability to collect statistics through EventSource + /// + /// See https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.Tracing/documentation/EventCounterTutorial.md + /// for a tutorial guide. + /// + /// See https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.cs + /// which shows tests, which are also useful in seeing actual use. + /// + public class EventCounter : IDisposable + { + /// + /// Initializes a new instance of the class. + /// EVentCounters live as long as the EventSource that they are attached to unless they are + /// explicitly Disposed. + /// + /// The name. + /// The event source. + public EventCounter(string name, EventSource eventSource) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + if (eventSource == null) + { + throw new ArgumentNullException(nameof(eventSource)); + } + + InitializeBuffer(); + _name = name; + _group = EventCounterGroup.GetEventCounterGroup(eventSource); + _group.Add(this); + _min = float.PositiveInfinity; + _max = float.NegativeInfinity; + } + + /// + /// Writes 'value' to the stream of values tracked by the counter. This updates the sum and other statistics that will + /// be logged on the next timer interval. + /// + /// The value. + public void WriteMetric(float value) + { + Enqueue(value); + } + + /// + /// Removes the counter from set that the EventSource will report on. After being disposed, this + /// counter will do nothing and its resource will be reclaimed if all references to it are removed. + /// If an EventCounter is not explicitly disposed it will be cleaned up automatically when the + /// EventSource it is attached to dies. + /// + public void Dispose() + { + var group = _group; + if (group != null) + { + group.Remove(this); + _group = null; + } + } + + public override string ToString() + { + return "EventCounter '" + _name + "' Count " + _count + " Mean " + (((double)_sum) / _count).ToString("n3"); + } + #region private implementation + + private readonly string _name; + private EventCounterGroup _group; + + #region Buffer Management + + // Values buffering + private const int BufferedSize = 10; + private const float UnusedBufferSlotValue = float.NegativeInfinity; + private const int UnsetIndex = -1; + private volatile float[] _bufferedValues; + private volatile int _bufferedValuesIndex; + + // arbitrarily we use _bufferfValues as the lock object. + private object MyLock { get { return _bufferedValues; } } + + private void InitializeBuffer() + { + _bufferedValues = new float[BufferedSize]; + for (int i = 0; i < _bufferedValues.Length; i++) + { + _bufferedValues[i] = UnusedBufferSlotValue; + } + } + + private void Enqueue(float value) + { + // It is possible that two threads read the same bufferedValuesIndex, but only one will be able to write the slot, so that is okay. + int i = _bufferedValuesIndex; + while (true) + { + float result = Interlocked.CompareExchange(ref _bufferedValues[i], value, UnusedBufferSlotValue); + i++; + if (_bufferedValues.Length <= i) + { + // It is possible that two threads both think the buffer is full, but only one get to actually flush it, the other + // will eventually enter this code path and potentially calling Flushing on a buffer that is not full, and that's okay too. + lock (MyLock) // Lock the counter + Flush(); + i = 0; + } + + if (result == UnusedBufferSlotValue) + { + // CompareExchange succeeded + _bufferedValuesIndex = i; + return; + } + } + } + + private void Flush() + { + Debug.Assert(Monitor.IsEntered(MyLock)); + for (int i = 0; i < _bufferedValues.Length; i++) + { + var value = Interlocked.Exchange(ref _bufferedValues[i], UnusedBufferSlotValue); + if (value != UnusedBufferSlotValue) + { + OnMetricWritten(value); + } + } + + _bufferedValuesIndex = 0; + } + + #endregion // Buffer Management + + #region Statistics Calculation + + // Statistics + private int _count; + private float _sum; + private float _sumSquared; + private float _min; + private float _max; + + private void OnMetricWritten(float value) + { + Debug.Assert(Monitor.IsEntered(MyLock)); + _sum += value; + _sumSquared += value * value; + if (value > _max) + _max = value; + + if (value < _min) + _min = value; + + _count++; + } + + internal EventCounterPayload GetEventCounterPayload() + { + lock (MyLock) // Lock the counter + { + Flush(); + EventCounterPayload result = new EventCounterPayload(); + result.Name = _name; + result.Count = _count; + if (0 < _count) + { + result.Mean = _sum / _count; + result.StandardDeviation = (float)Math.Sqrt(_sumSquared / _count - _sum * _sum / _count / _count); + } + else + { + result.Mean = 0; + result.StandardDeviation = 0; + } + result.Min = _min; + result.Max = _max; + ResetStatistics(); + return result; + } + } + + private void ResetStatistics() + { + Debug.Assert(Monitor.IsEntered(MyLock)); + _count = 0; + _sum = 0; + _sumSquared = 0; + _min = float.PositiveInfinity; + _max = float.NegativeInfinity; + } + + #endregion // Statistics Calculation + + #endregion // private implementation + } + + #region internal supporting classes + + [EventData] + internal class EventCounterPayload : IEnumerable> + { + public string Name { get; set; } + + public float Mean { get; set; } + + public float StandardDeviation { get; set; } + + public int Count { get; set; } + + public float Min { get; set; } + + public float Max { get; set; } + + public float IntervalSec { get; internal set; } + + #region Implementation of the IEnumerable interface + + public IEnumerator> GetEnumerator() + { + return ForEnumeration.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ForEnumeration.GetEnumerator(); + } + + private IEnumerable> ForEnumeration + { + get + { + yield return new KeyValuePair("Name", Name); + yield return new KeyValuePair("Mean", Mean); + yield return new KeyValuePair("StandardDeviation", StandardDeviation); + yield return new KeyValuePair("Count", Count); + yield return new KeyValuePair("Min", Min); + yield return new KeyValuePair("Max", Max); + } + } + + #endregion // Implementation of the IEnumerable interface + } + + internal class EventCounterGroup + { + private readonly EventSource _eventSource; + private readonly List _eventCounters; + + internal EventCounterGroup(EventSource eventSource) + { + _eventSource = eventSource; + _eventCounters = new List(); + RegisterCommandCallback(); + } + + internal void Add(EventCounter eventCounter) + { + lock (this) // Lock the EventCounterGroup + _eventCounters.Add(eventCounter); + } + + internal void Remove(EventCounter eventCounter) + { + lock (this) // Lock the EventCounterGroup + _eventCounters.Remove(eventCounter); + } + + #region EventSource Command Processing + + private void RegisterCommandCallback() + { + // Old destktop runtimes don't have this +#if NO_EVENTCOMMANDEXECUTED_SUPPORT + // We could not build against the API that had the EventCommandExecuted but maybe it is there are runtime. + // use reflection to try to get it. + System.Reflection.MethodInfo method = typeof(EventSource).GetMethod("add_EventCommandExecuted"); + if (method != null) + { + method.Invoke(_eventSource, new object[] { (EventHandler)OnEventSourceCommand }); + } + else + { + string msg = "EventCounterError: Old Runtime that does not support EventSource.EventCommandExecuted. EventCounters not Supported"; + _eventSource.Write(msg); + Debug.WriteLine(msg); + } +#else + _eventSource.EventCommandExecuted += OnEventSourceCommand; +#endif + } + + private void OnEventSourceCommand(object sender, EventCommandEventArgs e) + { + if (e.Command == EventCommand.Enable || e.Command == EventCommand.Update) + { + string valueStr; + float value; + if (e.Arguments.TryGetValue("EventCounterIntervalSec", out valueStr) && float.TryParse(valueStr, out value)) + { + // Recursion through EventSource callbacks possible. When we enable the timer + // we synchonously issue a EventSource.Write event, which in turn can call back + // to user code (in an EventListener) while holding this lock. This is dangerous + // because it mean this code might inadvertantly participate in a lock loop. + // The scenario seems very unlikely so we ignore that problem for now. + lock (this) // Lock the EventCounterGroup + { + EnableTimer(value); + } + } + } + } + + #endregion // EventSource Command Processing + + #region Global EventCounterGroup Array management + + // We need eventCounters to 'attach' themselves to a particular EventSource. + // this table provides the mapping from EventSource -> EventCounterGroup + // which represents this 'attached' information. + private static WeakReference[] s_eventCounterGroups; + private static readonly object s_eventCounterGroupsLock = new object(); + + private static void EnsureEventSourceIndexAvailable(int eventSourceIndex) + { + Debug.Assert(Monitor.IsEntered(s_eventCounterGroupsLock)); + if (EventCounterGroup.s_eventCounterGroups == null) + { + EventCounterGroup.s_eventCounterGroups = new WeakReference[eventSourceIndex + 1]; + } + else if (eventSourceIndex >= EventCounterGroup.s_eventCounterGroups.Length) + { + WeakReference[] newEventCounterGroups = new WeakReference[eventSourceIndex + 1]; + Array.Copy(EventCounterGroup.s_eventCounterGroups, 0, newEventCounterGroups, 0, EventCounterGroup.s_eventCounterGroups.Length); + EventCounterGroup.s_eventCounterGroups = newEventCounterGroups; + } + } + + internal static EventCounterGroup GetEventCounterGroup(EventSource eventSource) + { + lock (s_eventCounterGroupsLock) + { + int eventSourceIndex = EventListenerHelper.EventSourceIndex(eventSource); + EnsureEventSourceIndexAvailable(eventSourceIndex); + WeakReference weakRef = EventCounterGroup.s_eventCounterGroups[eventSourceIndex]; + EventCounterGroup ret = null; + if (weakRef == null || !weakRef.TryGetTarget(out ret)) + { + ret = new EventCounterGroup(eventSource); + EventCounterGroup.s_eventCounterGroups[eventSourceIndex] = new WeakReference(ret); + } + return ret; + } + } + + #endregion // Global EventCounterGroup Array management + + #region Timer Processing + + private DateTime _timeStampSinceCollectionStarted; + private int _pollingIntervalInMilliseconds; + private Timer _pollingTimer; + + private void DisposeTimer() + { + Debug.Assert(Monitor.IsEntered(this)); + if (_pollingTimer != null) + { + _pollingTimer.Dispose(); + _pollingTimer = null; + } + } + + private void EnableTimer(float pollingIntervalInSeconds) + { + Debug.Assert(Monitor.IsEntered(this)); + if (pollingIntervalInSeconds <= 0) + { + DisposeTimer(); + _pollingIntervalInMilliseconds = 0; + } + else if (_pollingIntervalInMilliseconds == 0 || pollingIntervalInSeconds * 1000 < _pollingIntervalInMilliseconds) + { + Debug.WriteLine("Polling interval changed at " + DateTime.UtcNow.ToString("mm.ss.ffffff")); + _pollingIntervalInMilliseconds = (int)(pollingIntervalInSeconds * 1000); + DisposeTimer(); + _timeStampSinceCollectionStarted = DateTime.UtcNow; + _pollingTimer = new Timer(OnTimer, null, _pollingIntervalInMilliseconds, _pollingIntervalInMilliseconds); + } + // Always fire the timer event (so you see everything up to this time). + OnTimer(null); + } + + private void OnTimer(object state) + { + Debug.WriteLine("Timer fired at " + DateTime.UtcNow.ToString("mm.ss.ffffff")); + lock (this) // Lock the EventCounterGroup + { + if (_eventSource.IsEnabled()) + { + DateTime now = DateTime.UtcNow; + TimeSpan elapsed = now - _timeStampSinceCollectionStarted; + + foreach (var eventCounter in _eventCounters) + { + EventCounterPayload payload = eventCounter.GetEventCounterPayload(); + payload.IntervalSec = (float)elapsed.TotalSeconds; + _eventSource.Write("EventCounters", new EventSourceOptions() { Level = EventLevel.LogAlways }, new PayloadType(payload)); + } + _timeStampSinceCollectionStarted = now; + } + else + { + DisposeTimer(); + } + } + } + + /// + /// This is the payload that is sent in the with EventSource.Write + /// + [EventData] + class PayloadType + { + public PayloadType(EventCounterPayload payload) { Payload = payload; } + public EventCounterPayload Payload { get; set; } + } + + #region PCL timer hack + +#if ES_BUILD_PCL + internal delegate void TimerCallback(object state); + + internal sealed class Timer : CancellationTokenSource, IDisposable + { + private int _period; + private TimerCallback _callback; + private object _state; + + internal Timer(TimerCallback callback, object state, int dueTime, int period) + { + _callback = callback; + _state = state; + _period = period; + Schedule(dueTime); + } + + private void Schedule(int dueTime) + { + Task.Delay(dueTime, Token).ContinueWith(OnTimer, null, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default); + } + + private void OnTimer(Task t, object s) + { + Schedule(_period); + _callback(_state); + } + + public new void Dispose() { base.Cancel(); } + } +#endif + #endregion // PCL timer hack + + #endregion // Timer Processing + + } + + // This class a work-around because .NET V4.6.2 did not make EventSourceIndex public (it was only protected) + // We make this helper class to get around that protection. We want V4.6.3 to make this public at which + // point this class is no longer needed and can be removed. + internal class EventListenerHelper : EventListener + { + public new static int EventSourceIndex(EventSource eventSource) { return EventListener.EventSourceIndex(eventSource); } + #if MONO + internal + #endif + protected override void OnEventWritten(EventWrittenEventArgs eventData) { } // override abstract methods to keep compiler happy + } + + #endregion // internal supporting classes +} diff --git a/external/corefx-bugfix/src/Common/src/CoreLib/System/Diagnostics/Tracing/unsafenativemethods.cs b/external/corefx-bugfix/src/Common/src/CoreLib/System/Diagnostics/Tracing/unsafenativemethods.cs new file mode 100644 index 000000000000..26b6dfddf65e --- /dev/null +++ b/external/corefx-bugfix/src/Common/src/CoreLib/System/Diagnostics/Tracing/unsafenativemethods.cs @@ -0,0 +1,235 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +/*============================================================ +** +** Class: UnsafeNativeMethods +** +============================================================*/ +namespace Microsoft.Win32 { + using Microsoft.Win32; + using Microsoft.Win32.SafeHandles; + using System; + using System.Runtime.CompilerServices; + using System.Runtime.ConstrainedExecution; + using System.Runtime.InteropServices; + using System.Runtime.Serialization; + using System.Runtime.Versioning; + using System.Security; + using System.Security.Permissions; + using System.Text; + using System.Diagnostics.Tracing; + + [System.Security.SecurityCritical] // auto-generated + [SuppressUnmanagedCodeSecurityAttribute()] + internal static class UnsafeNativeMethods + { + [SecurityCritical] + [SuppressUnmanagedCodeSecurityAttribute()] + 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 + // + [SecurityCritical] + internal unsafe 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 + // + [SecurityCritical] + [DllImport(Win32Native.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 + ); + + // + [SecurityCritical] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] + [DllImport(Win32Native.ADVAPI32, ExactSpelling = true, EntryPoint = "EventUnregister", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] + internal static extern uint EventUnregister([In] long registrationHandle); + + // + // Writing (Publishing/Logging) APIs + // + // + [SecurityCritical] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] + [DllImport(Win32Native.ADVAPI32, ExactSpelling = true, EntryPoint = "EventWrite", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] + internal static extern unsafe int EventWrite( + [In] long registrationHandle, + [In] ref EventDescriptor eventDescriptor, + [In] int userDataCount, + [In] EventProvider.EventData* userData + ); + + [SecurityCritical] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] + [DllImport(Win32Native.ADVAPI32, ExactSpelling = true, EntryPoint = "EventWriteString", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] + internal static extern unsafe int EventWriteString( + [In] long registrationHandle, + [In] byte level, + [In] long keyword, + [In] string msg + ); + + [StructLayout(LayoutKind.Sequential)] + unsafe 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; + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] + [DllImport(Win32Native.ADVAPI32, ExactSpelling = true, EntryPoint = "EventWriteTransfer", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] + [SuppressUnmanagedCodeSecurityAttribute] // Don't do security checks + 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 + }; + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] + [DllImport(Win32Native.ADVAPI32, ExactSpelling = true, EntryPoint = "EventActivityIdControl", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] + [SuppressUnmanagedCodeSecurityAttribute] // Don't do security checks + internal static extern int EventActivityIdControl([In] ActivityControl ControlCode, [In][Out] ref Guid ActivityId); + + internal enum EVENT_INFO_CLASS + { + BinaryTrackInfo, + SetEnableAllKeywords, + SetTraits, + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] + [DllImport(Win32Native.ADVAPI32, ExactSpelling = true, EntryPoint = "EventSetInformation", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] + [SuppressUnmanagedCodeSecurityAttribute] // Don't do security checks + 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; + }; + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] + [DllImport(Win32Native.ADVAPI32, ExactSpelling = true, EntryPoint = "EnumerateTraceGuidsEx", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] + [SuppressUnmanagedCodeSecurityAttribute] // Don't do security checks + internal static extern int EnumerateTraceGuidsEx( + TRACE_QUERY_INFO_CLASS TraceQueryInfoClass, + void* InBuffer, + int InBufferSize, + void* OutBuffer, + int OutBufferSize, + ref int ReturnLength); + + } + } +} diff --git a/mcs/class/corlib/ReferenceSources/win32native.cs b/mcs/class/corlib/ReferenceSources/win32native.cs index 06b5c9ea478a..2f27d85c2c69 100644 --- a/mcs/class/corlib/ReferenceSources/win32native.cs +++ b/mcs/class/corlib/ReferenceSources/win32native.cs @@ -79,5 +79,8 @@ internal class WIN32_FIND_DATA internal int dwFileAttributes = 0; internal String cFileName = null; } + + [DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)] + internal static extern uint GetCurrentProcessId(); } } \ No newline at end of file diff --git a/mcs/class/corlib/corlib-net_4_x.csproj b/mcs/class/corlib/corlib-net_4_x.csproj index f0e0c847d895..0748b480b981 100644 --- a/mcs/class/corlib/corlib-net_4_x.csproj +++ b/mcs/class/corlib/corlib-net_4_x.csproj @@ -293,11 +293,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + @@ -980,22 +1016,6 @@ - - - - - - - - - - - - - - - - diff --git a/mcs/class/corlib/corlib.dll.sources b/mcs/class/corlib/corlib.dll.sources index bd2fd295fdc5..67203168c076 100644 --- a/mcs/class/corlib/corlib.dll.sources +++ b/mcs/class/corlib/corlib.dll.sources @@ -167,22 +167,6 @@ System.Deployment.Internal/InternalApplicationIdentityHelper.cs System.Diagnostics/Debugger.cs System.Diagnostics/StackFrame.cs System.Diagnostics/StackTrace.cs -System.Diagnostics.Tracing/EventAttribute.cs -System.Diagnostics.Tracing/EventCommand.cs -System.Diagnostics.Tracing/EventCounter.cs -System.Diagnostics.Tracing/EventSource.cs -System.Diagnostics.Tracing/EventSourceAttribute.cs -System.Diagnostics.Tracing/EventSourceSettings.cs -System.Diagnostics.Tracing/EventCommandEventArgs.cs -System.Diagnostics.Tracing/EventListener.cs -System.Diagnostics.Tracing/EventWrittenEventArgs.cs -System.Diagnostics.Tracing/NonEventAttribute.cs -System.Diagnostics.Tracing/EventDataAttribute.cs -System.Diagnostics.Tracing/EventFieldAttribute.cs -System.Diagnostics.Tracing/EventFieldFormat.cs -System.Diagnostics.Tracing/EventFieldTags.cs -System.Diagnostics.Tracing/EventIgnoreAttribute.cs -System.Diagnostics.Tracing/EventManifestOptions.cs System.Diagnostics.SymbolStore/ISymbolBinder.cs System.Diagnostics.SymbolStore/ISymbolBinder1.cs System.Diagnostics.SymbolStore/ISymbolDocument.cs @@ -1099,12 +1083,49 @@ ReferenceSources/AppContextDefaultValues.cs ../referencesource/mscorlib/system/diagnostics/contracts/contracts.cs ../referencesource/mscorlib/system/diagnostics/contracts/contractsbcl.cs +../referencesource/mscorlib/system/diagnostics/eventing/activitytracker.cs ../referencesource/mscorlib/system/diagnostics/eventing/eventactivityoptions.cs +../referencesource/mscorlib/system/diagnostics/eventing/eventdescriptor.cs +../referencesource/mscorlib/system/diagnostics/eventing/eventprovider.cs +../referencesource/mscorlib/system/diagnostics/eventing/eventsource.cs ../referencesource/mscorlib/system/diagnostics/eventing/eventsourceexception.cs +../referencesource/mscorlib/system/diagnostics/eventing/StubEnvironment.cs ../referencesource/mscorlib/system/diagnostics/eventing/winmeta.cs +../../../external/corefx-bugfix/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventCounter.cs +../../../external/corefx-bugfix/src/Common/src/CoreLib/System/Diagnostics/Tracing/unsafenativemethods.cs + +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/ArrayTypeInfo.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/ConcurrentSet.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/ConcurrentSetItem.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/DataCollector.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/EmptyStruct.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/EnumerableTypeInfo.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/EnumHelper.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/EventDataAttribute.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/EventFieldAttribute.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/EventFieldFormat.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/EventIgnoreAttribute.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/EventPayload.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/EventSourceActivity.cs ../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/EventSourceOptions.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/FieldMetadata.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/InvokeTypeInfo.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/NameInfo.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/PropertyAccessor.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/PropertyAnalysis.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/SimpleEventTypes.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/SimpleTypeInfos.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/Statics.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingDataCollector.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingDataType.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingEventSource.cs ../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingEventTraits.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingEventTypes.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingMetadataCollector.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingTypeInfo.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingTypeInfo_T.cs +../referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TypeAnalysis.cs ../referencesource/mscorlib/system/globalization/bidicategory.cs ../referencesource/mscorlib/system/globalization/calendar.cs diff --git a/mcs/class/referencesource/mscorlib/system/AppContext/AppContextSwitches.cs b/mcs/class/referencesource/mscorlib/system/AppContext/AppContextSwitches.cs index 432d81001aa2..79c6bf86ae00 100644 --- a/mcs/class/referencesource/mscorlib/system/AppContext/AppContextSwitches.cs +++ b/mcs/class/referencesource/mscorlib/system/AppContext/AppContextSwitches.cs @@ -15,6 +15,7 @@ internal static class AppContextSwitches public static readonly bool ThrowExceptionIfDisposedCancellationTokenSource = false; public static readonly bool SetActorAsReferenceWhenCopyingClaimsIdentity = false; public static readonly bool NoAsyncCurrentCulture = false; + public static readonly bool PreserveEventListnerObjectIdentity = false; #else private static int _noAsyncCurrentCulture; public static bool NoAsyncCurrentCulture diff --git a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/activitytracker.cs b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/activitytracker.cs index 22be307d6eea..a77b897e37da 100644 --- a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/activitytracker.cs +++ b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/activitytracker.cs @@ -61,7 +61,7 @@ public void OnStart(string providerName, string activityName, int task, ref Guid if (m_checkedForEnable) return; m_checkedForEnable = true; -#if ES_BUILD_STANDALONE +#if ES_BUILD_STANDALONE || MONO Enable(); // Enable it unconditionally. #else if (System.Threading.Tasks.TplEtwProvider.Log.IsEnabled(EventLevel.Informational, System.Threading.Tasks.TplEtwProvider.Keywords.TasksFlowActivityIds)) @@ -609,7 +609,7 @@ void ActivityChanging(AsyncLocalValueChangedArgs args) #endregion } -#if ES_BUILD_STANDALONE +#if ES_BUILD_STANDALONE || MONO /******************************** SUPPORT *****************************/ /// /// This is supplied by the framework. It is has the semantics that the value is copied to any new Tasks that is created diff --git a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventprovider.cs b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventprovider.cs index 939d15ee520f..54249f1ce6cc 100644 --- a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventprovider.cs +++ b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventprovider.cs @@ -78,6 +78,7 @@ internal SessionInfo(int sessionIdBit_, int etwSessionId_) [SecurityCritical] UnsafeNativeMethods.ManifestEtw.EtwEnableCallback m_etwCallback; // Trace Callback function + GCHandle m_thisGCHandle; private long m_regHandle; // Trace Registration Handle private byte m_level; // Tracing Level private long m_anyKeywordMask; // Trace Enable Flags @@ -149,13 +150,25 @@ internal EventProvider() internal unsafe void Register(Guid providerGuid) { m_providerId = providerGuid; - uint status; m_etwCallback = new UnsafeNativeMethods.ManifestEtw.EtwEnableCallback(EtwEnableCallBack); - status = EventRegister(ref m_providerId, m_etwCallback); - if (status != 0) + if (m_thisGCHandle.IsAllocated) + m_thisGCHandle.Free(); + + m_thisGCHandle = GCHandle.Alloc(this); + + try + { + var status = UnsafeNativeMethods.ManifestEtw.EventRegister(ref providerGuid, m_etwCallback, GCHandle.ToIntPtr(m_thisGCHandle).ToPointer(), ref m_regHandle); + if (status != 0) + { + throw new ArgumentException(Win32Native.GetMessage(unchecked((int)status))); + } + } + catch { - throw new ArgumentException(Win32Native.GetMessage(unchecked((int)status))); + m_thisGCHandle.Free(); + throw; } } @@ -264,22 +277,44 @@ private unsafe void Deregister() { EventUnregister(); m_regHandle = 0; + m_thisGCHandle.Free(); } } + [AttributeUsage(AttributeTargets.Method)] + private sealed class MonoPInvokeCallbackAttribute : Attribute + { + public MonoPInvokeCallbackAttribute(Type t) + { + } + } + + [MonoPInvokeCallback(typeof(UnsafeNativeMethods.ManifestEtw.EtwEnableCallback))] + unsafe static 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 + ) + { + var _this = (EventProvider)GCHandle.FromIntPtr(new IntPtr(callbackContext)).Target; + _this.EtwEnableCallBackImpl(controlCode, setLevel, anyKeyword, allKeyword, filterData); + } + // // // // [System.Security.SecurityCritical] - unsafe void EtwEnableCallBack( - [In] ref System.Guid sourceId, + unsafe void EtwEnableCallBackImpl( [In] int controlCode, [In] byte setLevel, [In] long anyKeyword, [In] long allKeyword, - [In] UnsafeNativeMethods.ManifestEtw.EVENT_FILTER_DESCRIPTOR* filterData, - [In] void* callbackContext + [In] UnsafeNativeMethods.ManifestEtw.EVENT_FILTER_DESCRIPTOR* filterData ) { // This is an optional callback API. We will therefore ignore any failures that happen as a @@ -476,9 +511,17 @@ private unsafe void GetSessionInfo(Action action) fixed (Guid* provider = &m_providerId) { - hr = UnsafeNativeMethods.ManifestEtw.EnumerateTraceGuidsEx(UnsafeNativeMethods.ManifestEtw.TRACE_QUERY_INFO_CLASS.TraceGuidQueryInfo, - provider, sizeof(Guid), buffer, buffSize, ref buffSize); - } + try + { + hr = UnsafeNativeMethods.ManifestEtw.EnumerateTraceGuidsEx(UnsafeNativeMethods.ManifestEtw.TRACE_QUERY_INFO_CLASS.TraceGuidQueryInfo, + provider, sizeof(Guid), buffer, buffSize, ref buffSize); + } + catch (DllNotFoundException) + { + // This API isn't available on UWP prior to Windows SDK 16299 + return; + } + } if (hr == 0) break; if (hr != 122 /* ERROR_INSUFFICIENT_BUFFER */) @@ -539,7 +582,7 @@ private unsafe bool GetDataFromController(int etwSessionId, dataStart = 0; if (filterData == null) { -#if !ES_BUILD_PCL +#if !ES_BUILD_PCL && !MONO string regKey = @"\Microsoft\Windows\CurrentVersion\Winevt\Publishers\{" + m_providerId + "}"; if (System.Runtime.InteropServices.Marshal.SizeOf(typeof(IntPtr)) == 8) regKey = @"HKEY_LOCAL_MACHINE\Software" + @"\Wow6432Node" + regKey; @@ -1161,13 +1204,6 @@ internal unsafe bool WriteEventRaw( // 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). - [SecurityCritical] - private unsafe uint EventRegister(ref Guid providerId, UnsafeNativeMethods.ManifestEtw.EtwEnableCallback enableCallback) - { - m_providerId = providerId; - m_etwCallback = enableCallback; - return UnsafeNativeMethods.ManifestEtw.EventRegister(ref providerId, enableCallback, null, ref m_regHandle); - } [SecurityCritical] private uint EventUnregister() diff --git a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventsource.cs b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventsource.cs index 6bc1f76856fb..b8923813894a 100644 --- a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventsource.cs +++ b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventsource.cs @@ -200,6 +200,12 @@ using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract; #endif +#if MONO +using TplEtwProvider = System.Diagnostics.Tracing.TplEtwProvider; +#else +using TplEtwProvider = System.Threading.Tasks.TplEtwProvider; +#endif + #if ES_BUILD_STANDALONE namespace Microsoft.Diagnostics.Tracing #else @@ -551,8 +557,8 @@ public static void SetCurrentThreadActivityId(Guid activityId) } #endif // FEATURE_ACTIVITYSAMPLING } - if (System.Threading.Tasks.TplEtwProvider.Log != null) - System.Threading.Tasks.TplEtwProvider.Log.SetActivityId(activityId); + if (TplEtwProvider.Log != null) + TplEtwProvider.Log.SetActivityId(activityId); } /// @@ -586,8 +592,8 @@ public static void SetCurrentThreadActivityId(Guid activityId, out Guid oldActiv // We don't call the activityDying callback here because the caller has declared that // it is not dying. - if (System.Threading.Tasks.TplEtwProvider.Log != null) - System.Threading.Tasks.TplEtwProvider.Log.SetActivityId(activityId); + if (TplEtwProvider.Log != null) + TplEtwProvider.Log.SetActivityId(activityId); } /// @@ -4904,7 +4910,7 @@ internal set } -#if FEATURE_MANAGED_ETW_CHANNELS +#if FEATURE_MANAGED_ETW_CHANNELS || MONO /// /// Gets the channel for the event. /// @@ -5044,7 +5050,7 @@ internal bool IsOpcodeSet /// Event's task: allows logical grouping of events public EventTask Task { get; set; } -#if FEATURE_MANAGED_ETW_CHANNELS +#if FEATURE_MANAGED_ETW_CHANNELS || MONO /// Event's channel: defines an event log as an additional destination for the event public EventChannel Channel { get; set; } #endif @@ -6494,7 +6500,11 @@ private string CreateManifestString() // very early in the app domain creation, when _FusionStore is not set up yet, resulting in a failure to run the static constructory // for BinaryCompatibility. This failure is then cached and a TypeInitializationException is thrown every time some code attampts to // access BinaryCompatibility. +#if MONO + ArraySortHelper.IntrospectiveSort(sortedStrings, 0, sortedStrings.Length, Comparer.Default.Compare); +#else ArraySortHelper.IntrospectiveSort(sortedStrings, 0, sortedStrings.Length, Comparer.Default); +#endif #endif foreach (var ci in cultures) {