Fix EventSource Test Failures in CoreFX (#16999)
authorBrian Robbins <brianrob@microsoft.com>
Sat, 17 Mar 2018 22:18:25 +0000 (15:18 -0700)
committerGitHub <noreply@github.com>
Sat, 17 Mar 2018 22:18:25 +0000 (15:18 -0700)
src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs
src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs
src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs
src/mscorlib/src/System/Diagnostics/Eventing/EventPipeMetadataGenerator.cs
src/vm/eventpipe.cpp

index 751b0fd..21e03e0 100644 (file)
@@ -623,6 +623,7 @@ namespace System.Diagnostics.Tracing
                     continue;
 
                 byte[] metadata = EventPipeMetadataGenerator.Instance.GenerateEventMetadata(m_eventData[i]);
+                uint metadataLength = (metadata != null) ? (uint)metadata.Length : 0;
 
                 string eventName = m_eventData[i].Name;
                 Int64 keywords = m_eventData[i].Descriptor.Keywords;
@@ -638,7 +639,7 @@ namespace System.Diagnostics.Tracing
                         eventVersion,
                         level,
                         pMetadata,
-                        (uint)metadata.Length);
+                        metadataLength);
 
                     Debug.Assert(eventHandle != IntPtr.Zero);
                     m_eventData[i].EventHandle = eventHandle;
index cf8379f..b1c7327 100644 (file)
@@ -4,6 +4,7 @@
 
 using System;
 using System.Collections.Generic;
+using System.Collections.Concurrent;
 using Interlocked = System.Threading.Interlocked;
 
 #if ES_BUILD_STANDALONE
@@ -42,7 +43,6 @@ namespace System.Diagnostics.Tracing
         internal readonly byte[] nameMetadata;
 
 #if FEATURE_PERFTRACING
-        private IntPtr eventHandle = IntPtr.Zero;
         private readonly object eventHandleCreationLock = new object();
 #endif
 
@@ -82,13 +82,14 @@ namespace System.Diagnostics.Tracing
         }
 
 #if FEATURE_PERFTRACING
-        public IntPtr GetOrCreateEventHandle(EventProvider provider, EventDescriptor descriptor, TraceLoggingEventTypes eventTypes)
+        public IntPtr GetOrCreateEventHandle(EventProvider provider, ConcurrentDictionary<int, IntPtr> eventHandleMap, EventDescriptor descriptor, TraceLoggingEventTypes eventTypes)
         {
-            if (eventHandle == IntPtr.Zero)
+            IntPtr eventHandle = IntPtr.Zero;
+            if(!eventHandleMap.TryGetValue(descriptor.EventId, out eventHandle))
             {
                 lock (eventHandleCreationLock)
                 {
-                    if (eventHandle == IntPtr.Zero)
+                    if (!eventHandleMap.TryGetValue(descriptor.EventId, out eventHandle))
                     {
                         byte[] metadataBlob = EventPipeMetadataGenerator.Instance.GenerateEventMetadata(
                             descriptor.EventId,
@@ -97,6 +98,7 @@ namespace System.Diagnostics.Tracing
                             (EventLevel)descriptor.Level,
                             descriptor.Version,
                             eventTypes);
+                        uint metadataLength = (metadataBlob != null) ? (uint)metadataBlob.Length : 0;
 
                         unsafe
                         {
@@ -110,7 +112,7 @@ namespace System.Diagnostics.Tracing
                                     descriptor.Version,
                                     descriptor.Level,
                                     pMetadataBlob,
-                                    (uint)metadataBlob.Length);
+                                    metadataLength);
                             }
                         }
                     }
index 4ebe3a3..ccdc8bf 100644 (file)
@@ -24,6 +24,7 @@ using System.Resources;
 using System.Runtime.InteropServices;
 using System.Security;
 using System.Collections.ObjectModel;
+using System.Collections.Concurrent;
 
 #if !ES_BUILD_AGAINST_DOTNET_V35
 using Contract = System.Diagnostics.Contracts.Contract;
@@ -47,6 +48,10 @@ namespace System.Diagnostics.Tracing
         private byte[] providerMetadata;
 #endif
 
+#if FEATURE_PERFTRACING
+        private ConcurrentDictionary<int, IntPtr> m_eventHandleMap = new ConcurrentDictionary<int, IntPtr>();
+#endif
+
         /// <summary>
         /// Construct an EventSource with a given name for non-contract based events (e.g. those using the Write() API).
         /// </summary>
@@ -432,7 +437,7 @@ namespace System.Diagnostics.Tracing
             EventDescriptor descriptor = new EventDescriptor(identity, level, opcode, (long)keywords);
 
 #if FEATURE_PERFTRACING
-            IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_provider, descriptor, eventTypes);
+            IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_provider, m_eventHandleMap, descriptor, eventTypes);
             Debug.Assert(eventHandle != IntPtr.Zero);
 #else
             IntPtr eventHandle = IntPtr.Zero;
@@ -547,7 +552,7 @@ namespace System.Diagnostics.Tracing
                 }
 
 #if FEATURE_PERFTRACING
-                    IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_provider, descriptor, eventTypes);
+                    IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_provider, m_eventHandleMap, descriptor, eventTypes);
                     Debug.Assert(eventHandle != IntPtr.Zero);
 #else
                     IntPtr eventHandle = IntPtr.Zero;
@@ -616,7 +621,7 @@ namespace System.Diagnostics.Tracing
                     }
 
 #if FEATURE_PERFTRACING
-                    IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_provider, descriptor, eventTypes);
+                    IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_provider, m_eventHandleMap, descriptor, eventTypes);
                     Debug.Assert(eventHandle != IntPtr.Zero);
 #else
                     IntPtr eventHandle = IntPtr.Zero;
index a2b6095..d18610d 100644 (file)
@@ -65,48 +65,59 @@ namespace System.Diagnostics.Tracing
             uint version,
             EventParameterInfo[] parameters)
         {
-            // eventID          : 4 bytes
-            // eventName        : (eventName.Length + 1) * 2 bytes
-            // keywords         : 8 bytes
-            // eventVersion     : 4 bytes
-            // level            : 4 bytes
-            // parameterCount   : 4 bytes
-            uint metadataLength = 24 + ((uint)eventName.Length + 1) * 2;
-
-            // Check for an empty payload.
-            // Write<T> calls with no arguments by convention have a parameter of
-            // type NullTypeInfo which is serialized as nothing.
-            if((parameters.Length == 1) && (parameters[0].ParameterType == typeof(EmptyStruct)))
+            byte[] metadata = null;
+            try
             {
-                parameters = Array.Empty<EventParameterInfo>();
-            }
-
-            // Increase the metadataLength for parameters.
-            foreach (var parameter in parameters)
-            {
-                metadataLength = metadataLength + parameter.GetMetadataLength();
-            }
-
-            byte[] metadata = new byte[metadataLength];
-
-            // Write metadata: eventID, eventName, keywords, eventVersion, level, parameterCount, param1 type, param1 name...
-            fixed (byte *pMetadata = metadata)
-            {
-                uint offset = 0;
-                WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)eventId);
-                fixed(char *pEventName = eventName)
+                // eventID          : 4 bytes
+                // eventName        : (eventName.Length + 1) * 2 bytes
+                // keywords         : 8 bytes
+                // eventVersion     : 4 bytes
+                // level            : 4 bytes
+                // parameterCount   : 4 bytes
+                uint metadataLength = 24 + ((uint)eventName.Length + 1) * 2;
+
+                // Check for an empty payload.
+                // Write<T> calls with no arguments by convention have a parameter of
+                // type NullTypeInfo which is serialized as nothing.
+                if ((parameters.Length == 1) && (parameters[0].ParameterType == typeof(EmptyStruct)))
                 {
-                    WriteToBuffer(pMetadata, metadataLength, ref offset, (byte *)pEventName, ((uint)eventName.Length + 1) * 2);
+                    parameters = Array.Empty<EventParameterInfo>();
                 }
-                WriteToBuffer(pMetadata, metadataLength, ref offset, keywords);
-                WriteToBuffer(pMetadata, metadataLength, ref offset, version);
-                WriteToBuffer(pMetadata, metadataLength, ref offset, level);
-                WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)parameters.Length);
+
+                // Increase the metadataLength for parameters.
                 foreach (var parameter in parameters)
                 {
-                    parameter.GenerateMetadata(pMetadata, ref offset, metadataLength);
+                    metadataLength = metadataLength + parameter.GetMetadataLength();
+                }
+
+                metadata = new byte[metadataLength];
+
+                // Write metadata: eventID, eventName, keywords, eventVersion, level, parameterCount, param1 type, param1 name...
+                fixed (byte* pMetadata = metadata)
+                {
+                    uint offset = 0;
+                    WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)eventId);
+                    fixed (char* pEventName = eventName)
+                    {
+                        WriteToBuffer(pMetadata, metadataLength, ref offset, (byte*)pEventName, ((uint)eventName.Length + 1) * 2);
+                    }
+                    WriteToBuffer(pMetadata, metadataLength, ref offset, keywords);
+                    WriteToBuffer(pMetadata, metadataLength, ref offset, version);
+                    WriteToBuffer(pMetadata, metadataLength, ref offset, level);
+                    WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)parameters.Length);
+                    foreach (var parameter in parameters)
+                    {
+                        parameter.GenerateMetadata(pMetadata, ref offset, metadataLength);
+                    }
+                    Debug.Assert(metadataLength == offset);
                 }
-                Debug.Assert(metadataLength == offset);
+            }
+            catch
+            {
+                // If a failure occurs during metadata generation, make sure that we don't return
+                // malformed metadata.  Instead, return a null metadata blob.
+                // Consumers can either build in knowledge of the event or skip it entirely.
+                metadata = null;
             }
 
             return metadata;
@@ -262,7 +273,12 @@ namespace System.Diagnostics.Tracing
                 //     TypeCode : 4 bytes
                 //     PropertyName : NULL-terminated string
                 TypeCode typeCode = GetTypeCodeExtended(property.typeInfo.DataType);
-                Debug.Assert(typeCode != TypeCode.Object);
+
+                // EventPipe does not support this type.  Throw, which will cause no metadata to be registered for this event.
+                if(typeCode == TypeCode.Object)
+                {
+                    throw new NotSupportedException();
+                }
 
                 // Write the type code.
                 EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)typeCode);
index ab13738..910dee5 100644 (file)
@@ -958,7 +958,6 @@ INT_PTR QCALLTYPE EventPipeInternal::DefineEvent(
     BEGIN_QCALL;
 
     _ASSERTE(provHandle != NULL);
-    _ASSERTE(pMetadata != NULL);
     EventPipeProvider *pProvider = reinterpret_cast<EventPipeProvider *>(provHandle);
     pEvent = pProvider->AddEvent(eventID, keywords, eventVersion, (EventPipeEventLevel)level, (BYTE *)pMetadata, metadataLength);
     _ASSERTE(pEvent != NULL);