Merge pull request dotnet/corertdotnet/coreclr#3226 from dotnet/nmirror
authorSimon Nattress <nattress@gmail.com>
Fri, 7 Apr 2017 01:02:03 +0000 (18:02 -0700)
committerJan Kotas <jkotas@microsoft.com>
Fri, 7 Apr 2017 13:15:57 +0000 (06:15 -0700)
Merge nmirror to master

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
Commit migrated from https://github.com/dotnet/coreclr/commit/157a0aee00e8623811c3b9b1ff962a2e2ae8bb67

42 files changed:
src/coreclr/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/ActivityTracker.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventActivityOptions.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventCounter.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventDescriptor.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventSourceException.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/FrameworkEventSource.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/StubEnvironment.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/ArrayTypeInfo.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSet.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSetItem.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EmptyStruct.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EnumHelper.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EnumerableTypeInfo.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventDataAttribute.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventFieldAttribute.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventFieldFormat.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventIgnoreAttribute.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceOptions.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyAnalysis.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleEventTypes.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataCollector.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataType.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTraits.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TypeAnalysis.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/Winmeta.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/shared/System/IO/FileLoadException.cs [new file with mode: 0644]

index 7c6d039..c152fea 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)System\InvalidProgramException.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\InvalidTimeZoneException.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\Error.cs"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\IO\FileLoadException.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\Path.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\PathInternal.cs"/>
   <ItemGroup Condition="$(TargetsUnix) and !$(TargetsOSX)">
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Linux.cs"/>
   </ItemGroup>
+  <ItemGroup>
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\ActivityTracker.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventActivityOptions.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventCounter.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventDescriptor.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventProvider.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventSource.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventSourceException.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\StubEnvironment.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\PropertyValue.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\Winmeta.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\ArrayTypeInfo.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\ConcurrentSet.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\ConcurrentSetItem.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\DataCollector.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\EmptyStruct.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\EnumerableTypeInfo.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\EnumHelper.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\EventDataAttribute.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\EventFieldAttribute.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\EventFieldFormat.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\EventIgnoreAttribute.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\EventPayload.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\EventSourceActivity.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\EventSourceOptions.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\FieldMetadata.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\InvokeTypeInfo.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\NameInfo.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\PropertyAnalysis.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\SimpleEventTypes.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\SimpleTypeInfos.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\Statics.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingDataCollector.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingDataType.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingEventSource.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingEventTraits.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingEventTypes.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingMetadataCollector.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingTypeInfo.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TypeAnalysis.cs" />
+  </ItemGroup>
 </Project>
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/ActivityTracker.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/ActivityTracker.cs
new file mode 100644 (file)
index 0000000..e32abd2
--- /dev/null
@@ -0,0 +1,665 @@
+// 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.Diagnostics;
+using System.Threading;
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+using System.Threading.Tasks;
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// Tracks activities.  This is meant to be a singleton (accessed by the ActivityTracer.Instance static property)
+    ///  
+    /// Logically this is simply holds the m_current variable that holds the async local that holds the current ActivityInfo
+    /// An ActivityInfo is represents a activity (which knows its creator and thus knows its path). 
+    ///
+    /// Most of the magic is in the async local (it gets copied to new tasks)
+    /// 
+    /// On every start event call OnStart 
+    /// 
+    ///     Guid activityID;
+    ///     Guid relatedActivityID;
+    ///     if (OnStart(activityName, out activityID, out relatedActivityID, ForceStop, options))
+    ///         // Log Start event with activityID and relatedActivityID
+    ///     
+    /// On every stop event call OnStop
+    /// 
+    ///     Guid activityID;
+    ///     if (OnStop(activityName, ref activityID  ForceStop))
+    ///         // Stop event with activityID
+    ///            
+    /// On any normal event log the event with activityTracker.CurrentActivityId
+    /// </summary>
+    internal class ActivityTracker
+    {
+
+        /// <summary>
+        /// Called on work item begins.  The activity name = providerName + activityName without 'Start' suffix.
+        /// It updates CurrentActivityId to track.   
+        /// 
+        /// It returns true if the Start should be logged, otherwise (if it is illegal recursion) it return false. 
+        /// 
+        /// The start event should use as its activity ID the CurrentActivityId AFTER calling this routine and its
+        /// RelatedActivityID the CurrentActivityId BEFORE calling this routine (the creator).  
+        /// 
+        /// If activity tracing is not on, then activityId and relatedActivityId are not set
+        /// </summary>
+        public void OnStart(string providerName, string activityName, int task, ref Guid activityId, ref Guid relatedActivityId, EventActivityOptions options)
+        {
+            if (m_current == null)        // We are not enabled
+            {
+                // We  used to rely on the TPL provider turning us on, but that has the disadvantage that you don't get Start-Stop tracking
+                // until you use Tasks for the first time (which you may never do).   Thus we change it to pull rather tan push for whether
+                // we are enabled.   
+                if (m_checkedForEnable)
+                    return;
+                m_checkedForEnable = true;
+                if (TplEtwProvider.Log.IsEnabled(EventLevel.Informational, TplEtwProvider.Keywords.TasksFlowActivityIds))
+                    Enable();
+                if (m_current == null)
+                    return;
+            }
+
+
+            Debug.Assert((options & EventActivityOptions.Disable) == 0);
+
+            var currentActivity = m_current.Value;
+            var fullActivityName = NormalizeActivityName(providerName, activityName, task);
+
+            var etwLog = TplEtwProvider.Log;
+            if (etwLog.Debug)
+            {
+                etwLog.DebugFacilityMessage("OnStartEnter", fullActivityName);
+                etwLog.DebugFacilityMessage("OnStartEnterActivityState", ActivityInfo.LiveActivities(currentActivity));
+            }
+
+            if (currentActivity != null)
+            {
+                // Stop activity tracking if we reached the maximum allowed depth 
+                if (currentActivity.m_level >= MAX_ACTIVITY_DEPTH)
+                {
+                    activityId = Guid.Empty;
+                    relatedActivityId = Guid.Empty;
+                    if (etwLog.Debug)
+                        etwLog.DebugFacilityMessage("OnStartRET", "Fail");
+                    return;
+                }
+                // Check for recursion, and force-stop any activities if the activity already started.
+                if ((options & EventActivityOptions.Recursive) == 0)
+                {
+                    ActivityInfo existingActivity = FindActiveActivity(fullActivityName, currentActivity);
+                    if (existingActivity != null)
+                    {
+                        OnStop(providerName, activityName, task, ref activityId);
+                        currentActivity = m_current.Value;
+                    }
+                }
+            }
+
+            // Get a unique ID for this activity.
+            long id;
+            if (currentActivity == null)
+                id = Interlocked.Increment(ref m_nextId);
+            else
+                id = Interlocked.Increment(ref currentActivity.m_lastChildID);
+
+            // The previous ID is my 'causer' and becomes my related activity ID
+            relatedActivityId = EventSource.CurrentThreadActivityId;
+
+            // Add to the list of started but not stopped activities. 
+            ActivityInfo newActivity = new ActivityInfo(fullActivityName, id, currentActivity, relatedActivityId, options);
+            m_current.Value = newActivity;
+
+            // Remember the current ID so we can log it 
+            activityId = newActivity.ActivityId;
+            
+            if (etwLog.Debug)
+            {
+                etwLog.DebugFacilityMessage("OnStartRetActivityState", ActivityInfo.LiveActivities(newActivity));
+                etwLog.DebugFacilityMessage1("OnStartRet", activityId.ToString(), relatedActivityId.ToString());
+            }
+        }
+
+        /// <summary>
+        /// Called when a work item stops.  The activity name = providerName + activityName without 'Stop' suffix.
+        /// It updates m_current variable to track this fact.   The Stop event associated with stop should log the ActivityID associated with the event.
+        ///
+        /// If activity tracing is not on, then activityId and relatedActivityId are not set
+        /// </summary>
+        public void OnStop(string providerName, string activityName, int task, ref Guid activityId)
+        {
+            if (m_current == null)        // We are not enabled
+                return;
+
+            var fullActivityName = NormalizeActivityName(providerName, activityName, task);
+            
+            var etwLog = TplEtwProvider.Log;
+            if (etwLog.Debug)
+            {
+                etwLog.DebugFacilityMessage("OnStopEnter", fullActivityName);
+                etwLog.DebugFacilityMessage("OnStopEnterActivityState", ActivityInfo.LiveActivities(m_current.Value));
+            }
+
+            for (; ; ) // This is a retry loop.
+            {
+                ActivityInfo currentActivity = m_current.Value;
+                ActivityInfo newCurrentActivity = null;               // if we have seen any live activities (orphans), at he first one we have seen.   
+
+                // Search to find the activity to stop in one pass.   This insures that we don't let one mistake
+                // (stopping something that was not started) cause all active starts to be stopped 
+                // By first finding the target start to stop we are more robust.  
+                ActivityInfo activityToStop = FindActiveActivity(fullActivityName, currentActivity);
+
+                // ignore stops where we can't find a start because we may have popped them previously.
+                if (activityToStop == null)
+                {
+                    activityId = Guid.Empty;
+                    // TODO add some logging about this. Basically could not find matching start.
+                    if (etwLog.Debug)
+                        etwLog.DebugFacilityMessage("OnStopRET", "Fail");
+                    return;
+                }
+
+                activityId = activityToStop.ActivityId;
+
+                // See if there are any orphans that need to be stopped.  
+                ActivityInfo orphan = currentActivity;
+                while (orphan != activityToStop && orphan != null)
+                {
+                    if (orphan.m_stopped != 0)      // Skip dead activities.
+                    {
+                        orphan = orphan.m_creator;
+                        continue;
+                    }
+                    if (orphan.CanBeOrphan())
+                    {
+                        // We can't pop anything after we see a valid orphan, remember this for later when we update m_current.  
+                        if (newCurrentActivity == null)
+                            newCurrentActivity = orphan;
+                    }
+                    else
+                    {
+                        orphan.m_stopped = 1;
+                        Debug.Assert(orphan.m_stopped != 0);
+                    }
+                    orphan = orphan.m_creator;
+                }
+
+                // try to Stop the activity atomically.  Other threads may be trying to do this as well.
+                if (Interlocked.CompareExchange(ref activityToStop.m_stopped, 1, 0) == 0)
+                {
+                    // I succeeded stopping this activity. Now we update our m_current pointer 
+
+                    // If I haven't yet determined the new current activity, it is my creator.
+                    if (newCurrentActivity == null)
+                        newCurrentActivity = activityToStop.m_creator;
+
+                    m_current.Value = newCurrentActivity;
+
+                    if (etwLog.Debug)
+                    {
+                        etwLog.DebugFacilityMessage("OnStopRetActivityState", ActivityInfo.LiveActivities(newCurrentActivity));
+                        etwLog.DebugFacilityMessage("OnStopRet", activityId.ToString());
+                    }
+                    return;
+                }
+                // We failed to stop it.  We must have hit a race to stop it.  Just start over and try again.  
+            }
+        }
+
+        /// <summary>
+        /// Turns on activity tracking.    It is sticky, once on it stays on (race issues otherwise)
+        /// </summary>
+        public void Enable()
+        {
+            if (m_current == null)
+            {
+                // Catch the not Implemented 
+                try
+                {
+                    m_current = new AsyncLocal<ActivityInfo>(ActivityChanging);
+                }
+                catch (NotImplementedException) {
+#if (!ES_BUILD_PCL && ! ES_BUILD_PN)
+                    // send message to debugger without delay
+                    System.Diagnostics.Debugger.Log(0, null, "Activity Enabled() called but AsyncLocals Not Supported (pre V4.6).  Ignoring Enable");
+#endif
+                } 
+            }
+        }
+
+        /// <summary>
+        /// An activity tracker is a singleton, this is how you get the one and only instance.
+        /// </summary>
+        public static ActivityTracker Instance { get { return s_activityTrackerInstance; } }
+
+
+        #region private
+
+        /// <summary>
+        /// The current activity ID.  Use this to log normal events.  
+        /// </summary>
+        private Guid CurrentActivityId { get { return m_current.Value.ActivityId; } }
+
+        /// <summary>
+        /// Searched for a active (nonstopped) activity with the given name.  Returns null if not found.  
+        /// </summary>
+        private ActivityInfo FindActiveActivity(string name, ActivityInfo startLocation)
+        {
+            var activity = startLocation;
+            while (activity != null)
+            {
+                if (name == activity.m_name && activity.m_stopped == 0)
+                    return activity;
+                activity = activity.m_creator;
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Strip out "Start" or "End" suffix from activity name and add providerName prefix.
+        /// If 'task'  it does not end in Start or Stop and Task is non-zero use that as the name of the activity
+        /// </summary>
+        private string NormalizeActivityName(string providerName, string activityName, int task)
+        {
+            if (activityName.EndsWith(EventSource.s_ActivityStartSuffix, StringComparison.Ordinal))
+                activityName = activityName.Substring(0, activityName.Length - EventSource.s_ActivityStartSuffix.Length);
+            else if (activityName.EndsWith(EventSource.s_ActivityStopSuffix, StringComparison.Ordinal))
+                activityName = activityName.Substring(0, activityName.Length - EventSource.s_ActivityStopSuffix.Length);
+            else if (task != 0)
+                activityName = "task" + task.ToString();
+
+            // We use provider name to distinguish between activities from different providers.
+            return providerName + activityName;
+        }
+
+        // *******************************************************************************
+        /// <summary>
+        /// An ActivityInfo represents a particular activity.   It is almost read-only.   The only
+        /// fields that change after creation are
+        ///    m_lastChildID - used to generate unique IDs for the children activities and for the most part can be ignored.
+        ///    m_stopped - indicates that this activity is dead 
+        /// This read-only-ness is important because an activity's  m_creator chain forms the 
+        /// 'Path of creation' for the activity (which is also its unique ID) but is also used as
+        /// the 'list of live parents' which indicate of those ancestors, which are alive (if they
+        /// are not marked dead they are alive).   
+        /// </summary>
+        private class ActivityInfo
+        {
+            public ActivityInfo(string name, long uniqueId, ActivityInfo creator, Guid activityIDToRestore, EventActivityOptions options)
+            {
+                m_name = name;
+                m_eventOptions = options;
+                m_creator = creator;
+                m_uniqueId = uniqueId;
+                m_level = creator != null ? creator.m_level + 1 : 0;
+                m_activityIdToRestore = activityIDToRestore;
+
+                // Create a nice GUID that encodes the chain of activities that started this one.
+                CreateActivityPathGuid(out m_guid, out m_activityPathGuidOffset);
+            }
+
+            public Guid ActivityId
+            {
+                get
+                {
+                    return m_guid;
+                }
+            }
+
+            public static string Path(ActivityInfo activityInfo)
+            {
+                if (activityInfo == null)
+                    return ("");
+                return Path(activityInfo.m_creator) + "/" + activityInfo.m_uniqueId.ToString();
+            }
+
+            public override string ToString()
+            {
+                return m_name + "(" + Path(this) + (m_stopped != 0 ? ",DEAD)" : ")");
+            }
+
+            public static string LiveActivities(ActivityInfo list)
+            {
+                if (list == null)
+                    return "";
+                return list.ToString() + ";" + LiveActivities(list.m_creator);
+            }
+
+            public bool CanBeOrphan()
+            {
+                if ((m_eventOptions & EventActivityOptions.Detachable) != 0)
+                    return true;
+                return false;
+            }
+
+            #region private
+
+            #region CreateActivityPathGuid
+            /// <summary>
+            /// Logically every activity Path (see Path()) that describes the activities that caused this 
+            /// (rooted in an activity that predates activity tracking.  
+            ///
+            /// We wish to encode this path in the Guid to the extent that we can.  Many of the paths have
+            /// many small numbers in them and we take advantage of this in the encoding to output as long
+            /// a path in the GUID as possible.   
+            /// 
+            /// Because of the possibility of GUID collision, we only use 96 of the 128 bits of the GUID
+            /// for encoding the path.  The last 32 bits are a simple checksum (and random number) that 
+            /// identifies this as using the convention defined here.   
+            ///
+            /// It returns both the GUID which has the path as well as the offset that points just beyond
+            /// the end of the activity (so it can be appended to).  Note that if the end is in a nibble
+            /// (it uses nibbles instead of bytes as the unit of encoding, then it will point at the unfinished
+            /// byte (since the top nibble can't be zero you can determine if this is true by seeing if 
+            /// this byte is nonZero.   This offset is needed to efficiently create the ID for child activities. 
+            /// </summary>
+            private unsafe void CreateActivityPathGuid(out Guid idRet, out int activityPathGuidOffset)
+            {
+                fixed (Guid* outPtr = &idRet)
+                {
+                    int activityPathGuidOffsetStart = 0;
+                    if (m_creator != null)
+                    {
+                        activityPathGuidOffsetStart = m_creator.m_activityPathGuidOffset;
+                        idRet = m_creator.m_guid;
+                    }
+                    else
+                    {
+                        // TODO FIXME - differentiate between AD inside PCL
+                        int appDomainID = 0;
+#if (!ES_BUILD_STANDALONE && !ES_BUILD_PN)
+                        appDomainID = System.Threading.Thread.GetDomainID();
+#endif
+                        // We start with the appdomain number to make this unique among appdomains.
+                        activityPathGuidOffsetStart = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint)appDomainID);
+                    }
+
+                    activityPathGuidOffset = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint)m_uniqueId);
+
+
+                    // If the path does not fit, Make a GUID by incrementing rather than as a path, keeping as much of the path as possible
+                    if (12 < activityPathGuidOffset)
+                        CreateOverflowGuid(outPtr);
+                }
+            }
+
+            /// <summary>
+            /// If we can't fit the activity Path into the GUID we come here.   What we do is simply
+            /// generate a 4 byte number (s_nextOverflowId).  Then look for an ancestor that has  
+            /// sufficient space for this ID.   By doing this, we preserve the fact that this activity
+            /// is a child (of unknown depth) from that ancestor.
+            /// </summary>
+            private unsafe void CreateOverflowGuid(Guid* outPtr)
+            {
+                // Search backwards for an ancestor that has sufficient space to put the ID.  
+                for (ActivityInfo ancestor = m_creator; ancestor != null; ancestor = ancestor.m_creator)
+                {
+                    if (ancestor.m_activityPathGuidOffset <= 10)  // we need at least 2 bytes.  
+                    {
+                        uint id = unchecked((uint)Interlocked.Increment(ref ancestor.m_lastChildID));        // Get a unique ID 
+                        // Try to put the ID into the GUID
+                        *outPtr = ancestor.m_guid;
+                        int endId = AddIdToGuid(outPtr, ancestor.m_activityPathGuidOffset, id, true);
+
+                        // Does it fit?
+                        if (endId <= 12)
+                            break;
+                    }
+                }
+            }
+
+            /// <summary>
+            /// The encoding for a list of numbers used to make Activity  GUIDs.   Basically
+            /// we operate on nibbles (which are nice because they show up as hex digits).  The
+            /// list is ended with a end nibble (0) and depending on the nibble value (Below)
+            /// the value is either encoded into nibble itself or it can spill over into the
+            /// bytes that follow.   
+            /// </summary>
+            enum NumberListCodes : byte
+            {
+                End = 0x0,             // ends the list.   No valid value has this prefix.   
+                LastImmediateValue = 0xA,
+
+                PrefixCode = 0xB,      // all the 'long' encodings go here.  If the next nibble is MultiByte1-4
+                                       // than this is a 'overflow' id.   Unlike the hierarchical IDs these are 
+                                       // allocated densely but don't tell you anything about nesting. we use 
+                                       // these when we run out of space in the GUID to store the path.
+
+                MultiByte1 = 0xC,   // 1 byte follows.  If this Nibble is in the high bits, it the high bits of the number are stored in the low nibble.   
+                // commented out because the code does not explicitly reference the names (but they are logically defined).  
+                // MultiByte2 = 0xD,   // 2 bytes follow (we don't bother with the nibble optimization)
+                // MultiByte3 = 0xE,   // 3 bytes follow (we don't bother with the nibble optimization)
+                // MultiByte4 = 0xF,   // 4 bytes follow (we don't bother with the nibble optimization)
+            }
+
+            /// Add the activity id 'id' to the output Guid 'outPtr' starting at the offset 'whereToAddId'
+            /// Thus if this number is 6 that is where 'id' will be added.    This will return 13 (12
+            /// is the maximum number of bytes that fit in a GUID) if the path did not fit.  
+            /// If 'overflow' is true, then the number is encoded as an 'overflow number (which has a
+            /// special (longer prefix) that indicates that this ID is allocated differently 
+            private static unsafe int AddIdToGuid(Guid* outPtr, int whereToAddId, uint id, bool overflow = false)
+            {
+                byte* ptr = (byte*)outPtr;
+                byte* endPtr = ptr + 12;
+                ptr += whereToAddId;
+                if (endPtr <= ptr)
+                    return 13;                // 12 means we might exactly fit, 13 means we definately did not fit
+
+                if (0 < id && id <= (uint)NumberListCodes.LastImmediateValue && !overflow)
+                    WriteNibble(ref ptr, endPtr, id);
+                else
+                {
+                    uint len = 4;
+                    if (id <= 0xFF)
+                        len = 1;
+                    else if (id <= 0xFFFF)
+                        len = 2;
+                    else if (id <= 0xFFFFFF)
+                        len = 3;
+
+                    if (overflow)
+                    {
+                        if (endPtr <= ptr + 2)        // I need at least 2 bytes
+                            return 13;
+
+                        // Write out the prefix code nibble and the length nibble 
+                        WriteNibble(ref ptr, endPtr, (uint)NumberListCodes.PrefixCode);
+                    }
+                    // The rest is the same for overflow and non-overflow case
+                    WriteNibble(ref ptr, endPtr, (uint)NumberListCodes.MultiByte1 + (len - 1));
+
+                    // Do we have an odd nibble?   If so flush it or use it for the 12 byte case.   
+                    if (ptr < endPtr && *ptr != 0)
+                    {
+                        // If the value < 4096 we can use the nibble we are otherwise just outputting as padding. 
+                        if (id < 4096)
+                        {
+                            // Indicate this is a 1 byte multicode with 4 high order bits in the lower nibble.  
+                            *ptr = (byte)(((uint)NumberListCodes.MultiByte1 << 4) + (id >> 8));
+                            id &= 0xFF;     // Now we only want the low order bits.  
+                        }
+                        ptr++;
+                    }
+
+                    // Write out the bytes.
+                    while (0 < len)
+                    {
+                        if (endPtr <= ptr)
+                        {
+                            ptr++;        // Indicate that we have overflowed
+                            break;
+                        }
+                        *ptr++ = (byte)id;
+                        id = (id >> 8);
+                        --len;
+                    }
+                }
+
+                // Compute the checksum 
+                uint* sumPtr = (uint*)outPtr;
+                // We set the last DWORD the sum of the first 3 DWORDS in the GUID.   This 
+                sumPtr[3] = sumPtr[0] + sumPtr[1] + sumPtr[2] + 0x599D99AD;                        // This last number is a random number (it identifies us as us)
+
+                return (int)(ptr - ((byte*)outPtr));
+            }
+
+            /// <summary>
+            /// Write a single Nible 'value' (must be 0-15) to the byte buffer represented by *ptr.  
+            /// Will not go past 'endPtr'.  Also it assumes that we never write 0 so we can detect
+            /// whether a nibble has already been written to ptr  because it will be nonzero.   
+            /// Thus if it is non-zero it adds to the current byte, otherwise it advances and writes
+            /// the new byte (in the high bits) of the next byte.  
+            /// </summary>
+            private static unsafe void WriteNibble(ref byte* ptr, byte* endPtr, uint value)
+            {
+                Debug.Assert(0 <= value && value < 16);
+                Debug.Assert(ptr < endPtr);
+
+                if (*ptr != 0)
+                    *ptr++ |= (byte)value;
+                else
+                    *ptr = (byte)(value << 4);
+            }
+
+            #endregion // CreateGuidForActivityPath
+
+            readonly internal string m_name;                        // The name used in the 'start' and 'stop' APIs to help match up
+            readonly long m_uniqueId;                               // a small number that makes this activity unique among its siblings
+            internal readonly Guid m_guid;                          // Activity Guid, it is basically an encoding of the Path() (see CreateActivityPathGuid)
+            internal readonly int m_activityPathGuidOffset;         // Keeps track of where in m_guid the causality path stops (used to generated child GUIDs)
+            internal readonly int m_level;                          // current depth of the Path() of the activity (used to keep recursion under control)
+            readonly internal EventActivityOptions m_eventOptions;  // Options passed to start. 
+            internal long m_lastChildID;                            // used to create a unique ID for my children activities
+            internal int m_stopped;                                 // This work item has stopped
+            readonly internal ActivityInfo m_creator;               // My parent (creator).  Forms the Path() for the activity.
+            readonly internal Guid m_activityIdToRestore;           // The Guid to restore after a stop.
+            #endregion
+        }
+
+        // This callback is used to initialize the m_current AsyncLocal Variable.   
+        // Its job is to keep the ETW Activity ID (part of thread local storage) in sync
+        // with m_current.ActivityID
+        void ActivityChanging(AsyncLocalValueChangedArgs<ActivityInfo> args)
+        {
+            ActivityInfo cur = args.CurrentValue;
+            ActivityInfo prev = args.PreviousValue;
+
+            // Are we popping off a value?   (we have a prev, and it creator is cur) 
+            // Then check if we should use the GUID at the time of the start event
+            if (prev != null && prev.m_creator == cur)
+            {
+                // If the saved activity ID is not the same as the creator activity
+                // that takes precedence (it means someone explicitly did a SetActivityID)
+                // Set it to that and get out
+                if (cur == null || prev.m_activityIdToRestore != cur.ActivityId)
+                {
+                    EventSource.SetCurrentThreadActivityId(prev.m_activityIdToRestore);
+                    return;
+                }
+            }
+
+            // OK we did not have an explicit SetActivityID set.   Then we should be 
+            // setting the activity to current ActivityInfo.  However that activity 
+            // might be dead, in which case we should skip it, so we never set 
+            // the ID to dead things.   
+            while (cur != null)
+            {
+                // We found a live activity (typically the first time), set it to that.  
+                if (cur.m_stopped == 0)
+                {
+                    EventSource.SetCurrentThreadActivityId(cur.ActivityId);
+                    return;
+                }
+                cur = cur.m_creator;
+            }
+            // we can get here if there is no information on our activity stack (everything is dead)
+            // currently we do nothing, as that seems better than setting to Guid.Emtpy.  
+        }
+
+        /// <summary>
+        /// Async local variables have the property that the are automatically copied whenever a task is created and used
+        /// while that task is running.   Thus m_current 'flows' to any task that is caused by the current thread that
+        /// last set it.   
+        /// 
+        /// This variable points a a linked list that represents all Activities that have started but have not stopped.  
+        /// </summary>
+        AsyncLocal<ActivityInfo> m_current;
+        bool m_checkedForEnable;
+
+        // Singleton
+        private static ActivityTracker s_activityTrackerInstance = new ActivityTracker();
+
+        // Used to create unique IDs at the top level.  Not used for nested Ids (each activity has its own id generator)
+        static long m_nextId = 0;
+        private const ushort MAX_ACTIVITY_DEPTH = 100;            // Limit maximum depth of activities to be tracked at 100. 
+                                                                  // This will avoid leaking memory in case of activities that are never stopped.
+
+        #endregion
+    }
+
+#if ES_BUILD_STANDALONE || ES_BUILD_PN
+    /******************************** SUPPORT *****************************/
+    /// <summary>
+    /// This is supplied by the framework.   It is has the semantics that the value is copied to any new Tasks that is created
+    /// by the current task.   Thus all causally related code gets this value.    Note that reads and writes to this VARIABLE 
+    /// (not what it points it) to this does not need to be protected by locks because it is inherently thread local (you always
+    /// only get your thread local copy which means that you never have races.  
+    /// </summary>
+    /// 
+#if ES_BUILD_STANDALONE
+    [EventSource(Name = "Microsoft.Tasks.Nuget")]
+#else
+    [EventSource(Name = "System.Diagnostics.Tracing.TplEtwProvider")]
+#endif
+    internal class TplEtwProvider : EventSource
+    {
+        public class Keywords
+        {
+            public const EventKeywords TasksFlowActivityIds = (EventKeywords)0x80;
+            public const EventKeywords Debug = (EventKeywords)0x20000;
+        }
+
+        public static TplEtwProvider Log = new TplEtwProvider();
+        public bool Debug { get { return IsEnabled(EventLevel.Verbose, Keywords.Debug); } }
+
+        public void DebugFacilityMessage(string Facility, string Message) { WriteEvent(1, Facility, Message); }
+        public void DebugFacilityMessage1(string Facility, string Message, string Arg) { WriteEvent(2, Facility, Message, Arg); }
+        public void SetActivityId(Guid Id) { WriteEvent(3, Id); }
+    }
+#endif
+
+#if ES_BUILD_AGAINST_DOTNET_V35 || ES_BUILD_PCL || NO_ASYNC_LOCAL
+    // In these cases we don't have any Async local support.   Do nothing.   
+    internal sealed class AsyncLocalValueChangedArgs<T>
+    {
+        public T PreviousValue { get { return default(T); } }
+        public T CurrentValue { get { return default(T); } }
+
+    }
+
+    internal sealed class AsyncLocal<T>
+    {
+        public AsyncLocal(Action<AsyncLocalValueChangedArgs<T>> valueChangedHandler) { 
+            throw new NotImplementedException("AsyncLocal only available on V4.6 and above");
+        }
+        public T Value
+        {
+            get { return default(T); }
+            set { }
+        }
+    }
+#endif
+
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventActivityOptions.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventActivityOptions.cs
new file mode 100644 (file)
index 0000000..782afbf
--- /dev/null
@@ -0,0 +1,39 @@
+// 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;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// EventActivityOptions flags allow to specify different activity related characteristics.
+    /// </summary>
+    [Flags]
+    public enum EventActivityOptions
+    {
+        /// <summary>
+        /// No special options are added to the event.
+        /// </summary>
+        None = 0,
+
+        /// <summary>
+        /// Disable Implicit Activity Tracking
+        /// </summary>
+        Disable = 0x2,
+
+        /// <summary>
+        /// Allow activity event to call itself (directly or indirectly)
+        /// </summary>
+        Recursive = 0x4,
+
+        /// <summary>
+        /// Allows event activity to live beyond its parent.
+        /// </summary>
+        Detachable = 0x8
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventCounter.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventCounter.cs
new file mode 100644 (file)
index 0000000..b1f9464
--- /dev/null
@@ -0,0 +1,436 @@
+// 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 ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// Provides the ability to collect statistics through EventSource
+    /// </summary>
+    public class EventCounter
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="EventCounter"/> class.
+        /// </summary>
+        /// <param name="name">The name.</param>
+        /// <param name="eventSource">The event source.</param>
+        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;
+            EventCounterGroup.AddEventCounter(eventSource, this);
+        }
+
+        /// <summary>
+        /// Writes the metric.
+        /// </summary>
+        /// <param name="value">The value.</param>
+        public void WriteMetric(float value)
+        {
+            Enqueue(value);
+        }
+
+        #region private implementation
+
+        private readonly string _name;
+
+        #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;
+
+        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 (_bufferedValues)
+                    {
+                        Flush();
+                    }
+                    i = 0;
+                }
+
+                if (result == UnusedBufferSlotValue)
+                {
+                    // CompareExchange succeeded 
+                    _bufferedValuesIndex = i;
+                    return;
+                }
+            }
+        }
+
+        private void Flush()
+        {
+            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)
+        {
+            _sum += value;
+            _sumSquared += value * value;
+            if (_count == 0 || value > _max)
+            {
+                _max = value;
+            }
+
+            if (_count == 0 || value < _min)
+            {
+                _min = value;
+            }
+
+            _count++;
+        }
+
+        internal EventCounterPayload GetEventCounterPayload()
+        {
+            lock (_bufferedValues)
+            {
+                Flush();
+                EventCounterPayload result = new EventCounterPayload();
+                result.Name = _name;
+                result.Count = _count;
+                result.Mean = _sum / _count;
+                result.StandardDerivation = (float)Math.Sqrt(_sumSquared / _count - _sum * _sum / _count / _count);
+                result.Min = _min;
+                result.Max = _max;
+                ResetStatistics();
+                return result;
+            }
+        }
+
+        private void ResetStatistics()
+        {
+            _count = 0;
+            _sum = 0;
+            _sumSquared = 0;
+            _min = 0;
+            _max = 0;
+        }
+
+        #endregion // Statistics Calculation
+
+        #endregion // private implementation
+    }
+
+    #region internal supporting classes
+
+    [EventData]
+    internal class EventCounterPayload : IEnumerable<KeyValuePair<string, object>>
+    {
+        public string Name { get; set; }
+
+        public float Mean { get; set; }
+
+        public float StandardDerivation { 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<KeyValuePair<string, object>> GetEnumerator()
+        {
+            return ForEnumeration.GetEnumerator();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return ForEnumeration.GetEnumerator();
+        }
+
+        private IEnumerable<KeyValuePair<string, object>> ForEnumeration
+        {
+            get
+            {
+                yield return new KeyValuePair<string, object>("Name", Name);
+                yield return new KeyValuePair<string, object>("Mean", Mean);
+                yield return new KeyValuePair<string, object>("StandardDerivation", StandardDerivation);
+                yield return new KeyValuePair<string, object>("Count", Count);
+                yield return new KeyValuePair<string, object>("Min", Min);
+                yield return new KeyValuePair<string, object>("Max", Max);
+            }
+        }
+
+        #endregion // Implementation of the IEnumerable interface
+    }
+
+    internal class EventCounterGroup : IDisposable
+    {
+        private readonly EventSource _eventSource;
+        private readonly int _eventSourceIndex;
+        private readonly List<EventCounter> _eventCounters;
+
+        internal EventCounterGroup(EventSource eventSource, int eventSourceIndex)
+        {
+            _eventSource = eventSource;
+            _eventSourceIndex = eventSourceIndex;
+            _eventCounters = new List<EventCounter>();
+            RegisterCommandCallback();
+        }
+
+        private void Add(EventCounter eventCounter)
+        {
+            _eventCounters.Add(eventCounter);
+        }
+
+        #region EventSource Command Processing
+
+        private void RegisterCommandCallback()
+        {
+            _eventSource.EventCommandExecuted += OnEventSourceCommand;
+        }
+
+        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))
+                {
+                    EnableTimer(value);
+                }
+            }
+        }
+
+        #endregion // EventSource Command Processing
+
+        #region Global EventCounterGroup Array management
+
+        private static EventCounterGroup[] s_eventCounterGroups;
+
+        internal static void AddEventCounter(EventSource eventSource, EventCounter eventCounter)
+        {
+            int eventSourceIndex = EventListener.EventSourceIndex(eventSource);
+
+            EventCounterGroup.EnsureEventSourceIndexAvailable(eventSourceIndex);
+            EventCounterGroup eventCounterGroup = GetEventCounterGroup(eventSource);
+            eventCounterGroup.Add(eventCounter);
+        }
+
+        private static void EnsureEventSourceIndexAvailable(int eventSourceIndex)
+        {
+            if (EventCounterGroup.s_eventCounterGroups == null)
+            {
+                EventCounterGroup.s_eventCounterGroups = new EventCounterGroup[eventSourceIndex + 1];
+            }
+            else if (eventSourceIndex >= EventCounterGroup.s_eventCounterGroups.Length)
+            {
+                EventCounterGroup[] newEventCounterGroups = new EventCounterGroup[eventSourceIndex + 1];
+                Array.Copy(EventCounterGroup.s_eventCounterGroups, 0, newEventCounterGroups, 0, EventCounterGroup.s_eventCounterGroups.Length);
+                EventCounterGroup.s_eventCounterGroups = newEventCounterGroups;
+            }
+        }
+
+        private static EventCounterGroup GetEventCounterGroup(EventSource eventSource)
+        {
+            int eventSourceIndex = EventListener.EventSourceIndex(eventSource);
+            EventCounterGroup result = EventCounterGroup.s_eventCounterGroups[eventSourceIndex];
+            if (result == null)
+            {
+                result = new EventCounterGroup(eventSource, eventSourceIndex);
+                EventCounterGroup.s_eventCounterGroups[eventSourceIndex] = result;
+            }
+
+            return result;
+        }
+
+        #endregion // Global EventCounterGroup Array management
+
+        #region Timer Processing
+
+        private DateTime _timeStampSinceCollectionStarted;
+        private int _pollingIntervalInMilliseconds;
+        private Timer _pollingTimer;
+
+        private void EnableTimer(float pollingIntervalInSeconds)
+        {
+            if (pollingIntervalInSeconds == 0)
+            {
+                if (_pollingTimer != null)
+                {
+                    _pollingTimer.Dispose();
+                    _pollingTimer = null;
+                }
+
+                _pollingIntervalInMilliseconds = 0;
+            }
+            else if (_pollingIntervalInMilliseconds == 0 || pollingIntervalInSeconds < _pollingIntervalInMilliseconds)
+            {
+                _pollingIntervalInMilliseconds = (int)(pollingIntervalInSeconds * 1000);
+                if (_pollingTimer != null)
+                {
+                    _pollingTimer.Dispose();
+                    _pollingTimer = null;
+                }
+
+                _timeStampSinceCollectionStarted = DateTime.Now;
+                _pollingTimer = new Timer(OnTimer, null, _pollingIntervalInMilliseconds, _pollingIntervalInMilliseconds);
+            }
+        }
+
+        private void OnTimer(object state)
+        {
+            if (_eventSource.IsEnabled())
+            {
+                DateTime now = DateTime.Now;
+                TimeSpan elapsed = now - _timeStampSinceCollectionStarted;
+                lock (_pollingTimer)
+                {
+                    foreach (var eventCounter in _eventCounters)
+                    {
+                        EventCounterPayload payload = eventCounter.GetEventCounterPayload();
+                        payload.IntervalSec = (float)elapsed.TotalSeconds;
+                        _eventSource.Write("EventCounters", new EventSourceOptions() { Level = EventLevel.LogAlways }, new { Payload = payload });
+                    }
+
+
+                    _timeStampSinceCollectionStarted = now;
+                }
+            }
+            else
+            {
+                _pollingTimer.Dispose();
+                _pollingTimer = null;
+                EventCounterGroup.s_eventCounterGroups[_eventSourceIndex] = null;
+            }
+        }
+
+        #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
+
+        #region Implementation of the IDisposable interface
+
+        private bool _disposed = false;
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            if (_disposed)
+            {
+                return;
+            }
+
+            if (disposing)
+            {
+                if (_pollingTimer != null)
+                {
+                    _pollingTimer.Dispose();
+                    _pollingTimer = null;
+                }
+            }
+
+            _disposed = true;
+        }
+
+        #endregion // Implementation of the IDisposable interface
+    }
+
+    #endregion // internal supporting classes
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventDescriptor.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventDescriptor.cs
new file mode 100644 (file)
index 0000000..a1dcf1c
--- /dev/null
@@ -0,0 +1,195 @@
+// 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 Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
+#endif
+
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    [StructLayout(LayoutKind.Explicit, Size = 16)]
+#if !CORECLR && !ES_BUILD_PN    
+    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
+#endif // !CORECLR && !ES_BUILD_PN
+    internal struct EventDescriptor
+    {
+        # region private
+        [FieldOffset(0)]
+        private int m_traceloggingId;
+        [FieldOffset(0)]
+        private ushort m_id;
+        [FieldOffset(2)]
+        private byte m_version;
+        [FieldOffset(3)]
+        private byte m_channel;
+        [FieldOffset(4)]
+        private byte m_level;
+        [FieldOffset(5)]
+        private byte m_opcode;
+        [FieldOffset(6)]
+        private ushort m_task;
+        [FieldOffset(8)]
+        private long m_keywords;
+        #endregion
+
+        public EventDescriptor(
+                int traceloggingId,
+                byte level,
+                byte opcode,
+                long keywords
+                )
+        {
+            this.m_id = 0;
+            this.m_version = 0;
+            this.m_channel = 0;
+            this.m_traceloggingId = traceloggingId;
+            this.m_level = level;
+            this.m_opcode = opcode;
+            this.m_task = 0;
+            this.m_keywords = keywords;
+        }
+
+        public EventDescriptor(
+                int id,
+                byte version,
+                byte channel,
+                byte level,
+                byte opcode,
+                int task,
+                long keywords
+                )
+        {
+            if (id < 0)
+            {
+                throw new ArgumentOutOfRangeException(nameof(id), Resources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+            }
+
+            if (id > ushort.MaxValue)
+            {
+                throw new ArgumentOutOfRangeException(nameof(id), Resources.GetResourceString("ArgumentOutOfRange_NeedValidId", 1, ushort.MaxValue));
+            }
+
+            m_traceloggingId = 0;
+            m_id = (ushort)id;
+            m_version = version;
+            m_channel = channel;
+            m_level = level;
+            m_opcode = opcode;
+            m_keywords = keywords;
+
+            if (task < 0)
+            {
+                throw new ArgumentOutOfRangeException(nameof(task), Resources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+            }
+
+            if (task > ushort.MaxValue)
+            {
+                throw new ArgumentOutOfRangeException(nameof(task), Resources.GetResourceString("ArgumentOutOfRange_NeedValidId", 1, ushort.MaxValue));
+            }
+
+            m_task = (ushort)task;
+        }
+
+        public int EventId
+        {
+            get
+            {
+                return m_id;
+            }
+        }
+        public byte Version
+        {
+            get
+            {
+                return m_version;
+            }
+        }
+        public byte Channel
+        {
+            get
+            {
+                return m_channel;
+            }
+        }
+        public byte Level
+        {
+            get
+            {
+                return m_level;
+            }
+        }
+        public byte Opcode
+        {
+            get
+            {
+                return m_opcode;
+            }
+        }
+        public int Task
+        {
+            get
+            {
+                return m_task;
+            }
+        }
+        public long Keywords
+        {
+            get
+            {
+                return m_keywords;
+            }
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (!(obj is EventDescriptor))
+                return false;
+
+            return Equals((EventDescriptor) obj);
+        }
+
+        public override int GetHashCode()
+        {
+            return m_id ^ m_version ^ m_channel ^ m_level ^ m_opcode ^ m_task ^ (int)m_keywords;
+        }
+
+        public bool Equals(EventDescriptor other)
+        {
+            if ((m_id != other.m_id) ||
+                (m_version != other.m_version) ||
+                (m_channel != other.m_channel) ||
+                (m_level != other.m_level) ||
+                (m_opcode != other.m_opcode) ||
+                (m_task != other.m_task) ||
+                (m_keywords != other.m_keywords))
+            {
+                return false;
+            }
+            return true;
+        }
+
+        public static bool operator ==(EventDescriptor event1, EventDescriptor event2)
+        {
+            return event1.Equals(event2);
+        }
+
+        public static bool operator !=(EventDescriptor event1, EventDescriptor event2)
+        {
+            return !event1.Equals(event2);
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs
new file mode 100644 (file)
index 0000000..e18574c
--- /dev/null
@@ -0,0 +1,1207 @@
+// 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 Microsoft.Win32;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System.Security;
+#if !CORECLR && !ES_BUILD_PN
+using System.Security.Permissions;
+#endif // !CORECLR && !ES_BUILD_PN
+using System.Threading;
+using System;
+
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
+#if ES_BUILD_AGAINST_DOTNET_V35
+using Microsoft.Internal;       // for Tuple (can't define alias for open generic types so we "use" the whole namespace)
+#endif
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    // New in CLR4.0
+    internal enum ControllerCommand
+    {
+        // Strictly Positive numbers are for provider-specific commands, negative number are for 'shared' commands. 256
+        // The first 256 negative numbers are reserved for the framework.  
+        Update = 0,                 // Not used by EventPrividerBase.  
+        SendManifest = -1,
+        Enable = -2,
+        Disable = -3,
+    };
+
+    /// <summary>
+    /// Only here because System.Diagnostics.EventProvider needs one more extensibility hook (when it gets a 
+    /// controller callback)
+    /// </summary>
+#if !CORECLR && !ES_BUILD_PN
+    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
+#endif // !CORECLR && !ES_BUILD_PN
+    internal partial 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
+        // EventWrite.   We do make it a nested type because we really don't expect anyone to use 
+        // it except subclasses (and then only rarely).  
+        public struct EventData
+        {
+            internal unsafe ulong Ptr;
+            internal uint Size;
+            internal uint Reserved;
+        }
+
+        /// <summary>
+        /// A struct characterizing ETW sessions (identified by the etwSessionId) as
+        /// activity-tracing-aware or legacy. A session that's activity-tracing-aware
+        /// has specified one non-zero bit in the reserved range 44-47 in the 
+        /// 'allKeywords' value it passed in for a specific EventProvider.
+        /// </summary>
+        public struct SessionInfo
+        {
+            internal int sessionIdBit;      // the index of the bit used for tracing in the "reserved" field of AllKeywords
+            internal int etwSessionId;      // the machine-wide ETW session ID
+
+            internal SessionInfo(int sessionIdBit_, int etwSessionId_)
+            { sessionIdBit = sessionIdBit_; etwSessionId = etwSessionId_; }
+        }
+
+        private static bool m_setInformationMissing;
+
+        UnsafeNativeMethods.ManifestEtw.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
+        private long m_allKeywordMask;                   // Match all keyword
+        private List<SessionInfo> m_liveSessions;        // current live sessions (Tuple<sessionIdBit, etwSessionId>)
+        private bool m_enabled;                          // Enabled flag from Trace callback
+        private Guid m_providerId;                       // Control Guid 
+        internal bool m_disposed;                        // when true provider has unregistered
+
+        [ThreadStatic]
+        private static WriteEventErrorCode s_returnCode; // The last return code 
+
+        private const int s_basicTypeAllocationBufferSize = 16;
+        private const int s_etwMaxNumberArguments = 128;
+        private const int s_etwAPIMaxRefObjCount = 8;
+        private const int s_maxEventDataDescriptors = 128;
+        private const int s_traceEventMaximumSize = 65482;
+        private const int s_traceEventMaximumStringSize = 32724;
+
+        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
+        public enum WriteEventErrorCode : int
+        {
+            //check mapping to runtime codes
+            NoError = 0,
+            NoFreeBuffers = 1,
+            EventTooBig = 2,
+            NullInput = 3,
+            TooManyArgs = 4,
+            Other = 5,
+        };
+
+        // Because callbacks happen on registration, and we need the callbacks for those setup
+        // we can't call Register in the constructor.   
+        //
+        // Note that EventProvider should ONLY be used by EventSource.  In particular because
+        // it registers a callback from native code you MUST dispose it BEFORE shutdown, otherwise
+        // you may get native callbacks during shutdown when we have destroyed the delegate.  
+        // EventSource has special logic to do this, no one else should be calling EventProvider.  
+        internal EventProvider()
+        {
+        }
+
+        /// <summary>
+        /// This method registers the controlGuid of this class with ETW. We need to be running on
+        /// Vista or above. If not a PlatformNotSupported exception will be thrown. If for some 
+        /// reason the ETW Register call failed a NotSupported exception will be thrown. 
+        /// </summary>
+        // <SecurityKernel Critical="True" Ring="0">
+        // <CallsSuppressUnmanagedCode Name="UnsafeNativeMethods.ManifestEtw.EventRegister(System.Guid&,Microsoft.Win32.UnsafeNativeMethods.ManifestEtw+EtwEnableCallback,System.Void*,System.Int64&):System.UInt32" />
+        // <SatisfiesLinkDemand Name="Win32Exception..ctor(System.Int32)" />
+        // <ReferencesCritical Name="Method: EtwEnableCallBack(Guid&, Int32, Byte, Int64, Int64, Void*, Void*):Void" Ring="1" />
+        // </SecurityKernel>
+        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)
+            {
+                throw new ArgumentException(Win32Native.GetMessage(unchecked((int)status)));
+            }
+        }
+
+        //
+        // implement Dispose Pattern to early deregister from ETW insted of waiting for 
+        // the finalizer to call deregistration.
+        // Once the user is done with the provider it needs to call Close() or Dispose()
+        // If neither are called the finalizer will unregister the provider anyway
+        //
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        // <SecurityKernel Critical="True" TreatAsSafe="Does not expose critical resource" Ring="1">
+        // <ReferencesCritical Name="Method: Deregister():Void" Ring="1" />
+        // </SecurityKernel>
+        protected virtual void Dispose(bool disposing)
+        {
+            //
+            // explicit cleanup is done by calling Dispose with true from 
+            // Dispose() or Close(). The disposing arguement is ignored because there
+            // are no unmanaged resources.
+            // The finalizer calls Dispose with false.
+            //
+
+            //
+            // check if the object has been allready disposed
+            //
+            if (m_disposed) return;
+
+            // Disable the provider.  
+            m_enabled = false;
+
+            // Do most of the work under a lock to avoid shutdown race.
+
+            long registrationHandle = 0;  
+            lock (EventListener.EventListenersLock)
+            {
+                // Double check
+                if (m_disposed)
+                    return;
+
+                registrationHandle = m_regHandle;
+                m_regHandle = 0;
+                m_disposed = true;
+            }
+
+            // We do the Unregistration outside the EventListenerLock because there is a lock
+            // inside the ETW routines.   This lock is taken before ETW issues commands
+            // Thus the ETW lock gets taken first and then our EventListenersLock gets taken
+            // in SendCommand(), and also here.  If we called EventUnregister after taking
+            // the EventListenersLock then the take-lock order is reversed and we can have
+            // deadlocks in race conditions (dispose racing with an ETW command).   
+            // 
+            // We solve by Unregistering after releasing the EventListenerLock.     
+            if (registrationHandle != 0)
+                EventUnregister(registrationHandle);
+
+        }
+
+        /// <summary>
+        /// This method deregisters the controlGuid of this class with ETW.
+        /// 
+        /// </summary>
+        public virtual void Close()
+        {
+            Dispose();
+        }
+
+        ~EventProvider()
+        {
+            Dispose(false);
+        }
+
+        // <SecurityKernel Critical="True" Ring="0">
+        // <UsesUnsafeCode Name="Parameter filterData of type: Void*" />
+        // <UsesUnsafeCode Name="Parameter callbackContext of type: Void*" />
+        // </SecurityKernel>
+        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
+                        )
+        {
+            // This is an optional callback API. We will therefore ignore any failures that happen as a 
+            // result of turning on this provider as to not crash the app.
+            // EventSource has code to validate whether initialization it expected to occur actually occurred
+            try
+            {
+                ControllerCommand command = ControllerCommand.Update;
+                IDictionary<string, string> args = null;
+                bool skipFinalOnControllerCommand = false;
+                if (controlCode == UnsafeNativeMethods.ManifestEtw.EVENT_CONTROL_CODE_ENABLE_PROVIDER)
+                {
+                    m_enabled = true;
+                    m_level = setLevel;
+                    m_anyKeywordMask = anyKeyword;
+                    m_allKeywordMask = allKeyword;
+
+                    // ES_SESSION_INFO is a marker for additional places we #ifdeffed out to remove
+                    // references to EnumerateTraceGuidsEx.  This symbol is actually not used because
+                    // today we use FEATURE_ACTIVITYSAMPLING to determine if this code is there or not.
+                    // However we put it in the #if so that we don't lose the fact that this feature
+                    // switch is at least partially independent of FEATURE_ACTIVITYSAMPLING
+
+                    List<Tuple<SessionInfo, bool>> sessionsChanged = GetSessions();
+                    foreach (var session in sessionsChanged)
+                    {
+                        int sessionChanged = session.Item1.sessionIdBit;
+                        int etwSessionId = session.Item1.etwSessionId;
+                        bool bEnabling = session.Item2;
+
+                        skipFinalOnControllerCommand = true;
+                        args = null;                                // reinitialize args for every session...
+
+                        // if we get more than one session changed we have no way
+                        // of knowing which one "filterData" belongs to
+                        if (sessionsChanged.Count > 1)
+                            filterData = null;
+
+                        // read filter data only when a session is being *added*
+                        byte[] data;
+                        int keyIndex;
+                        if (bEnabling &&
+                            GetDataFromController(etwSessionId, filterData, out command, out data, out keyIndex))
+                        {
+                            args = new Dictionary<string, string>(4);
+                            while (keyIndex < data.Length)
+                            {
+                                int keyEnd = FindNull(data, keyIndex);
+                                int valueIdx = keyEnd + 1;
+                                int valueEnd = FindNull(data, valueIdx);
+                                if (valueEnd < data.Length)
+                                {
+                                    string key = System.Text.Encoding.UTF8.GetString(data, keyIndex, keyEnd - keyIndex);
+                                    string value = System.Text.Encoding.UTF8.GetString(data, valueIdx, valueEnd - valueIdx);
+                                    args[key] = value;
+                                }
+                                keyIndex = valueEnd + 1;
+                            }
+                        }
+
+                        // execute OnControllerCommand once for every session that has changed.
+                        OnControllerCommand(command, args, (bEnabling ? sessionChanged : -sessionChanged), etwSessionId);
+                    }
+                }
+                else if (controlCode == UnsafeNativeMethods.ManifestEtw.EVENT_CONTROL_CODE_DISABLE_PROVIDER)
+                {
+                    m_enabled = false;
+                    m_level = 0;
+                    m_anyKeywordMask = 0;
+                    m_allKeywordMask = 0;
+                    m_liveSessions = null;
+                }
+                else if (controlCode == UnsafeNativeMethods.ManifestEtw.EVENT_CONTROL_CODE_CAPTURE_STATE)
+                {
+                    command = ControllerCommand.SendManifest;
+                }
+                else
+                    return;     // per spec you ignore commands you don't recognize.  
+
+                if (!skipFinalOnControllerCommand)
+                    OnControllerCommand(command, args, 0, 0);
+            }
+            catch (Exception)
+            {
+                // We want to ignore any failures that happen as a result of turning on this provider as to
+                // not crash the app.
+            }
+        }
+
+        // New in CLR4.0
+        protected virtual void OnControllerCommand(ControllerCommand command, IDictionary<string, string> arguments, int sessionId, int etwSessionId) { }
+        protected EventLevel Level { get { return (EventLevel)m_level; } set { m_level = (byte)value; } }
+        protected EventKeywords MatchAnyKeyword { get { return (EventKeywords)m_anyKeywordMask; } set { m_anyKeywordMask = unchecked((long)value); } }
+        protected EventKeywords MatchAllKeyword { get { return (EventKeywords)m_allKeywordMask; } set { m_allKeywordMask = unchecked((long)value); } }
+
+        static private int FindNull(byte[] buffer, int idx)
+        {
+            while (idx < buffer.Length && buffer[idx] != 0)
+                idx++;
+            return idx;
+        }
+
+        /// <summary>
+        /// Determines the ETW sessions that have been added and/or removed to the set of
+        /// sessions interested in the current provider. It does so by (1) enumerating over all
+        /// ETW sessions that enabled 'this.m_Guid' for the current process ID, and (2)
+        /// comparing the current list with a list it cached on the previous invocation.
+        ///
+        /// The return value is a list of tuples, where the SessionInfo specifies the
+        /// ETW session that was added or remove, and the bool specifies whether the
+        /// session was added or whether it was removed from the set.
+        /// </summary>
+        private List<Tuple<SessionInfo, bool>> GetSessions()
+        {
+            List<SessionInfo> liveSessionList = null;
+
+            GetSessionInfo(
+                (int etwSessionId, long matchAllKeywords, ref List<SessionInfo> sessionList) =>
+                    GetSessionInfoCallback(etwSessionId, matchAllKeywords, ref sessionList),
+                ref liveSessionList);
+
+            List<Tuple<SessionInfo, bool>> changedSessionList = new List<Tuple<SessionInfo, bool>>();
+
+            // first look for sessions that have gone away (or have changed)
+            // (present in the m_liveSessions but not in the new liveSessionList)
+            if (m_liveSessions != null)
+            {
+                foreach (SessionInfo s in m_liveSessions)
+                {
+                    int idx;
+                    if ((idx = IndexOfSessionInList(liveSessionList, s.etwSessionId)) < 0 ||
+                        (liveSessionList[idx].sessionIdBit != s.sessionIdBit))
+                        changedSessionList.Add(Tuple.Create(s, false));
+
+                }
+            }
+            // next look for sessions that were created since the last callback  (or have changed)
+            // (present in the new liveSessionList but not in m_liveSessions)
+            if (liveSessionList != null)
+            {
+                foreach (SessionInfo s in liveSessionList)
+                {
+                    int idx;
+                    if ((idx = IndexOfSessionInList(m_liveSessions, s.etwSessionId)) < 0 ||
+                        (m_liveSessions[idx].sessionIdBit != s.sessionIdBit))
+                        changedSessionList.Add(Tuple.Create(s, true));
+                }
+            }
+
+            m_liveSessions = liveSessionList;
+            return changedSessionList;
+        }
+
+
+        /// <summary>
+        /// This method is the callback used by GetSessions() when it calls into GetSessionInfo(). 
+        /// It updates a List{SessionInfo} based on the etwSessionId and matchAllKeywords that 
+        /// GetSessionInfo() passes in.
+        /// </summary>
+        private static void GetSessionInfoCallback(int etwSessionId, long matchAllKeywords,
+                                ref List<SessionInfo> sessionList)
+        {
+            uint sessionIdBitMask = (uint)SessionMask.FromEventKeywords(unchecked((ulong)matchAllKeywords));
+            // an ETW controller that specifies more than the mandated bit for our EventSource
+            // will be ignored...
+            if (bitcount(sessionIdBitMask) > 1)
+                return;
+
+            if (sessionList == null)
+                sessionList = new List<SessionInfo>(8);
+
+            if (bitcount(sessionIdBitMask) == 1)
+            {
+                // activity-tracing-aware etw session
+                sessionList.Add(new SessionInfo(bitindex(sessionIdBitMask) + 1, etwSessionId));
+            }
+            else
+            {
+                // legacy etw session
+                sessionList.Add(new SessionInfo(bitcount((uint)SessionMask.All) + 1, etwSessionId));
+            }
+        }
+
+        private delegate void SessionInfoCallback(int etwSessionId, long matchAllKeywords, ref List<SessionInfo> sessionList);
+        
+        /// <summary>
+        /// This method enumerates over all active ETW sessions that have enabled 'this.m_Guid' 
+        /// for the current process ID, calling 'action' for each session, and passing it the
+        /// ETW session and the 'AllKeywords' the session enabled for the current provider.
+        /// </summary>
+        private unsafe void GetSessionInfo(SessionInfoCallback action, ref List<SessionInfo> sessionList)
+        {
+            // We wish the EventSource package to be legal for Windows Store applications.   
+            // Currently EnumerateTraceGuidsEx is not an allowed API, so we avoid its use here
+            // and use the information in the registry instead.  This means that ETW controllers
+            // that do not publish their intent to the registry (basically all controllers EXCEPT 
+            // TraceEventSesion) will not work properly 
+
+            // However the framework version of EventSource DOES have ES_SESSION_INFO defined and thus
+            // does not have this issue.  
+#if ES_SESSION_INFO || !ES_BUILD_STANDALONE  
+            int buffSize = 256;     // An initial guess that probably works most of the time.  
+            byte* buffer;
+            for (; ; )
+            {
+                var space = stackalloc byte[buffSize];
+                buffer = space;
+                var hr = 0;
+
+                fixed (Guid* provider = &m_providerId)
+                {
+                    hr = UnsafeNativeMethods.ManifestEtw.EnumerateTraceGuidsEx(UnsafeNativeMethods.ManifestEtw.TRACE_QUERY_INFO_CLASS.TraceGuidQueryInfo,
+                        provider, sizeof(Guid), buffer, buffSize, ref buffSize);
+                }
+                if (hr == 0)
+                    break;
+                if (hr != 122 /* ERROR_INSUFFICIENT_BUFFER */)
+                    return;
+            }
+
+            var providerInfos = (UnsafeNativeMethods.ManifestEtw.TRACE_GUID_INFO*)buffer;
+            var providerInstance = (UnsafeNativeMethods.ManifestEtw.TRACE_PROVIDER_INSTANCE_INFO*)&providerInfos[1];
+            int processId = unchecked((int)Win32Native.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];
+                    // 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);
+                }
+                if (providerInstance->NextOffset == 0)
+                    break;
+                Debug.Assert(0 <= providerInstance->NextOffset && providerInstance->NextOffset < buffSize);
+                var structBase = (byte*)providerInstance;
+                providerInstance = (UnsafeNativeMethods.ManifestEtw.TRACE_PROVIDER_INSTANCE_INFO*)&structBase[providerInstance->NextOffset];
+            }
+#else 
+#if !ES_BUILD_PCL && !FEATURE_PAL  // TODO command arguments don't work on PCL builds...
+            // This code is only used in the Nuget Package Version of EventSource.  because
+            // the code above is using APIs baned from UWP apps.     
+            // 
+            // TODO: In addition to only working when TraceEventSession enables the provider, this code
+            // also has a problem because TraceEvent does not clean up if the registry is stale 
+            // It is unclear if it is worth keeping, but for now we leave it as it does work
+            // at least some of the time.  
+
+            // Determine our session from what is in the registry.  
+            string regKey = @"\Microsoft\Windows\CurrentVersion\Winevt\Publishers\{" + m_providerId + "}";
+            if (System.Runtime.InteropServices.Marshal.SizeOf(typeof(IntPtr)) == 8)
+                regKey = @"Software" + @"\Wow6432Node" + regKey;
+            else
+                regKey = @"Software" + regKey;
+
+            var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(regKey);
+            if (key != null)
+            {
+                foreach (string valueName in key.GetValueNames())
+                {
+                    if (valueName.StartsWith("ControllerData_Session_", StringComparison.Ordinal))
+                    {
+                        string strId = valueName.Substring(23);      // strip of the ControllerData_Session_
+                        int etwSessionId;
+                        if (int.TryParse(strId, out etwSessionId))
+                        {
+                            // we need to assert this permission for partial trust scenarios
+                            (new RegistryPermission(RegistryPermissionAccess.Read, regKey)).Assert();
+                            var data = key.GetValue(valueName) as byte[];
+                            if (data != null)
+                            {
+                                var dataAsString = System.Text.Encoding.UTF8.GetString(data);
+                                int keywordIdx = dataAsString.IndexOf("EtwSessionKeyword", StringComparison.Ordinal);
+                                if (0 <= keywordIdx)
+                                {
+                                    int startIdx = keywordIdx + 18;
+                                    int endIdx = dataAsString.IndexOf('\0', startIdx);
+                                    string keywordBitString = dataAsString.Substring(startIdx, endIdx-startIdx);
+                                    int keywordBit;
+                                    if (0 < endIdx && int.TryParse(keywordBitString, out keywordBit))
+                                        action(etwSessionId, 1L << keywordBit, ref sessionList);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+#endif
+#endif
+        }
+
+        /// <summary>
+        /// Returns the index of the SesisonInfo from 'sessions' that has the specified 'etwSessionId'
+        /// or -1 if the value is not present.
+        /// </summary>
+        private static int IndexOfSessionInList(List<SessionInfo> sessions, int etwSessionId)
+        {
+            if (sessions == null)
+                return -1;
+            // for non-coreclr code we could use List<T>.FindIndex(Predicate<T>), but we need this to compile
+            // on coreclr as well
+            for (int i = 0; i < sessions.Count; ++i)
+                if (sessions[i].etwSessionId == etwSessionId)
+                    return i;
+
+            return -1;
+        }
+
+        /// <summary>
+        /// Gets any data to be passed from the controller to the provider.  It starts with what is passed
+        /// into the callback, but unfortunately this data is only present for when the provider is active
+        /// at the time the controller issues the command.  To allow for providers to activate after the
+        /// controller issued a command, we also check the registry and use that to get the data.  The function
+        /// returns an array of bytes representing the data, the index into that byte array where the data
+        /// starts, and the command being issued associated with that data.  
+        /// </summary>
+        private unsafe bool GetDataFromController(int etwSessionId,
+                UnsafeNativeMethods.ManifestEtw.EVENT_FILTER_DESCRIPTOR* filterData, out ControllerCommand command, out byte[] data, out int dataStart)
+        {
+            data = null;
+            dataStart = 0;
+            if (filterData == null)
+            {
+#if (!ES_BUILD_PCL && !ES_BUILD_PN && !FEATURE_PAL)
+                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;
+                else
+                    regKey = @"HKEY_LOCAL_MACHINE\Software" + regKey;
+
+                string valueName = "ControllerData_Session_" + etwSessionId.ToString(CultureInfo.InvariantCulture);
+
+                // we need to assert this permission for partial trust scenarios
+#if !CORECLR
+                (new RegistryPermission(RegistryPermissionAccess.Read, regKey)).Assert();
+#endif
+                data = Microsoft.Win32.Registry.GetValue(regKey, valueName, null) as byte[];
+                if (data != null)
+                {
+                    // We only used the persisted data from the registry for updates.   
+                    command = ControllerCommand.Update;
+                    return true;
+                }
+#endif
+            }
+            else
+            {
+                if (filterData->Ptr != 0 && 0 < filterData->Size && filterData->Size <= 1024)
+                {
+                    data = new byte[filterData->Size];
+                    Marshal.Copy((IntPtr)filterData->Ptr, data, 0, data.Length);
+                }
+                command = (ControllerCommand)filterData->Type;
+                return true;
+            }
+
+            command = ControllerCommand.Update;
+            return false;
+        }
+
+        /// <summary>
+        /// IsEnabled, method used to test if provider is enabled
+        /// </summary>
+        public bool IsEnabled()
+        {
+            return m_enabled;
+        }
+
+        /// <summary>
+        /// IsEnabled, method used to test if event is enabled
+        /// </summary>
+        /// <param name="level">
+        /// Level  to test
+        /// </param>
+        /// <param name="keywords">
+        /// Keyword  to test
+        /// </param>
+        public bool IsEnabled(byte level, long keywords)
+        {
+            //
+            // If not enabled at all, return false.
+            //
+            if (!m_enabled)
+            {
+                return false;
+            }
+
+            // This also covers the case of Level == 0.
+            if ((level <= m_level) ||
+                (m_level == 0))
+            {
+
+                //
+                // Check if Keyword is enabled
+                //
+
+                if ((keywords == 0) ||
+                    (((keywords & m_anyKeywordMask) != 0) &&
+                     ((keywords & m_allKeywordMask) == m_allKeywordMask)))
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
+        public static WriteEventErrorCode GetLastWriteEventError()
+        {
+            return s_returnCode;
+        }
+
+        //
+        // Helper function to set the last error on the thread
+        //
+        private static void SetLastError(int 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;
+            }
+        }
+
+        // <SecurityKernel Critical="True" Ring="0">
+        // <UsesUnsafeCode Name="Local intptrPtr of type: IntPtr*" />
+        // <UsesUnsafeCode Name="Local intptrPtr of type: Int32*" />
+        // <UsesUnsafeCode Name="Local longptr of type: Int64*" />
+        // <UsesUnsafeCode Name="Local uintptr of type: UInt32*" />
+        // <UsesUnsafeCode Name="Local ulongptr of type: UInt64*" />
+        // <UsesUnsafeCode Name="Local charptr of type: Char*" />
+        // <UsesUnsafeCode Name="Local byteptr of type: Byte*" />
+        // <UsesUnsafeCode Name="Local shortptr of type: Int16*" />
+        // <UsesUnsafeCode Name="Local sbyteptr of type: SByte*" />
+        // <UsesUnsafeCode Name="Local ushortptr of type: UInt16*" />
+        // <UsesUnsafeCode Name="Local floatptr of type: Single*" />
+        // <UsesUnsafeCode Name="Local doubleptr of type: Double*" />
+        // <UsesUnsafeCode Name="Local boolptr of type: Boolean*" />
+        // <UsesUnsafeCode Name="Local guidptr of type: Guid*" />
+        // <UsesUnsafeCode Name="Local decimalptr of type: Decimal*" />
+        // <UsesUnsafeCode Name="Local booleanptr of type: Boolean*" />
+        // <UsesUnsafeCode Name="Parameter dataDescriptor of type: EventData*" />
+        // <UsesUnsafeCode Name="Parameter dataBuffer of type: Byte*" />
+        // </SecurityKernel>
+        private static unsafe object EncodeObject(ref object data, ref EventData* dataDescriptor, ref byte* dataBuffer, ref uint totalEventSize)
+        /*++
+
+        Routine Description:
+
+           This routine is used by WriteEvent to unbox the object type and
+           to fill the passed in ETW data descriptor. 
+
+        Arguments:
+
+           data - argument to be decoded
+
+           dataDescriptor - pointer to the descriptor to be filled (updated to point to the next empty entry)
+
+           dataBuffer - storage buffer for storing user data, needed because cant get the address of the object
+                        (updated to point to the next empty entry)
+
+        Return Value:
+
+           null if the object is a basic type other than string or byte[]. String otherwise
+
+        --*/
+        {
+        Again:
+            dataDescriptor->Reserved = 0;
+
+            string sRet = data as string;
+            byte[] blobRet = null;
+
+            if (sRet != null)
+            {
+                dataDescriptor->Size = ((uint)sRet.Length + 1) * 2;
+            }
+            else if ((blobRet = data as byte[]) != null)
+            {
+                // first store array length
+                *(int*)dataBuffer = blobRet.Length;
+                dataDescriptor->Ptr = (ulong)dataBuffer;
+                dataDescriptor->Size = 4;
+                totalEventSize += dataDescriptor->Size;
+
+                // then the array parameters
+                dataDescriptor++;
+                dataBuffer += s_basicTypeAllocationBufferSize;
+                dataDescriptor->Size = (uint)blobRet.Length;
+            }
+            else if (data is IntPtr)
+            {
+                dataDescriptor->Size = (uint)sizeof(IntPtr);
+                IntPtr* intptrPtr = (IntPtr*)dataBuffer;
+                *intptrPtr = (IntPtr)data;
+                dataDescriptor->Ptr = (ulong)intptrPtr;
+            }
+            else if (data is int)
+            {
+                dataDescriptor->Size = (uint)sizeof(int);
+                int* intptr = (int*)dataBuffer;
+                *intptr = (int)data;
+                dataDescriptor->Ptr = (ulong)intptr;
+            }
+            else if (data is long)
+            {
+                dataDescriptor->Size = (uint)sizeof(long);
+                long* longptr = (long*)dataBuffer;
+                *longptr = (long)data;
+                dataDescriptor->Ptr = (ulong)longptr;
+            }
+            else if (data is uint)
+            {
+                dataDescriptor->Size = (uint)sizeof(uint);
+                uint* uintptr = (uint*)dataBuffer;
+                *uintptr = (uint)data;
+                dataDescriptor->Ptr = (ulong)uintptr;
+            }
+            else if (data is UInt64)
+            {
+                dataDescriptor->Size = (uint)sizeof(ulong);
+                UInt64* ulongptr = (ulong*)dataBuffer;
+                *ulongptr = (ulong)data;
+                dataDescriptor->Ptr = (ulong)ulongptr;
+            }
+            else if (data is char)
+            {
+                dataDescriptor->Size = (uint)sizeof(char);
+                char* charptr = (char*)dataBuffer;
+                *charptr = (char)data;
+                dataDescriptor->Ptr = (ulong)charptr;
+            }
+            else if (data is byte)
+            {
+                dataDescriptor->Size = (uint)sizeof(byte);
+                byte* byteptr = (byte*)dataBuffer;
+                *byteptr = (byte)data;
+                dataDescriptor->Ptr = (ulong)byteptr;
+            }
+            else if (data is short)
+            {
+                dataDescriptor->Size = (uint)sizeof(short);
+                short* shortptr = (short*)dataBuffer;
+                *shortptr = (short)data;
+                dataDescriptor->Ptr = (ulong)shortptr;
+            }
+            else if (data is sbyte)
+            {
+                dataDescriptor->Size = (uint)sizeof(sbyte);
+                sbyte* sbyteptr = (sbyte*)dataBuffer;
+                *sbyteptr = (sbyte)data;
+                dataDescriptor->Ptr = (ulong)sbyteptr;
+            }
+            else if (data is ushort)
+            {
+                dataDescriptor->Size = (uint)sizeof(ushort);
+                ushort* ushortptr = (ushort*)dataBuffer;
+                *ushortptr = (ushort)data;
+                dataDescriptor->Ptr = (ulong)ushortptr;
+            }
+            else if (data is float)
+            {
+                dataDescriptor->Size = (uint)sizeof(float);
+                float* floatptr = (float*)dataBuffer;
+                *floatptr = (float)data;
+                dataDescriptor->Ptr = (ulong)floatptr;
+            }
+            else if (data is double)
+            {
+                dataDescriptor->Size = (uint)sizeof(double);
+                double* doubleptr = (double*)dataBuffer;
+                *doubleptr = (double)data;
+                dataDescriptor->Ptr = (ulong)doubleptr;
+            }
+            else if (data is bool)
+            {
+                // WIN32 Bool is 4 bytes
+                dataDescriptor->Size = 4;
+                int* intptr = (int*)dataBuffer;
+                if (((bool)data))
+                {
+                    *intptr = 1;
+                }
+                else
+                {
+                    *intptr = 0;
+                }
+                dataDescriptor->Ptr = (ulong)intptr;
+            }
+            else if (data is Guid)
+            {
+                dataDescriptor->Size = (uint)sizeof(Guid);
+                Guid* guidptr = (Guid*)dataBuffer;
+                *guidptr = (Guid)data;
+                dataDescriptor->Ptr = (ulong)guidptr;
+            }
+            else if (data is decimal)
+            {
+                dataDescriptor->Size = (uint)sizeof(decimal);
+                decimal* decimalptr = (decimal*)dataBuffer;
+                *decimalptr = (decimal)data;
+                dataDescriptor->Ptr = (ulong)decimalptr;
+            }
+            else if (data is DateTime)
+            {
+                const long UTCMinTicks = 504911232000000000;
+                long dateTimeTicks = 0;
+                // We cannot translate dates sooner than 1/1/1601 in UTC. 
+                // To avoid getting an ArgumentOutOfRangeException we compare with 1/1/1601 DateTime ticks
+                if (((DateTime)data).Ticks > UTCMinTicks)
+                    dateTimeTicks = ((DateTime)data).ToFileTimeUtc();
+                dataDescriptor->Size = (uint)sizeof(long);
+                long* longptr = (long*)dataBuffer;
+                *longptr = dateTimeTicks;
+                dataDescriptor->Ptr = (ulong)longptr;
+            }
+            else
+            {
+                if (data is System.Enum)
+                {
+                    Type underlyingType = Enum.GetUnderlyingType(data.GetType());
+                    if (underlyingType == typeof(int))
+                    {
+#if !ES_BUILD_PCL
+                        data = ((IConvertible)data).ToInt32(null);
+#else
+                        data = (int)data;
+#endif
+                        goto Again;
+                    }
+                    else if (underlyingType == typeof(long))
+                    {
+#if !ES_BUILD_PCL
+                        data = ((IConvertible)data).ToInt64(null);
+#else
+                        data = (long)data;
+#endif
+                        goto Again;
+                    }
+                }
+
+                // To our eyes, everything else is a just a string
+                if (data == null)
+                    sRet = "";
+                else
+                    sRet = data.ToString();
+                dataDescriptor->Size = ((uint)sRet.Length + 1) * 2;
+            }
+
+            totalEventSize += dataDescriptor->Size;
+
+            // advance buffers
+            dataDescriptor++;
+            dataBuffer += s_basicTypeAllocationBufferSize;
+
+            return (object)sRet ?? (object)blobRet;
+        }
+
+        /// <summary>
+        /// WriteEvent, method to write a parameters with event schema properties
+        /// </summary>
+        /// <param name="eventDescriptor">
+        /// Event Descriptor for this event. 
+        /// </param>
+        /// <param name="activityID">
+        /// A pointer to the activity ID GUID to log 
+        /// </param>
+        /// <param name="childActivityID">
+        /// childActivityID is marked as 'related' to the current activity ID. 
+        /// </param>
+        /// <param name="eventPayload">
+        /// Payload for the ETW event. 
+        /// </param>
+        // <SecurityKernel Critical="True" Ring="0">
+        // <CallsSuppressUnmanagedCode Name="UnsafeNativeMethods.ManifestEtw.EventWrite(System.Int64,EventDescriptor&,System.UInt32,System.Void*):System.UInt32" />
+        // <UsesUnsafeCode Name="Local dataBuffer of type: Byte*" />
+        // <UsesUnsafeCode Name="Local pdata of type: Char*" />
+        // <UsesUnsafeCode Name="Local userData of type: EventData*" />
+        // <UsesUnsafeCode Name="Local userDataPtr of type: EventData*" />
+        // <UsesUnsafeCode Name="Local currentBuffer of type: Byte*" />
+        // <UsesUnsafeCode Name="Local v0 of type: Char*" />
+        // <UsesUnsafeCode Name="Local v1 of type: Char*" />
+        // <UsesUnsafeCode Name="Local v2 of type: Char*" />
+        // <UsesUnsafeCode Name="Local v3 of type: Char*" />
+        // <UsesUnsafeCode Name="Local v4 of type: Char*" />
+        // <UsesUnsafeCode Name="Local v5 of type: Char*" />
+        // <UsesUnsafeCode Name="Local v6 of type: Char*" />
+        // <UsesUnsafeCode Name="Local v7 of type: Char*" />
+        // <ReferencesCritical Name="Method: EncodeObject(Object&, EventData*, Byte*):String" Ring="1" />
+        // </SecurityKernel>
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Performance-critical code")]
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
+        internal unsafe bool WriteEvent(ref EventDescriptor eventDescriptor, Guid* activityID, Guid* childActivityID, params object[] eventPayload)
+        {
+            int status = 0;
+
+            if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords))
+            {
+                int argCount = 0;
+                unsafe
+                {
+                    argCount = eventPayload.Length;
+
+                    if (argCount > s_etwMaxNumberArguments)
+                    {
+                        s_returnCode = WriteEventErrorCode.TooManyArgs;
+                        return false;
+                    }
+
+                    uint totalEventSize = 0;
+                    int index;
+                    int refObjIndex = 0;
+                    List<int> refObjPosition = new List<int>(s_etwAPIMaxRefObjCount);
+                    List<object> dataRefObj = new List<object>(s_etwAPIMaxRefObjCount);
+                    EventData* userData = stackalloc EventData[2 * argCount];
+                    EventData* userDataPtr = (EventData*)userData;
+                    byte* dataBuffer = stackalloc byte[s_basicTypeAllocationBufferSize * 2 * argCount]; // Assume 16 chars for non-string argument
+                    byte* currentBuffer = dataBuffer;
+
+                    //
+                    // The loop below goes through all the arguments and fills in the data 
+                    // descriptors. For strings save the location in the dataString array.
+                    // Calculates the total size of the event by adding the data descriptor
+                    // size value set in EncodeObject method.
+                    //
+                    bool hasNonStringRefArgs = false;
+                    for (index = 0; index < eventPayload.Length; index++)
+                    {
+                        if (eventPayload[index] != null)
+                        {
+                            object supportedRefObj;
+                            supportedRefObj = EncodeObject(ref eventPayload[index], ref userDataPtr, ref currentBuffer, ref totalEventSize);
+
+                            if (supportedRefObj != null)
+                            {
+                                // EncodeObject advanced userDataPtr to the next empty slot
+                                int idx = (int)(userDataPtr - userData - 1);
+                                if (!(supportedRefObj is string))
+                                {
+                                    if (eventPayload.Length + idx + 1 - index > s_etwMaxNumberArguments)
+                                    {
+                                        s_returnCode = WriteEventErrorCode.TooManyArgs;
+                                        return false;
+                                    }
+                                    hasNonStringRefArgs = true;
+                                }
+                                dataRefObj.Add(supportedRefObj);
+                                refObjPosition.Add(idx);
+                                refObjIndex++;
+                            }
+                        }
+                        else
+                        {
+                            s_returnCode = WriteEventErrorCode.NullInput;
+                            return false;
+                        }
+                    }
+
+                    // update argCount based on actual number of arguments written to 'userData'
+                    argCount = (int)(userDataPtr - userData);
+
+                    if (totalEventSize > s_traceEventMaximumSize)
+                    {
+                        s_returnCode = WriteEventErrorCode.EventTooBig;
+                        return false;
+                    }
+
+                    // the optimized path (using "fixed" instead of allocating pinned GCHandles
+                    if (!hasNonStringRefArgs && (refObjIndex < s_etwAPIMaxRefObjCount))
+                    {
+                        // Fast path: at most 8 string arguments
+
+                        // ensure we have at least s_etwAPIMaxStringCount in dataString, so that
+                        // the "fixed" statement below works
+                        while (refObjIndex < s_etwAPIMaxRefObjCount)
+                        {
+                            dataRefObj.Add(null);
+                            ++refObjIndex;
+                        }
+
+                        //
+                        // now fix any string arguments and set the pointer on the data descriptor 
+                        //
+                        fixed (char* v0 = (string)dataRefObj[0], v1 = (string)dataRefObj[1], v2 = (string)dataRefObj[2], v3 = (string)dataRefObj[3],
+                                v4 = (string)dataRefObj[4], v5 = (string)dataRefObj[5], v6 = (string)dataRefObj[6], v7 = (string)dataRefObj[7])
+                        {
+                            userDataPtr = (EventData*)userData;
+                            if (dataRefObj[0] != null)
+                            {
+                                userDataPtr[refObjPosition[0]].Ptr = (ulong)v0;
+                            }
+                            if (dataRefObj[1] != null)
+                            {
+                                userDataPtr[refObjPosition[1]].Ptr = (ulong)v1;
+                            }
+                            if (dataRefObj[2] != null)
+                            {
+                                userDataPtr[refObjPosition[2]].Ptr = (ulong)v2;
+                            }
+                            if (dataRefObj[3] != null)
+                            {
+                                userDataPtr[refObjPosition[3]].Ptr = (ulong)v3;
+                            }
+                            if (dataRefObj[4] != null)
+                            {
+                                userDataPtr[refObjPosition[4]].Ptr = (ulong)v4;
+                            }
+                            if (dataRefObj[5] != null)
+                            {
+                                userDataPtr[refObjPosition[5]].Ptr = (ulong)v5;
+                            }
+                            if (dataRefObj[6] != null)
+                            {
+                                userDataPtr[refObjPosition[6]].Ptr = (ulong)v6;
+                            }
+                            if (dataRefObj[7] != null)
+                            {
+                                userDataPtr[refObjPosition[7]].Ptr = (ulong)v7;
+                            }
+
+                            status = UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, activityID, childActivityID, argCount, userData);
+                        }
+                    }
+                    else
+                    {
+                        // Slow path: use pinned handles
+                        userDataPtr = (EventData*)userData;
+
+                        GCHandle[] rgGCHandle = new GCHandle[refObjIndex];
+                        for (int i = 0; i < refObjIndex; ++i)
+                        {
+                            // below we still use "fixed" to avoid taking dependency on the offset of the first field
+                            // in the object (the way we would need to if we used GCHandle.AddrOfPinnedObject)
+                            rgGCHandle[i] = GCHandle.Alloc(dataRefObj[i], GCHandleType.Pinned);
+                            if (dataRefObj[i] is string)
+                            {
+                                fixed (char* p = (string)dataRefObj[i])
+                                    userDataPtr[refObjPosition[i]].Ptr = (ulong)p;
+                            }
+                            else
+                            {
+                                fixed (byte* p = (byte[])dataRefObj[i])
+                                    userDataPtr[refObjPosition[i]].Ptr = (ulong)p;
+                            }
+                        }
+
+                        status = UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, activityID, childActivityID, argCount, userData);
+
+                        for (int i = 0; i < refObjIndex; ++i)
+                        {
+                            rgGCHandle[i].Free();
+                        }
+                    }
+                }
+            }
+
+            if (status != 0)
+            {
+                SetLastError((int)status);
+                return false;
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// WriteEvent, method to be used by generated code on a derived class
+        /// </summary>
+        /// <param name="eventDescriptor">
+        /// Event Descriptor for this event. 
+        /// </param>
+        /// <param name="activityID">
+        /// A pointer to the activity ID to log 
+        /// </param>
+        /// <param name="childActivityID">
+        /// If this event is generating a child activity (WriteEventTransfer related activity) this is child activity
+        /// This can be null for events that do not generate a child activity.  
+        /// </param>
+        /// <param name="dataCount">
+        /// number of event descriptors 
+        /// </param>
+        /// <param name="data">
+        /// pointer  do the event data
+        /// </param>
+        // <SecurityKernel Critical="True" Ring="0">
+        // <CallsSuppressUnmanagedCode Name="UnsafeNativeMethods.ManifestEtw.EventWrite(System.Int64,EventDescriptor&,System.UInt32,System.Void*):System.UInt32" />
+        // </SecurityKernel>
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
+        internal unsafe protected bool WriteEvent(ref EventDescriptor eventDescriptor, Guid* activityID, Guid* childActivityID, int dataCount, IntPtr data)
+        {
+            if (childActivityID != null)
+            {
+                // activity transfers are supported only for events that specify the Send or Receive opcode
+                Debug.Assert((EventOpcode)eventDescriptor.Opcode == EventOpcode.Send ||
+                                (EventOpcode)eventDescriptor.Opcode == EventOpcode.Receive ||
+                                (EventOpcode)eventDescriptor.Opcode == EventOpcode.Start ||
+                                (EventOpcode)eventDescriptor.Opcode == EventOpcode.Stop);
+            }
+
+            int status = UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, activityID, childActivityID, dataCount, (EventData*)data);
+
+            if (status != 0)
+            {
+                SetLastError(status);
+                return false;
+            }
+            return true;
+        }
+
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
+        internal unsafe bool WriteEventRaw(
+            ref EventDescriptor eventDescriptor,
+            Guid* activityID,
+            Guid* relatedActivityID,
+            int dataCount,
+            IntPtr data)
+        {
+            int status;
+
+            status = UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper(
+                m_regHandle,
+                ref eventDescriptor,
+                activityID,
+                relatedActivityID,
+                dataCount,
+                (EventData*)data);
+
+            if (status != 0)
+            {
+                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(ref Guid providerId, UnsafeNativeMethods.ManifestEtw.EtwEnableCallback enableCallback)
+        {
+            m_providerId = providerId;
+            m_etwCallback = enableCallback;
+            return UnsafeNativeMethods.ManifestEtw.EventRegister(ref providerId, enableCallback, null, ref m_regHandle);
+        }
+
+        private uint EventUnregister(long registrationHandle)
+        {
+            return UnsafeNativeMethods.ManifestEtw.EventUnregister(registrationHandle);
+        }
+
+        static int[] nibblebits = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
+        private static int bitcount(uint n)
+        {
+            int count = 0;
+            for (; n != 0; n = n >> 4)
+                count += nibblebits[n & 0x0f];
+            return count;
+        }
+        private static int bitindex(uint n)
+        {
+            Debug.Assert(bitcount(n) == 1);
+            int idx = 0;
+            while ((n & (1 << idx)) == 0)
+                idx++;
+            return idx;
+        }
+    }
+}
+
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs
new file mode 100644 (file)
index 0000000..6a17265
--- /dev/null
@@ -0,0 +1,6929 @@
+// 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.
+
+// This program uses code hyperlinks available as part of the HyperAddin Visual Studio plug-in.
+// It is available from http://www.codeplex.com/hyperAddin 
+#if !PLATFORM_UNIX
+
+#define FEATURE_MANAGED_ETW
+
+#if !ES_BUILD_STANDALONE && !CORECLR && !ES_BUILD_PN
+#define FEATURE_ACTIVITYSAMPLING
+#endif // !ES_BUILD_STANDALONE
+
+#endif // !PLATFORM_UNIX
+
+#if ES_BUILD_STANDALONE
+#define FEATURE_MANAGED_ETW_CHANNELS
+// #define FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
+#endif
+
+/* DESIGN NOTES DESIGN NOTES DESIGN NOTES DESIGN NOTES */
+// DESIGN NOTES
+// Over the years EventSource has become more complex and so it is important to understand
+// the basic structure of the code to insure that it does not grow more complex.
+//
+// Basic Model
+//
+// PRINCIPLE: EventSource - ETW decoupling
+// 
+// Conceptually and EventSouce is something takes event logging data from the source methods 
+// To the EventListener that can subscribe them.  Note that CONCEPTUALLY EVENTSOURCES DON'T
+// KNOW ABOUT ETW!.   The MODEL of the system is that there is a special EventListern Which
+// we will call the EtwEventListener, that forwards commands from ETW to EventSources and
+// listeners to the EventSources and forwards on those events to ETW.   THus the model should
+// be that you DON'T NEED ETW.    
+//
+// Now in actual practice, EventSouce have rather intimate knowledge of ETW and send events
+// to it directly, but this can be VIEWED AS AN OPTIMIATION.  
+//
+// Basic Event Data Flow:
+// 
+// There are two ways for event Data to enter the system
+//     1) WriteEvent* and friends.  This is called the 'contract' based approach because 
+//        you write a method per event which forms a contract that is know at compile time.
+//        In this scheme each event is given an EVENTID (small integer). which is its identity
+//     2) Write<T> methods.   This is called the 'dynamic' approach because new events 
+//        can be created on the fly.  Event identity is determined by the event NAME, and these
+//        are not quite as efficient at runtime since you have at least a hash table lookup
+//        on every event write.  
+//
+// EventSource-EventListener transfer fully support both ways of writing events (either contract
+// based (WriteEvent*) or dynamic (Write<T>).   Both way fully support the same set of data
+// types.   It is suggested, however, that you use the contract based approach when the event scheme 
+// is known at compile time (that is whenever possible).  It is more efficient, but more importantly
+// it makes the contract very explicit, and centralizes all policy about logging.  These are good 
+// things.    The Write<T> API is really meant for more ad-hoc 
+//
+// Allowed Data. 
+// 
+// Note that EventSource-EventListeners have a conceptual serialization-deserialization that happens
+// during the transfer.   In particular object identity is not preserved, some objects are morphed, 
+// and not all data types are supported.   In particular you can pass
+// 
+// A Valid type to log to an EventSource include
+//   * Primitive data types
+//   * IEnumerable<T> of valid types T (this include arrays)  (* New for V4.6)
+//   * Explicitly Opted in class or struct with public property Getters over Valid types.  (* New for V4.6)
+// 
+// This set of types is roughly a generalization of JSON support (Basically primitives, bags, and arrays).   
+//
+// Explicitly allowed structs include (* New for V4.6)
+//   * Marked with the EventData attribute
+//   * implicitly defined (e.g the C# new {x = 3, y = 5} syntax)
+//   * KeyValuePair<K,V>  (thus dictionaries can be passed since they are an IEnumerable of KeyValuePair)
+//         
+// When classes are returned in an EventListener, what is returned is something that implements 
+// IDictionary<string, T>.  Thus when objects are passed to an EventSource they are transformed
+// into a key-value bag (the IDictionary<string, T>) for consumption in the listener.   These 
+// are obvious NOT the original objects.  
+// 
+// ETWserialization formats:
+// 
+// As mentioned conceptually EventSource's send data to EventListeners and there is a conceptual 
+// copy/morph of that data as described above.   In addition the .NET framework supports a conceptual
+// ETWListener that will send the data to then ETW stream.   If you use this feature, the data needs 
+// to be serialized in a way that ETW supports.  ETW supports the following serialization formats 
+// 
+//     1) Manifest Based serialization. 
+//     2) SelfDescribing serialization (TraceLogging style in the TraceLogging directory)
+//
+// A key factor is that the Write<T> method, which support on the fly definition of events, can't
+// support the manifest based serialization because the manifest needs the schema of all events 
+// to be known before any events are emitted.  This implies the following
+//
+// If you use Write<T> and the output goes to ETW it will use the SelfDescribing format.
+// If you use the EventSource(string) constructor for an eventSource (in which you don't
+// create a subclass), the default is also to use Self-Describing serialization.  In addition
+// you can use the EventSoruce(EventSourceSettings) constructor to also explicitly specify
+// Self-Describing serialization format.   These effect the WriteEvent* APIs going to ETW.  
+//
+// Note that none of this ETW serialization logic affects EventListeners.   Only the ETW listener.  
+// 
+// *************************************************************************************
+// *** INTERNALS: Event Propagation
+//
+//   Data enters the system either though
+//
+// 1) A user defined method in the user defined subclass of EventSource which calls 
+//     A) A typesafe type specific overload of WriteEvent(ID, ...)  e.g. WriteEvent(ID, string, string) 
+//           * which calls into the unsafe WriteEventCore(ID COUNT EventData*) WriteEventWithRelatedActivityIdCore()
+//     B) The typesafe overload WriteEvent(ID, object[])  which calls the private helper WriteEventVarargs(ID, Guid* object[])
+//     C) Directly into the unsafe WriteEventCore(ID, COUNT EventData*) or WriteEventWithRelatedActivityIdCore()
+//
+//     All event data eventually flows to one of 
+//        * WriteEventWithRelatedActivityIdCore(ID, Guid*, COUNT, EventData*) 
+//        * WriteEventVarargs(ID, Guid*, object[])
+//
+// 2) A call to one of the overloads of Write<T>.   All these overloads end up in 
+//        * WriteImpl<T>(EventName, Options, Data, Guid*, Guid*)
+// 
+// On output there are the following routines
+//    Writing to all listeners that are NOT ETW, we have the following routines
+//       * WriteToAllListeners(ID, Guid*, COUNT, EventData*) 
+//       * WriteToAllListeners(ID, Guid*, object[])
+//       * WriteToAllListeners(NAME, Guid*, EventPayload)
+//
+//       EventPayload is the internal type that implements the IDictionary<string, object> interface
+//       The EventListeners will pass back for serialized classes for nested object, but  
+//       WriteToAllListeners(NAME, Guid*, EventPayload) unpacks this uses the fields as if they
+//       were parameters to a method.  
+// 
+//       The first two are used for the WriteEvent* case, and the later is used for the Write<T> case.  
+// 
+//    Writing to ETW, Manifest Based 
+//          EventProvider.WriteEvent(EventDescriptor, Guid*, COUNT, EventData*)
+//          EventProvider.WriteEvent(EventDescriptor, Guid*, object[])
+//    Writing to ETW, Self-Describing format
+//          WriteMultiMerge(NAME, Options, Types, EventData*)
+//          WriteMultiMerge(NAME, Options, Types, object[])
+//          WriteImpl<T> has logic that knows how to serialize (like WriteMultiMerge) but also knows 
+//             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)
+//         EventProvider.WriteEventRaw   - sets last error
+//         EventSource.WriteEventRaw     - Does EventSource exception handling logic
+//            WriteMultiMerge
+//            WriteImpl<T>
+//         EventProvider.WriteEvent(EventDescriptor, Guid*, COUNT, EventData*)
+//         EventProvider.WriteEvent(EventDescriptor, Guid*, object[])
+// 
+// Serialization:  We have a bit of a hodge-podge of serializers right now.   Only the one for ETW knows
+// how to deal with nested classes or arrays.   I will call this serializer the 'TypeInfo' serializer
+// since it is the TraceLoggingTypeInfo structure that knows how to do this.   Effectively for a type you
+// can call one of these 
+//      WriteMetadata - transforms the type T into serialization meta data blob for that type
+//      WriteObjectData - transforms an object of T into serialization meta data blob for that type
+//      GetData - transforms an object of T into its deserialized form suitable for passing to EventListener. 
+// The first two are used to serialize something for ETW.   The second one is used to transform the object 
+// for use by the EventListener.    We also have a 'DecodeObject' method that will take a EventData* and
+// deserialize to pass to an EventListener, but it only works on primitive types (types supported in version V4.5). 
+// 
+// It is an important observation that while EventSource does support users directly calling with EventData* 
+// blobs, we ONLY support that for the primitive types (V4.5 level support).   Thus while there is a EventData*
+// path through the system it is only for some types.  The object[] path is the more general (but less efficient) path.  
+//
+// TODO There is cleanup needed There should be no divergence until WriteEventRaw.  
+// 
+// TODO: We should have a single choke point (right now we always have this parallel EventData* and object[] path.   This 
+// was historical (at one point we tried to pass object directly from EventSoruce to EventListener.  That was always 
+// fragile and a compatibility headache, but we have finally been forced into the idea that there is always a transformation.
+// This allows us to use the EventData* form to be the canonical data format in the low level APIs.  This also gives us the
+// opportunity to expose this format to EventListeners in the future.   
+// 
+using System;
+using System.Runtime.CompilerServices;
+#if FEATURE_ACTIVITYSAMPLING
+using System.Collections.Concurrent;
+#endif
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Reflection;
+using System.Resources;
+using System.Security;
+#if !CORECLR && !ES_BUILD_PN
+using System.Security.Permissions;
+#endif // !CORECLR && !ES_BUILD_PN
+
+using System.Text;
+using System.Threading;
+using Microsoft.Win32;
+
+#if ES_BUILD_STANDALONE
+using EventDescriptor = Microsoft.Diagnostics.Tracing.EventDescriptor;
+#else
+using System.Threading.Tasks;
+#endif
+
+using Microsoft.Reflection;
+
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
+#if ES_BUILD_PN
+using Internal.Runtime.Augments;
+#endif
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// This class is meant to be inherited by a user-defined event source in order to define a managed
+    /// ETW provider.   Please See DESIGN NOTES above for the internal architecture.  
+    /// The minimal definition of an EventSource simply specifies a number of ETW event methods that
+    /// call one of the EventSource.WriteEvent overloads, <see cref="EventSource.WriteEventCore"/>, 
+    /// or <see cref="EventSource.WriteEventWithRelatedActivityIdCore"/> to log them. This functionality 
+    /// is sufficient for many users.
+    /// <para>
+    /// To achieve more control over the ETW provider manifest exposed by the event source type, the 
+    /// [<see cref="EventAttribute"/>] attributes can be specified for the ETW event methods.
+    /// </para><para>
+    /// For very advanced EventSources, it is possible to intercept the commands being given to the
+    /// eventSource and change what filtering is done (see EventListener.EnableEvents and 
+    /// <see cref="EventListener.DisableEvents"/>) or cause actions to be performed by the eventSource, 
+    /// e.g. dumping a data structure (see EventSource.SendCommand and
+    /// <see cref="EventSource.OnEventCommand"/>).
+    /// </para><para>
+    /// The eventSources can be turned on with Windows ETW controllers (e.g. logman), immediately. 
+    /// It is also possible to control and intercept the data dispatcher programmatically.  See 
+    /// <see cref="EventListener"/> for more.
+    /// </para>
+    /// </summary>
+    /// <remarks>
+    /// This is a minimal definition for a custom event source:
+    /// <code>
+    /// [EventSource(Name="Samples-Demos-Minimal")]
+    /// sealed class MinimalEventSource : EventSource
+    /// {
+    ///     public static MinimalEventSource Log = new MinimalEventSource();
+    ///     public void Load(long ImageBase, string Name) { WriteEvent(1, ImageBase, Name); }
+    ///     public void Unload(long ImageBase) { WriteEvent(2, ImageBase); }
+    ///     private MinimalEventSource() {}
+    /// }
+    /// </code>
+    /// </remarks>
+    public partial class EventSource : IDisposable
+    {
+
+#if FEATURE_EVENTSOURCE_XPLAT
+        private static readonly EventListener persistent_Xplat_Listener = XplatEventLogger.InitializePersistentListener();
+#endif //FEATURE_EVENTSOURCE_XPLAT
+
+        /// <summary>
+        /// The human-friendly name of the eventSource.  It defaults to the simple name of the class
+        /// </summary>
+        public string Name { get { return m_name; } }
+        /// <summary>
+        /// Every eventSource is assigned a GUID to uniquely identify it to the system. 
+        /// </summary>
+        public Guid Guid { get { return m_guid; } }
+
+        /// <summary>
+        /// Returns true if the eventSource has been enabled at all. This is the prefered test
+        /// to be performed before a relatively expensive EventSource operation.
+        /// </summary>
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        public bool IsEnabled()
+        {
+            return m_eventSourceEnabled;
+        }
+
+        /// <summary>
+        /// Returns true if events with greater than or equal 'level' and have one of 'keywords' set are enabled. 
+        /// 
+        /// Note that the result of this function is only an approximation on whether a particular
+        /// event is active or not. It is only meant to be used as way of avoiding expensive
+        /// computation for logging when logging is not on, therefore it sometimes returns false
+        /// positives (but is always accurate when returning false).  EventSources are free to 
+        /// have additional filtering.    
+        /// </summary>
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        public bool IsEnabled(EventLevel level, EventKeywords keywords)
+        {
+            return IsEnabled(level, keywords, EventChannel.None);
+        }
+
+        /// <summary>
+        /// Returns true if events with greater than or equal 'level' and have one of 'keywords' set are enabled, or
+        /// if 'keywords' specifies a channel bit for a channel that is enabled.
+        /// 
+        /// Note that the result of this function only an approximation on whether a particular
+        /// event is active or not. It is only meant to be used as way of avoiding expensive
+        /// computation for logging when logging is not on, therefore it sometimes returns false
+        /// positives (but is always accurate when returning false).  EventSources are free to 
+        /// have additional filtering.    
+        /// </summary>
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        public bool IsEnabled(EventLevel level, EventKeywords keywords, EventChannel channel)
+        {
+            if (!m_eventSourceEnabled)
+                return false;
+
+            if (!IsEnabledCommon(m_eventSourceEnabled, m_level, m_matchAnyKeyword, level, keywords, channel))
+                return false;
+
+#if !FEATURE_ACTIVITYSAMPLING
+
+            return true;
+
+#else // FEATURE_ACTIVITYSAMPLING
+
+            return true;
+
+#if OPTIMIZE_IS_ENABLED
+            //================================================================================
+            // 2013/03/06 - The code below is a possible optimization for IsEnabled(level, kwd)
+            //    in case activity tracing/sampling is enabled. The added complexity of this
+            //    code however weighs against having it "on" until we know it's really needed.
+            //    For now we'll have this #ifdef-ed out in case we see evidence this is needed.
+            //================================================================================            
+
+            // At this point we believe the event is enabled, however we now need to check
+            // if we filter because of activity 
+
+            // Optimization, all activity filters also register a delegate here, so if there 
+            // is no delegate, we know there are no activity filters, which means that there
+            // is no additional filtering, which means that we can return true immediately.  
+            if (s_activityDying == null)
+                return true;
+
+            // if there's at least one legacy ETW listener we can't filter this
+            if (m_legacySessions != null && m_legacySessions.Count > 0)
+                return true;
+
+            // if any event ID that triggers a new activity, or "transfers" activities
+            // is covered by 'keywords' we can't filter this
+            if (unchecked(((long)keywords & m_keywordTriggers)) != 0)
+                return true;
+
+            // See if all listeners have activity filters that would block the event.
+            for (int perEventSourceSessionId = 0; perEventSourceSessionId < SessionMask.MAX; ++perEventSourceSessionId)
+            {
+                EtwSession etwSession = m_etwSessionIdMap[perEventSourceSessionId];
+                if (etwSession == null)
+                    continue;
+
+                ActivityFilter activityFilter = etwSession.m_activityFilter;
+                if (activityFilter == null || 
+                    ActivityFilter.GetFilter(activityFilter, this) == null)
+                {
+                    // No activity filter for ETW, if event is active for ETW, we can't filter.  
+                    for (int i = 0; i < m_eventData.Length; i++)
+                        if (m_eventData[i].EnabledForETW)
+                            return true;
+                }
+                else if (ActivityFilter.IsCurrentActivityActive(activityFilter))
+                    return true;
+            }
+
+            // for regular event listeners
+            var curDispatcher = m_Dispatchers;
+            while (curDispatcher != null)
+            {
+                ActivityFilter activityFilter = curDispatcher.m_Listener.m_activityFilter;
+                if (activityFilter == null)
+                {
+                    // See if any event is enabled.   
+                    for (int i = 0; i < curDispatcher.m_EventEnabled.Length; i++)
+                        if (curDispatcher.m_EventEnabled[i])
+                            return true;
+                }
+                else if (ActivityFilter.IsCurrentActivityActive(activityFilter))
+                    return true;
+                curDispatcher = curDispatcher.m_Next;
+            }
+
+            // Every listener has an activity filter that is blocking writing the event, 
+            // thus the event is not enabled.  
+            return false;
+#endif // OPTIMIZE_IS_ENABLED
+
+#endif // FEATURE_ACTIVITYSAMPLING
+        }
+
+        /// <summary>
+        /// Returns the settings for the event source instance
+        /// </summary>
+        public EventSourceSettings Settings
+        {
+            get { return m_config; }
+        }
+
+        // Manifest support 
+        /// <summary>
+        /// Returns the GUID that uniquely identifies the eventSource defined by 'eventSourceType'.  
+        /// This API allows you to compute this without actually creating an instance of the EventSource.   
+        /// It only needs to reflect over the type.  
+        /// </summary>
+        public static Guid GetGuid(Type eventSourceType)
+        {
+            if (eventSourceType == null)
+                throw new ArgumentNullException(nameof(eventSourceType));
+            Contract.EndContractBlock();
+
+            EventSourceAttribute attrib = (EventSourceAttribute)GetCustomAttributeHelper(eventSourceType, typeof(EventSourceAttribute));
+            string name = eventSourceType.Name;
+            if (attrib != null)
+            {
+                if (attrib.Guid != null)
+                {
+                    Guid g = Guid.Empty;
+#if !ES_BUILD_AGAINST_DOTNET_V35
+                    if (Guid.TryParse(attrib.Guid, out g))
+                        return g;
+#else
+                    try { return new Guid(attrib.Guid); }
+                    catch (Exception) { }
+#endif
+                }
+
+                if (attrib.Name != null)
+                    name = attrib.Name;
+            }
+
+            if (name == null)
+            {
+                throw new ArgumentException(Resources.GetResourceString("Argument_InvalidTypeName"), nameof(eventSourceType));
+            }
+            return GenerateGuidFromName(name.ToUpperInvariant());       // Make it case insensitive.  
+        }
+        /// <summary>
+        /// Returns the official ETW Provider name for the eventSource defined by 'eventSourceType'.  
+        /// This API allows you to compute this without actually creating an instance of the EventSource.   
+        /// It only needs to reflect over the type.  
+        /// </summary>
+        public static string GetName(Type eventSourceType)
+        {
+            return GetName(eventSourceType, EventManifestOptions.None);
+        }
+
+        /// <summary>
+        /// Returns a string of the XML manifest associated with the eventSourceType. The scheme for this XML is
+        /// documented at in EventManifest Schema http://msdn.microsoft.com/en-us/library/aa384043(VS.85).aspx.
+        /// This is the preferred way of generating a manifest to be embedded in the ETW stream as it is fast and
+        /// the fact that it only includes localized entries for the current UI culture is an acceptable tradeoff.
+        /// </summary>
+        /// <param name="eventSourceType">The type of the event source class for which the manifest is generated</param>
+        /// <param name="assemblyPathToIncludeInManifest">The manifest XML fragment contains the string name of the DLL name in
+        /// which it is embedded.  This parameter specifies what name will be used</param>
+        /// <returns>The XML data string</returns>
+        public static string GenerateManifest(Type eventSourceType, string assemblyPathToIncludeInManifest)
+        {
+            return GenerateManifest(eventSourceType, assemblyPathToIncludeInManifest, EventManifestOptions.None);
+        }
+        /// <summary>
+        /// Returns a string of the XML manifest associated with the eventSourceType. The scheme for this XML is
+        /// documented at in EventManifest Schema http://msdn.microsoft.com/en-us/library/aa384043(VS.85).aspx.
+        /// Pass EventManifestOptions.AllCultures when generating a manifest to be registered on the machine. This
+        /// ensures that the entries in the event log will be "optimally" localized.
+        /// </summary>
+        /// <param name="eventSourceType">The type of the event source class for which the manifest is generated</param>
+        /// <param name="assemblyPathToIncludeInManifest">The manifest XML fragment contains the string name of the DLL name in
+        /// which it is embedded.  This parameter specifies what name will be used</param>
+        /// <param name="flags">The flags to customize manifest generation. If flags has bit OnlyIfNeededForRegistration specified
+        /// this returns null when the eventSourceType does not require explicit registration</param>
+        /// <returns>The XML data string or null</returns>
+        public static string GenerateManifest(Type eventSourceType, string assemblyPathToIncludeInManifest, EventManifestOptions flags)
+        {
+            if (eventSourceType == null)
+                throw new ArgumentNullException(nameof(eventSourceType));
+            Contract.EndContractBlock();
+
+            byte[] manifestBytes = EventSource.CreateManifestAndDescriptors(eventSourceType, assemblyPathToIncludeInManifest, null, flags);
+            return (manifestBytes == null) ? null : Encoding.UTF8.GetString(manifestBytes, 0, manifestBytes.Length);
+        }
+
+        // EventListener support
+        /// <summary>
+        /// returns a list (IEnumerable) of all sources in the appdomain).  EventListeners typically need this.  
+        /// </summary>
+        /// <returns></returns>
+        public static IEnumerable<EventSource> GetSources()
+        {
+            var ret = new List<EventSource>();
+            lock (EventListener.EventListenersLock)
+            {
+                foreach (WeakReference eventSourceRef in EventListener.s_EventSources)
+                {
+                    EventSource eventSource = eventSourceRef.Target as EventSource;
+                    if (eventSource != null && !eventSource.IsDisposed)
+                        ret.Add(eventSource);
+                }
+            }
+            return ret;
+        }
+
+        /// <summary>
+        /// Send a command to a particular EventSource identified by 'eventSource'.
+        /// Calling this routine simply forwards the command to the EventSource.OnEventCommand
+        /// callback.  What the EventSource does with the command and its arguments are from 
+        /// that point EventSource-specific.  
+        /// </summary>
+        /// <param name="eventSource">The instance of EventSource to send the command to</param>
+        /// <param name="command">A positive user-defined EventCommand, or EventCommand.SendManifest</param>
+        /// <param name="commandArguments">A set of (name-argument, value-argument) pairs associated with the command</param>
+        public static void SendCommand(EventSource eventSource, EventCommand command, IDictionary<string, string> commandArguments)
+        {
+            if (eventSource == null)
+                throw new ArgumentNullException(nameof(eventSource));
+
+            // User-defined EventCommands should not conflict with the reserved commands.
+            if ((int)command <= (int)EventCommand.Update && (int)command != (int)EventCommand.SendManifest)
+            {
+                throw new ArgumentException(Resources.GetResourceString("EventSource_InvalidCommand"), nameof(command));
+            }
+
+            eventSource.SendCommand(null, 0, 0, command, true, EventLevel.LogAlways, EventKeywords.None, commandArguments);
+        }
+
+#if !ES_BUILD_STANDALONE
+        /// <summary>
+        /// This property allows EventSource code to appropriately handle as "different" 
+        /// activities started on different threads that have not had an activity created on them.
+        /// </summary>
+        internal static Guid InternalCurrentThreadActivityId
+        {
+            get
+            {
+                Guid retval = CurrentThreadActivityId;
+                if (retval == Guid.Empty)
+                {
+                    retval = FallbackActivityId;
+                }
+                return retval;
+            }
+        }
+
+        internal static Guid FallbackActivityId
+        {
+            get
+            {
+#pragma warning disable 612, 618
+                int threadID = AppDomain.GetCurrentThreadId();
+
+                // Managed thread IDs are more aggressively re-used than native thread IDs,
+                // so we'll use the latter...
+                return new Guid(unchecked((uint)threadID),
+                                unchecked((ushort)s_currentPid), unchecked((ushort)(s_currentPid >> 16)),
+                                0x94, 0x1b, 0x87, 0xd5, 0xa6, 0x5c, 0x36, 0x64);
+#pragma warning restore 612, 618
+            }
+        }
+#endif // !ES_BUILD_STANDALONE
+
+        // Error APIs.  (We don't throw by default, but you can probe for status)
+        /// <summary>
+        /// Because
+        /// 
+        ///     1) Logging is often optional and thus should not generate fatal errors (exceptions)
+        ///     2) EventSources are often initialized in class constructors (which propagate exceptions poorly)
+        ///     
+        /// The event source constructor does not throw exceptions.  Instead we remember any exception that 
+        /// was generated (it is also logged to Trace.WriteLine).
+        /// </summary>
+        public Exception ConstructionException { get { return m_constructionException; } }
+
+        /// <summary>
+        /// EventSources can have arbitrary string key-value pairs associated with them called Traits.  
+        /// These traits are not interpreted by the EventSource but may be interpreted by EventListeners
+        /// (e.g. like the built in ETW listener).   These traits are specififed at EventSource 
+        /// construction time and can be retrieved by using this GetTrait API.  
+        /// </summary>
+        /// <param name="key">The key to look up in the set of key-value pairs passed to the EventSource constructor</param>
+        /// <returns>The value string associated iwth key.  Will return null if there is no such key.</returns>
+        public string GetTrait(string key)
+        {
+            if (m_traits != null)
+            {
+                for (int i = 0; i < m_traits.Length - 1; i += 2)
+                {
+                    if (m_traits[i] == key)
+                        return m_traits[i + 1];
+                }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Displays the name and GUID for the eventSource for debugging purposes.  
+        /// </summary>
+        public override string ToString()
+        {
+            return Resources.GetResourceString("EventSource_ToString", Name, Guid);
+        }
+
+        /// <summary>
+        /// Fires when a Command (e.g. Enable) comes from a an EventListener.  
+        /// </summary>
+        public event EventHandler<EventCommandEventArgs> EventCommandExecuted
+        {
+            add
+            {
+                m_eventCommandExecuted += value;
+
+                // If we have an EventHandler<EventCommandEventArgs> attached to the EventSource before the first command arrives
+                // It should get a chance to handle the deferred commands.
+                EventCommandEventArgs deferredCommands = m_deferredCommands;
+                while (deferredCommands != null)
+                {
+                    value(this, deferredCommands);
+                    deferredCommands = deferredCommands.nextCommand;
+                }
+            }
+            remove
+            {
+                m_eventCommandExecuted -= value;
+            }
+        }
+
+        #region protected
+        /// <summary>
+        /// This is the constructor that most users will use to create their eventSource.   It takes 
+        /// no parameters.  The ETW provider name and GUID of the EventSource are determined by the EventSource 
+        /// custom attribute (so you can determine these things declaratively).   If the GUID for the eventSource
+        /// is not specified in the EventSourceAttribute (recommended), it is Generated by hashing the name.
+        /// If the ETW provider name of the EventSource is not given, the name of the EventSource class is used as
+        /// the ETW provider name.
+        /// </summary>
+        protected EventSource()
+            : this(EventSourceSettings.EtwManifestEventFormat)
+        {
+        }
+
+        /// <summary>
+        /// By default calling the 'WriteEvent' methods do NOT throw on errors (they silently discard the event).  
+        /// This is because in most cases users assume logging is not 'precious' and do NOT wish to have logging failures
+        /// crash the program. However for those applications where logging is 'precious' and if it fails the caller
+        /// wishes to react, setting 'throwOnEventWriteErrors' will cause an exception to be thrown if WriteEvent
+        /// fails. Note the fact that EventWrite succeeds does not necessarily mean that the event reached its destination
+        /// only that operation of writing it did not fail. These EventSources will not generate self-describing ETW events.
+        /// 
+        /// For compatibility only use the EventSourceSettings.ThrowOnEventWriteErrors flag instead.  
+        /// </summary>
+        // [Obsolete("Use the EventSource(EventSourceSettings) overload")]
+        protected EventSource(bool throwOnEventWriteErrors)
+            : this(EventSourceSettings.EtwManifestEventFormat | (throwOnEventWriteErrors ? EventSourceSettings.ThrowOnEventWriteErrors : 0))
+        { }
+
+        /// <summary>
+        /// Construct an EventSource with additional non-default settings (see EventSourceSettings for more)  
+        /// </summary>
+        protected EventSource(EventSourceSettings settings) : this(settings, null) { }
+
+        /// <summary>
+        /// Construct an EventSource with additional non-default settings.  
+        /// 
+        /// Also specify a list of key-value pairs called traits (you must pass an even number of strings).   
+        /// The first string is the key and the second is the value.   These are not interpreted by EventSource
+        /// itself but may be interprated the listeners.  Can be fetched with GetTrait(string).   
+        /// </summary>
+        /// <param name="settings">See EventSourceSettings for more.</param>
+        /// <param name="traits">A collection of key-value strings (must be an even number).</param>
+        protected EventSource(EventSourceSettings settings, params string[] traits)
+        {
+            m_config = ValidateSettings(settings);
+
+            Guid eventSourceGuid;
+            string eventSourceName;
+
+            EventMetadata[] eventDescriptors;
+            byte[] manifest;
+            GetMetadata(out eventSourceGuid, out eventSourceName, out eventDescriptors, out manifest);
+
+            if (eventSourceGuid.Equals(Guid.Empty) || eventSourceName == null)
+            {
+                var myType = this.GetType();
+                eventSourceGuid = GetGuid(myType);
+                eventSourceName = GetName(myType);
+            }
+
+            Initialize(eventSourceGuid, eventSourceName, traits);
+        }
+
+        internal virtual void GetMetadata(out Guid eventSourceGuid, out string eventSourceName, out EventMetadata[] eventData, out byte[] manifestBytes)
+        {
+            //
+            // In ProjectN subclasses need to override this method, and return the data from their EventSourceAttribute and EventAttribute annotations.
+            // On other architectures it is a no-op.
+            //
+            // eventDescriptors needs to contain one EventDescriptor for each event; the event's ID should be the same as its index in this array.
+            // manifestBytes is a UTF-8 encoding of the ETW manifest for the type.
+            //
+            // This will be implemented by an IL rewriter, so we can't make this method abstract or the initial build of the subclass would fail.
+            //
+            eventSourceGuid = Guid.Empty;
+            eventSourceName = null;
+            eventData = null;
+            manifestBytes = null;
+
+            return;
+        }
+
+        /// <summary>
+        /// This method is called when the eventSource is updated by the controller.  
+        /// </summary>
+        protected virtual void OnEventCommand(EventCommandEventArgs command) { }
+
+#pragma warning disable 1591
+        // optimized for common signatures (no args)
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId)
+        {
+            WriteEventCore(eventId, 0, null);
+        }
+
+        // optimized for common signatures (ints)
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, int arg1)
+        {
+            if (m_eventSourceEnabled)
+            {
+                EventSource.EventData* descrs = stackalloc EventSource.EventData[1];
+                descrs[0].DataPointer = (IntPtr)(&arg1);
+                descrs[0].Size = 4;
+                WriteEventCore(eventId, 1, descrs);
+            }
+        }
+
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, int arg1, int arg2)
+        {
+            if (m_eventSourceEnabled)
+            {
+                EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
+                descrs[0].DataPointer = (IntPtr)(&arg1);
+                descrs[0].Size = 4;
+                descrs[1].DataPointer = (IntPtr)(&arg2);
+                descrs[1].Size = 4;
+                WriteEventCore(eventId, 2, descrs);
+            }
+        }
+
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, int arg1, int arg2, int arg3)
+        {
+            if (m_eventSourceEnabled)
+            {
+                EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
+                descrs[0].DataPointer = (IntPtr)(&arg1);
+                descrs[0].Size = 4;
+                descrs[1].DataPointer = (IntPtr)(&arg2);
+                descrs[1].Size = 4;
+                descrs[2].DataPointer = (IntPtr)(&arg3);
+                descrs[2].Size = 4;
+                WriteEventCore(eventId, 3, descrs);
+            }
+        }
+
+        // optimized for common signatures (longs)
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, long arg1)
+        {
+            if (m_eventSourceEnabled)
+            {
+                EventSource.EventData* descrs = stackalloc EventSource.EventData[1];
+                descrs[0].DataPointer = (IntPtr)(&arg1);
+                descrs[0].Size = 8;
+                WriteEventCore(eventId, 1, descrs);
+            }
+        }
+
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, long arg1, long arg2)
+        {
+            if (m_eventSourceEnabled)
+            {
+                EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
+                descrs[0].DataPointer = (IntPtr)(&arg1);
+                descrs[0].Size = 8;
+                descrs[1].DataPointer = (IntPtr)(&arg2);
+                descrs[1].Size = 8;
+                WriteEventCore(eventId, 2, descrs);
+            }
+        }
+
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, long arg1, long arg2, long arg3)
+        {
+            if (m_eventSourceEnabled)
+            {
+                EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
+                descrs[0].DataPointer = (IntPtr)(&arg1);
+                descrs[0].Size = 8;
+                descrs[1].DataPointer = (IntPtr)(&arg2);
+                descrs[1].Size = 8;
+                descrs[2].DataPointer = (IntPtr)(&arg3);
+                descrs[2].Size = 8;
+                WriteEventCore(eventId, 3, descrs);
+            }
+        }
+
+        // optimized for common signatures (strings)
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, string arg1)
+        {
+            if (m_eventSourceEnabled)
+            {
+                if (arg1 == null) arg1 = "";
+                fixed (char* string1Bytes = arg1)
+                {
+                    EventSource.EventData* descrs = stackalloc EventSource.EventData[1];
+                    descrs[0].DataPointer = (IntPtr)string1Bytes;
+                    descrs[0].Size = ((arg1.Length + 1) * 2);
+                    WriteEventCore(eventId, 1, descrs);
+                }
+            }
+        }
+
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, string arg1, string arg2)
+        {
+            if (m_eventSourceEnabled)
+            {
+                if (arg1 == null) arg1 = "";
+                if (arg2 == null) arg2 = "";
+                fixed (char* string1Bytes = arg1)
+                fixed (char* string2Bytes = arg2)
+                {
+                    EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
+                    descrs[0].DataPointer = (IntPtr)string1Bytes;
+                    descrs[0].Size = ((arg1.Length + 1) * 2);
+                    descrs[1].DataPointer = (IntPtr)string2Bytes;
+                    descrs[1].Size = ((arg2.Length + 1) * 2);
+                    WriteEventCore(eventId, 2, descrs);
+                }
+            }
+        }
+
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, string arg1, string arg2, string arg3)
+        {
+            if (m_eventSourceEnabled)
+            {
+                if (arg1 == null) arg1 = "";
+                if (arg2 == null) arg2 = "";
+                if (arg3 == null) arg3 = "";
+                fixed (char* string1Bytes = arg1)
+                fixed (char* string2Bytes = arg2)
+                fixed (char* string3Bytes = arg3)
+                {
+                    EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
+                    descrs[0].DataPointer = (IntPtr)string1Bytes;
+                    descrs[0].Size = ((arg1.Length + 1) * 2);
+                    descrs[1].DataPointer = (IntPtr)string2Bytes;
+                    descrs[1].Size = ((arg2.Length + 1) * 2);
+                    descrs[2].DataPointer = (IntPtr)string3Bytes;
+                    descrs[2].Size = ((arg3.Length + 1) * 2);
+                    WriteEventCore(eventId, 3, descrs);
+                }
+            }
+        }
+
+        // optimized for common signatures (string and ints)
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, string arg1, int arg2)
+        {
+            if (m_eventSourceEnabled)
+            {
+                if (arg1 == null) arg1 = "";
+                fixed (char* string1Bytes = arg1)
+                {
+                    EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
+                    descrs[0].DataPointer = (IntPtr)string1Bytes;
+                    descrs[0].Size = ((arg1.Length + 1) * 2);
+                    descrs[1].DataPointer = (IntPtr)(&arg2);
+                    descrs[1].Size = 4;
+                    WriteEventCore(eventId, 2, descrs);
+                }
+            }
+        }
+
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, string arg1, int arg2, int arg3)
+        {
+            if (m_eventSourceEnabled)
+            {
+                if (arg1 == null) arg1 = "";
+                fixed (char* string1Bytes = arg1)
+                {
+                    EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
+                    descrs[0].DataPointer = (IntPtr)string1Bytes;
+                    descrs[0].Size = ((arg1.Length + 1) * 2);
+                    descrs[1].DataPointer = (IntPtr)(&arg2);
+                    descrs[1].Size = 4;
+                    descrs[2].DataPointer = (IntPtr)(&arg3);
+                    descrs[2].Size = 4;
+                    WriteEventCore(eventId, 3, descrs);
+                }
+            }
+        }
+
+        // optimized for common signatures (string and longs)
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, string arg1, long arg2)
+        {
+            if (m_eventSourceEnabled)
+            {
+                if (arg1 == null) arg1 = "";
+                fixed (char* string1Bytes = arg1)
+                {
+                    EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
+                    descrs[0].DataPointer = (IntPtr)string1Bytes;
+                    descrs[0].Size = ((arg1.Length + 1) * 2);
+                    descrs[1].DataPointer = (IntPtr)(&arg2);
+                    descrs[1].Size = 8;
+                    WriteEventCore(eventId, 2, descrs);
+                }
+            }
+        }
+
+        // optimized for common signatures (long and string)
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, long arg1, string arg2)
+        {
+            if (m_eventSourceEnabled)
+            {
+                if (arg2 == null) arg2 = "";
+                fixed (char* string2Bytes = arg2)
+                {
+                    EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
+                    descrs[0].DataPointer = (IntPtr)(&arg1);
+                    descrs[0].Size = 8;
+                    descrs[1].DataPointer = (IntPtr)string2Bytes;
+                    descrs[1].Size = ((arg2.Length + 1) * 2);
+                    WriteEventCore(eventId, 2, descrs);
+                }
+            }
+        }
+
+        // optimized for common signatures (int and string)
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, int arg1, string arg2)
+        {
+            if (m_eventSourceEnabled)
+            {
+                if (arg2 == null) arg2 = "";
+                fixed (char* string2Bytes = arg2)
+                {
+                    EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
+                    descrs[0].DataPointer = (IntPtr)(&arg1);
+                    descrs[0].Size = 4;
+                    descrs[1].DataPointer = (IntPtr)string2Bytes;
+                    descrs[1].Size = ((arg2.Length + 1) * 2);
+                    WriteEventCore(eventId, 2, descrs);
+                }
+            }
+        }
+
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, byte[] arg1)
+        {
+            if (m_eventSourceEnabled)
+            {
+                EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
+                if (arg1 == null || arg1.Length == 0)
+                {
+                    int blobSize = 0;
+                    descrs[0].DataPointer = (IntPtr)(&blobSize);
+                    descrs[0].Size = 4;
+                    descrs[1].DataPointer = (IntPtr)(&blobSize); // valid address instead of empty content 
+                    descrs[1].Size = 0;
+                    WriteEventCore(eventId, 2, descrs);
+                }
+                else
+                {
+                    int blobSize = arg1.Length;
+                    fixed (byte* blob = &arg1[0])
+                    {
+                        descrs[0].DataPointer = (IntPtr)(&blobSize);
+                        descrs[0].Size = 4;
+                        descrs[1].DataPointer = (IntPtr)blob;
+                        descrs[1].Size = blobSize;
+                        WriteEventCore(eventId, 2, descrs);
+                    }
+                }
+            }
+        }
+
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, long arg1, byte[] arg2)
+        {
+            if (m_eventSourceEnabled)
+            {
+                EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
+                descrs[0].DataPointer = (IntPtr)(&arg1);
+                descrs[0].Size = 8;
+                if (arg2 == null || arg2.Length == 0)
+                {
+                    int blobSize = 0;
+                    descrs[1].DataPointer = (IntPtr)(&blobSize);
+                    descrs[1].Size = 4;
+                    descrs[2].DataPointer = (IntPtr)(&blobSize); // valid address instead of empty contents 
+                    descrs[2].Size = 0;
+                    WriteEventCore(eventId, 3, descrs);
+                }
+                else
+                {
+                    int blobSize = arg2.Length;
+                    fixed (byte* blob = &arg2[0])
+                    {
+                        descrs[1].DataPointer = (IntPtr)(&blobSize);
+                        descrs[1].Size = 4;
+                        descrs[2].DataPointer = (IntPtr)blob;
+                        descrs[2].Size = blobSize;
+                        WriteEventCore(eventId, 3, descrs);
+                    }
+                }
+            }
+        }
+
+#pragma warning restore 1591
+
+        /// <summary>
+        /// Used to construct the data structure to be passed to the native ETW APIs - EventWrite and EventWriteTransfer.
+        /// </summary>
+        protected internal struct EventData
+        {
+            /// <summary>
+            /// Address where the one argument lives (if this points to managed memory you must ensure the
+            /// managed object is pinned.
+            /// </summary>
+            public IntPtr DataPointer { get { return (IntPtr)m_Ptr; } set { m_Ptr = unchecked((long)value); } }
+            /// <summary>
+            /// Size of the argument referenced by DataPointer
+            /// </summary>
+            public int Size { get { return m_Size; } set { m_Size = value; } }
+
+            #region private
+            /// <summary>
+            /// Initializes the members of this EventData object to point at a previously-pinned
+            /// tracelogging-compatible metadata blob.
+            /// </summary>
+            /// <param name="pointer">Pinned tracelogging-compatible metadata blob.</param>
+            /// <param name="size">The size of the metadata blob.</param>
+            /// <param name="reserved">Value for reserved: 2 for per-provider metadata, 1 for per-event metadata</param>
+            internal unsafe void SetMetadata(byte* pointer, int size, int reserved)
+            {
+                this.m_Ptr = (long)(ulong)(UIntPtr)pointer;
+                this.m_Size = size;
+                this.m_Reserved = reserved; // Mark this descriptor as containing tracelogging-compatible metadata.
+            }
+
+            //Important, we pass this structure directly to the Win32 EventWrite API, so this structure must be layed out exactly
+            // the way EventWrite wants it.  
+            internal long m_Ptr;
+            internal int m_Size;
+#pragma warning disable 0649
+            internal int m_Reserved;       // Used to pad the size to match the Win32 API
+#pragma warning restore 0649
+            #endregion
+        }
+
+        /// <summary>
+        /// This routine allows you to create efficient WriteEvent helpers, however the code that you use to
+        /// do this, while straightforward, is unsafe.
+        /// </summary>
+        /// <remarks>
+        /// <code>
+        ///    protected unsafe void WriteEvent(int eventId, string arg1, long arg2)
+        ///    {
+        ///        if (IsEnabled())
+        ///        {
+        ///            if (arg2 == null) arg2 = "";
+        ///            fixed (char* string2Bytes = arg2)
+        ///            {
+        ///                EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
+        ///                descrs[0].DataPointer = (IntPtr)(&amp;arg1);
+        ///                descrs[0].Size = 8;
+        ///                descrs[1].DataPointer = (IntPtr)string2Bytes;
+        ///                descrs[1].Size = ((arg2.Length + 1) * 2);
+        ///                WriteEventCore(eventId, 2, descrs);
+        ///            }
+        ///        }
+        ///    }
+        /// </code>
+        /// </remarks>
+        [CLSCompliant(false)]
+        protected unsafe void WriteEventCore(int eventId, int eventDataCount, EventSource.EventData* data)
+        {
+            WriteEventWithRelatedActivityIdCore(eventId, null, eventDataCount, data);
+        }
+
+        /// <summary>
+        /// This routine allows you to create efficient WriteEventWithRelatedActivityId helpers, however the code 
+        /// that you use to do this, while straightforward, is unsafe. The only difference from
+        /// <see cref="WriteEventCore"/> is that you pass the relatedActivityId from caller through to this API
+        /// </summary>
+        /// <remarks>
+        /// <code>
+        ///    protected unsafe void WriteEventWithRelatedActivityId(int eventId, Guid relatedActivityId, string arg1, long arg2)
+        ///    {
+        ///        if (IsEnabled())
+        ///        {
+        ///            if (arg2 == null) arg2 = "";
+        ///            fixed (char* string2Bytes = arg2)
+        ///            {
+        ///                EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
+        ///                descrs[0].DataPointer = (IntPtr)(&amp;arg1);
+        ///                descrs[0].Size = 8;
+        ///                descrs[1].DataPointer = (IntPtr)string2Bytes;
+        ///                descrs[1].Size = ((arg2.Length + 1) * 2);
+        ///                WriteEventWithRelatedActivityIdCore(eventId, relatedActivityId, 2, descrs);
+        ///            }
+        ///        }
+        ///    }
+        /// </code>
+        /// </remarks>
+        [CLSCompliant(false)]
+        protected unsafe void WriteEventWithRelatedActivityIdCore(int eventId, Guid* relatedActivityId, int eventDataCount, EventSource.EventData* data)
+        {
+            if (m_eventSourceEnabled)
+            {
+                try
+                {
+                    Debug.Assert(m_eventData != null);  // You must have initialized this if you enabled the source.
+                    if (relatedActivityId != null)
+                        ValidateEventOpcodeForTransfer(ref m_eventData[eventId], m_eventData[eventId].Name);
+
+                    EventOpcode opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode;
+                    EventActivityOptions activityOptions = m_eventData[eventId].ActivityOptions;
+                    Guid* pActivityId = null;
+                    Guid activityId = Guid.Empty;
+                    Guid relActivityId = Guid.Empty;
+
+                    if (opcode != EventOpcode.Info && relatedActivityId == null &&
+                       ((activityOptions & EventActivityOptions.Disable) == 0))
+                    {
+                        if (opcode == EventOpcode.Start)
+                        {
+                            m_activityTracker.OnStart(m_name, m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Task, ref activityId, ref relActivityId, m_eventData[eventId].ActivityOptions);
+                        }
+                        else if (opcode == EventOpcode.Stop)
+                        {
+                            m_activityTracker.OnStop(m_name, m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Task, ref activityId);
+                        }
+
+                        if (activityId != Guid.Empty)
+                            pActivityId = &activityId;
+                        if (relActivityId != Guid.Empty)
+                            relatedActivityId = &relActivityId;
+                    }
+
+#if FEATURE_MANAGED_ETW
+                    if (m_eventData[eventId].EnabledForETW)
+                    {
+
+#if FEATURE_ACTIVITYSAMPLING
+                        // this code should be kept in sync with WriteEventVarargs().
+                        SessionMask etwSessions = SessionMask.All;
+                        // only compute etwSessions if there are *any* ETW filters enabled...
+                        if ((ulong)m_curLiveSessions != 0)
+                            etwSessions = GetEtwSessionMask(eventId, relatedActivityId);
+                        // OutputDebugString(string.Format("{0}.WriteEvent(id {1}) -> to sessions {2:x}", 
+                        //                   m_name, m_eventData[eventId].Name, (ulong) etwSessions));
+
+                        if ((ulong)etwSessions != 0 || m_legacySessions != null && m_legacySessions.Count > 0)
+                        {
+                            if (!SelfDescribingEvents)
+                            {
+                                if (etwSessions.IsEqualOrSupersetOf(m_curLiveSessions))
+                                {
+                                    // OutputDebugString(string.Format("  (1) id {0}, kwd {1:x}", 
+                                    //                   m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Keywords));
+                                    // by default the Descriptor.Keyword will have the perEventSourceSessionId bit 
+                                    // mask set to 0x0f so, when all ETW sessions want the event we don't need to 
+                                    // synthesize a new one
+                                    if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
+                                        ThrowEventSourceException(m_eventData[eventId].Name);
+                                }
+                                else
+                                {
+                                    long origKwd = unchecked((long)((ulong)m_eventData[eventId].Descriptor.Keywords & ~(SessionMask.All.ToEventKeywords())));
+                                    // OutputDebugString(string.Format("  (2) id {0}, kwd {1:x}", 
+                                    //                   m_eventData[eventId].Name, etwSessions.ToEventKeywords() | (ulong) origKwd));
+                                    // only some of the ETW sessions will receive this event. Synthesize a new
+                                    // Descriptor whose Keywords field will have the appropriate bits set.
+                                    // etwSessions might be 0, if there are legacy ETW listeners that want this event
+                                    var desc = new EventDescriptor(
+                                        m_eventData[eventId].Descriptor.EventId,
+                                        m_eventData[eventId].Descriptor.Version,
+                                        m_eventData[eventId].Descriptor.Channel,
+                                        m_eventData[eventId].Descriptor.Level,
+                                        m_eventData[eventId].Descriptor.Opcode,
+                                        m_eventData[eventId].Descriptor.Task,
+                                        unchecked((long)etwSessions.ToEventKeywords() | origKwd));
+
+                                    if (!m_provider.WriteEvent(ref desc, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
+                                        ThrowEventSourceException(m_eventData[eventId].Name);
+                                }
+                            }
+                            else
+                            {
+                                TraceLoggingEventTypes tlet = m_eventData[eventId].TraceLoggingEventTypes;
+                                if (tlet == null)
+                                {
+                                    tlet = new TraceLoggingEventTypes(m_eventData[eventId].Name,
+                                                                            EventTags.None,
+                                                                        m_eventData[eventId].Parameters);
+                                    Interlocked.CompareExchange(ref m_eventData[eventId].TraceLoggingEventTypes, tlet, null);
+
+                                }
+                                long origKwd = unchecked((long)((ulong)m_eventData[eventId].Descriptor.Keywords & ~(SessionMask.All.ToEventKeywords())));
+                                // TODO: activity ID support
+                                EventSourceOptions opt = new EventSourceOptions
+                                {
+                                    Keywords = (EventKeywords)unchecked((long)etwSessions.ToEventKeywords() | origKwd),
+                                    Level = (EventLevel)m_eventData[eventId].Descriptor.Level,
+                                    Opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode
+                                };
+
+                                WriteMultiMerge(m_eventData[eventId].Name, ref opt, tlet, pActivityId, relatedActivityId, data);
+                            }
+                        }
+#else
+                        if (!SelfDescribingEvents)
+                        {
+                            if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
+                                ThrowEventSourceException(m_eventData[eventId].Name);
+                        }
+                        else
+                        {
+                            TraceLoggingEventTypes tlet = m_eventData[eventId].TraceLoggingEventTypes;
+                            if (tlet == null)
+                            {
+                                tlet = new TraceLoggingEventTypes(m_eventData[eventId].Name,
+                                                                    m_eventData[eventId].Tags,
+                                                                    m_eventData[eventId].Parameters);
+                                Interlocked.CompareExchange(ref m_eventData[eventId].TraceLoggingEventTypes, tlet, null);
+
+                            }
+                            EventSourceOptions opt = new EventSourceOptions
+                            {
+                                Keywords = (EventKeywords)m_eventData[eventId].Descriptor.Keywords,
+                                Level = (EventLevel)m_eventData[eventId].Descriptor.Level,
+                                Opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode
+                            };
+
+                            WriteMultiMerge(m_eventData[eventId].Name, ref opt, tlet, pActivityId, relatedActivityId, data);
+                        }
+#endif // FEATURE_ACTIVITYSAMPLING
+                    }
+#endif // FEATURE_MANAGED_ETW
+
+                    if (m_Dispatchers != null && m_eventData[eventId].EnabledForAnyListener)
+                        WriteToAllListeners(eventId, relatedActivityId, eventDataCount, data);
+                }
+                catch (Exception ex)
+                {
+                    if (ex is EventSourceException)
+                        throw;
+                    else
+                        ThrowEventSourceException(m_eventData[eventId].Name, ex);
+                }
+            }
+        }
+
+        // fallback varags helpers. 
+        /// <summary>
+        /// This is the varargs helper for writing an event. It does create an array and box all the arguments so it is
+        /// relatively inefficient and should only be used for relatively rare events (e.g. less than 100 / sec). If your
+        /// rates are faster than that you should use <see cref="WriteEventCore"/> to create fast helpers for your particular 
+        /// method signature. Even if you use this for rare events, this call should be guarded by an <see cref="IsEnabled()"/> 
+        /// check so that the varargs call is not made when the EventSource is not active.  
+        /// </summary>
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        protected unsafe void WriteEvent(int eventId, params object[] args)
+        {
+            WriteEventVarargs(eventId, null, args);
+        }
+
+        /// <summary>
+        /// This is the varargs helper for writing an event which also specifies a related activity. It is completely analogous
+        /// to corresponding WriteEvent (they share implementation). It does create an array and box all the arguments so it is
+        /// relatively inefficient and should only be used for relatively rare events (e.g. less than 100 / sec).  If your
+        /// rates are faster than that you should use <see cref="WriteEventWithRelatedActivityIdCore"/> to create fast helpers for your 
+        /// particular method signature. Even if you use this for rare events, this call should be guarded by an <see cref="IsEnabled()"/>
+        /// check so that the varargs call is not made when the EventSource is not active.
+        /// </summary>
+        protected unsafe void WriteEventWithRelatedActivityId(int eventId, Guid relatedActivityId, params object[] args)
+        {
+            WriteEventVarargs(eventId, &relatedActivityId, args);
+        }
+
+        #endregion
+
+        #region IDisposable Members
+        /// <summary>
+        /// Disposes of an EventSource.
+        /// </summary>
+        public void Dispose()
+        {
+            this.Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+        /// <summary>
+        /// Disposes of an EventSource.
+        /// </summary>
+        /// <remarks>
+        /// Called from Dispose() with disposing=true, and from the finalizer (~EventSource) with disposing=false.
+        /// Guidelines:
+        /// 1. We may be called more than once: do nothing after the first call.
+        /// 2. Avoid throwing exceptions if disposing is false, i.e. if we're being finalized.
+        /// </remarks>
+        /// <param name="disposing">True if called from Dispose(), false if called from the finalizer.</param>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+#if FEATURE_MANAGED_ETW
+                // Send the manifest one more time to ensure circular buffers have a chance to get to this information
+                // even in scenarios with a high volume of ETW events.
+                if (m_eventSourceEnabled)
+                {
+                    try
+                    {
+                        SendManifest(m_rawManifest);
+                    }
+                    catch (Exception)
+                    { }           // If it fails, simply give up.   
+                    m_eventSourceEnabled = false;
+                }
+                if (m_provider != null)
+                {
+                    m_provider.Dispose();
+                    m_provider = null;
+                }
+#endif
+            }
+            m_eventSourceEnabled = false;
+            m_eventSourceDisposed = true;
+        }
+        /// <summary>
+        /// Finalizer for EventSource
+        /// </summary>
+        ~EventSource()
+        {
+            this.Dispose(false);
+        }
+        #endregion
+
+        #region private
+#if FEATURE_ACTIVITYSAMPLING
+        internal void WriteStringToListener(EventListener listener, string msg, SessionMask m)
+        {
+            Debug.Assert(listener == null || (uint)m == (uint)SessionMask.FromId(0));
+
+            if (m_eventSourceEnabled)
+            {
+                if (listener == null)
+                {
+                    WriteEventString(0, unchecked((long)m.ToEventKeywords()), msg);
+                }
+                else
+                {
+                    EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this);
+                    eventCallbackArgs.EventId = 0;
+                    eventCallbackArgs.Message = msg;
+                    eventCallbackArgs.Payload = new ReadOnlyCollection<object>(new List<object>() { msg });
+                    eventCallbackArgs.PayloadNames = new ReadOnlyCollection<string>(new List<string> { "message" });
+                    eventCallbackArgs.EventName = "EventSourceMessage";
+                    listener.OnEventWritten(eventCallbackArgs);
+                }
+            }
+        }
+#endif
+
+        private unsafe void WriteEventRaw(
+            string eventName,
+            ref EventDescriptor eventDescriptor,
+            Guid* activityID,
+            Guid* relatedActivityID,
+            int dataCount,
+            IntPtr data)
+        {
+#if FEATURE_MANAGED_ETW
+            if (m_provider == null)
+            {
+                ThrowEventSourceException(eventName);
+            }
+            else
+            {
+                if (!m_provider.WriteEventRaw(ref eventDescriptor, activityID, relatedActivityID, dataCount, data))
+                    ThrowEventSourceException(eventName);
+            }
+#endif // FEATURE_MANAGED_ETW
+        }
+
+        // FrameworkEventSource is on the startup path for the framework, so we have this internal overload that it can use
+        // to prevent the working set hit from looking at the custom attributes on the type to get the Guid.
+        internal EventSource(Guid eventSourceGuid, string eventSourceName)
+            : this(eventSourceGuid, eventSourceName, EventSourceSettings.EtwManifestEventFormat)
+        { }
+
+        // Used by the internal FrameworkEventSource constructor and the TraceLogging-style event source constructor
+        internal EventSource(Guid eventSourceGuid, string eventSourceName, EventSourceSettings settings, string[] traits = null)
+        {
+            m_config = ValidateSettings(settings);
+            Initialize(eventSourceGuid, eventSourceName, traits);
+        }
+
+        /// <summary>
+        /// This method is responsible for the common initialization path from our constructors. It must
+        /// not leak any exceptions (otherwise, since most EventSource classes define a static member, 
+        /// "Log", such an exception would become a cached exception for the initialization of the static
+        /// member, and any future access to the "Log" would throw the cached exception).
+        /// </summary>
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "guid")]
+        private unsafe void Initialize(Guid eventSourceGuid, string eventSourceName, string[] traits)
+        {
+            try
+            {
+                m_traits = traits;
+                if (m_traits != null && m_traits.Length % 2 != 0)
+                {
+                    throw new ArgumentException(Resources.GetResourceString("TraitEven"), nameof(traits));
+                }
+
+                if (eventSourceGuid == Guid.Empty)
+                {
+                    throw new ArgumentException(Resources.GetResourceString("EventSource_NeedGuid"));
+                }
+
+                if (eventSourceName == null)
+                {
+                    throw new ArgumentException(Resources.GetResourceString("EventSource_NeedName"));
+                }
+
+                m_name = eventSourceName;
+                m_guid = eventSourceGuid;
+#if FEATURE_ACTIVITYSAMPLING
+                m_curLiveSessions = new SessionMask(0);
+                m_etwSessionIdMap = new EtwSession[SessionMask.MAX];
+#endif // FEATURE_ACTIVITYSAMPLING
+
+                //Enable Implicit Activity tracker
+                m_activityTracker = ActivityTracker.Instance;
+
+#if FEATURE_MANAGED_ETW
+                // Create and register our provider traits.  We do this early because it is needed to log errors 
+                // In the self-describing event case. 
+                this.InitializeProviderMetadata();
+
+                // Register the provider with ETW
+                var provider = new OverideEventProvider(this);
+                provider.Register(eventSourceGuid);
+#endif
+                // Add the eventSource to the global (weak) list.  
+                // This also sets m_id, which is the index in the list. 
+                EventListener.AddEventSource(this);
+
+#if FEATURE_MANAGED_ETW
+                // OK if we get this far without an exception, then we can at least write out error messages. 
+                // Set m_provider, which allows this.  
+                m_provider = provider;
+
+#if (!ES_BUILD_STANDALONE && !ES_BUILD_PN)
+                // API available on OS >= Win 8 and patched Win 7.
+                // Disable only for FrameworkEventSource to avoid recursion inside exception handling.
+                var osVer = Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor;
+                if (this.Name != "System.Diagnostics.Eventing.FrameworkEventSource" || osVer >= 62)
+#endif
+                {
+                    int setInformationResult;
+                    System.Runtime.InteropServices.GCHandle metadataHandle =
+                        System.Runtime.InteropServices.GCHandle.Alloc(this.providerMetadata, System.Runtime.InteropServices.GCHandleType.Pinned);
+                    IntPtr providerMetadata = metadataHandle.AddrOfPinnedObject();
+
+                    setInformationResult = m_provider.SetInformation(
+                        UnsafeNativeMethods.ManifestEtw.EVENT_INFO_CLASS.SetTraits,
+                        providerMetadata,
+                        (uint)this.providerMetadata.Length);
+
+                    metadataHandle.Free();
+                }
+#endif // FEATURE_MANAGED_ETW
+
+                Debug.Assert(!m_eventSourceEnabled);     // We can't be enabled until we are completely initted.  
+                // We are logically completely initialized at this point.  
+                m_completelyInited = true;
+            }
+            catch (Exception e)
+            {
+                if (m_constructionException == null)
+                    m_constructionException = e;
+                ReportOutOfBandMessage("ERROR: Exception during construction of EventSource " + Name + ": " + e.Message, true);
+            }
+
+            // Once m_completelyInited is set, you can have concurrency, so all work is under the lock.  
+            lock (EventListener.EventListenersLock)
+            {
+                // If there are any deferred commands, we can do them now.   
+                // This is the most likely place for exceptions to happen.  
+                // Note that we are NOT resetting m_deferredCommands to NULL here, 
+                // We are giving for EventHandler<EventCommandEventArgs> that will be attached later
+                EventCommandEventArgs deferredCommands = m_deferredCommands;
+                while (deferredCommands != null)
+                {
+                    DoCommand(deferredCommands);      // This can never throw, it catches them and reports the errors.   
+                    deferredCommands = deferredCommands.nextCommand;
+                }
+            }
+        }
+
+        private static string GetName(Type eventSourceType, EventManifestOptions flags)
+        {
+            if (eventSourceType == null)
+                throw new ArgumentNullException(nameof(eventSourceType));
+            Contract.EndContractBlock();
+
+            EventSourceAttribute attrib = (EventSourceAttribute)GetCustomAttributeHelper(eventSourceType, typeof(EventSourceAttribute), flags);
+            if (attrib != null && attrib.Name != null)
+                return attrib.Name;
+
+            return eventSourceType.Name;
+        }
+
+        /// <summary>
+        /// Implements the SHA1 hashing algorithm. Note that this
+        /// implementation is for hashing public information. Do not
+        /// use this code to hash private data, as this implementation does
+        /// not take any steps to avoid information disclosure.
+        /// </summary>
+        private struct Sha1ForNonSecretPurposes
+        {
+            private long length; // Total message length in bits
+            private uint[] w; // Workspace
+            private int pos; // Length of current chunk in bytes
+
+            /// <summary>
+            /// Call Start() to initialize the hash object.
+            /// </summary>
+            public void Start()
+            {
+                if (this.w == null)
+                {
+                    this.w = new uint[85];
+                }
+
+                this.length = 0;
+                this.pos = 0;
+                this.w[80] = 0x67452301;
+                this.w[81] = 0xEFCDAB89;
+                this.w[82] = 0x98BADCFE;
+                this.w[83] = 0x10325476;
+                this.w[84] = 0xC3D2E1F0;
+            }
+
+            /// <summary>
+            /// Adds an input byte to the hash.
+            /// </summary>
+            /// <param name="input">Data to include in the hash.</param>
+            public void Append(byte input)
+            {
+                this.w[this.pos / 4] = (this.w[this.pos / 4] << 8) | input;
+                if (64 == ++this.pos)
+                {
+                    this.Drain();
+                }
+            }
+
+            /// <summary>
+            /// Adds input bytes to the hash.
+            /// </summary>
+            /// <param name="input">
+            /// Data to include in the hash. Must not be null.
+            /// </param>
+            public void Append(byte[] input)
+            {
+                foreach (var b in input)
+                {
+                    this.Append(b);
+                }
+            }
+
+            /// <summary>
+            /// Retrieves the hash value.
+            /// Note that after calling this function, the hash object should
+            /// be considered uninitialized. Subsequent calls to Append or
+            /// Finish will produce useless results. Call Start() to
+            /// reinitialize.
+            /// </summary>
+            /// <param name="output">
+            /// Buffer to receive the hash value. Must not be null.
+            /// Up to 20 bytes of hash will be written to the output buffer.
+            /// If the buffer is smaller than 20 bytes, the remaining hash
+            /// bytes will be lost. If the buffer is larger than 20 bytes, the
+            /// rest of the buffer is left unmodified.
+            /// </param>
+            public void Finish(byte[] output)
+            {
+                long l = this.length + 8 * this.pos;
+                this.Append(0x80);
+                while (this.pos != 56)
+                {
+                    this.Append(0x00);
+                }
+
+                unchecked
+                {
+                    this.Append((byte)(l >> 56));
+                    this.Append((byte)(l >> 48));
+                    this.Append((byte)(l >> 40));
+                    this.Append((byte)(l >> 32));
+                    this.Append((byte)(l >> 24));
+                    this.Append((byte)(l >> 16));
+                    this.Append((byte)(l >> 8));
+                    this.Append((byte)l);
+
+                    int end = output.Length < 20 ? output.Length : 20;
+                    for (int i = 0; i != end; i++)
+                    {
+                        uint temp = this.w[80 + i / 4];
+                        output[i] = (byte)(temp >> 24);
+                        this.w[80 + i / 4] = temp << 8;
+                    }
+                }
+            }
+
+            /// <summary>
+            /// Called when this.pos reaches 64.
+            /// </summary>
+            private void Drain()
+            {
+                for (int i = 16; i != 80; i++)
+                {
+                    this.w[i] = Rol1((this.w[i - 3] ^ this.w[i - 8] ^ this.w[i - 14] ^ this.w[i - 16]));
+                }
+
+                unchecked
+                {
+                    uint a = this.w[80];
+                    uint b = this.w[81];
+                    uint c = this.w[82];
+                    uint d = this.w[83];
+                    uint e = this.w[84];
+
+                    for (int i = 0; i != 20; i++)
+                    {
+                        const uint k = 0x5A827999;
+                        uint f = (b & c) | ((~b) & d);
+                        uint temp = Rol5(a) + f + e + k + this.w[i]; e = d; d = c; c = Rol30(b); b = a; a = temp;
+                    }
+
+                    for (int i = 20; i != 40; i++)
+                    {
+                        uint f = b ^ c ^ d;
+                        const uint k = 0x6ED9EBA1;
+                        uint temp = Rol5(a) + f + e + k + this.w[i]; e = d; d = c; c = Rol30(b); b = a; a = temp;
+                    }
+
+                    for (int i = 40; i != 60; i++)
+                    {
+                        uint f = (b & c) | (b & d) | (c & d);
+                        const uint k = 0x8F1BBCDC;
+                        uint temp = Rol5(a) + f + e + k + this.w[i]; e = d; d = c; c = Rol30(b); b = a; a = temp;
+                    }
+
+                    for (int i = 60; i != 80; i++)
+                    {
+                        uint f = b ^ c ^ d;
+                        const uint k = 0xCA62C1D6;
+                        uint temp = Rol5(a) + f + e + k + this.w[i]; e = d; d = c; c = Rol30(b); b = a; a = temp;
+                    }
+
+                    this.w[80] += a;
+                    this.w[81] += b;
+                    this.w[82] += c;
+                    this.w[83] += d;
+                    this.w[84] += e;
+                }
+
+                this.length += 512; // 64 bytes == 512 bits
+                this.pos = 0;
+            }
+
+            private static uint Rol1(uint input)
+            {
+                return (input << 1) | (input >> 31);
+            }
+
+            private static uint Rol5(uint input)
+            {
+                return (input << 5) | (input >> 27);
+            }
+
+            private static uint Rol30(uint input)
+            {
+                return (input << 30) | (input >> 2);
+            }
+        }
+
+        private static Guid GenerateGuidFromName(string name)
+        {
+            byte[] bytes = Encoding.BigEndianUnicode.GetBytes(name);
+            var hash = new Sha1ForNonSecretPurposes();
+            hash.Start();
+            hash.Append(namespaceBytes);
+            hash.Append(bytes);
+            Array.Resize(ref bytes, 16);
+            hash.Finish(bytes);
+
+            bytes[7] = unchecked((byte)((bytes[7] & 0x0F) | 0x50));    // Set high 4 bits of octet 7 to 5, as per RFC 4122
+            return new Guid(bytes);
+        }
+
+        private unsafe object DecodeObject(int eventId, int parameterId, ref EventSource.EventData* data)
+        {
+            // TODO FIX : We use reflection which in turn uses EventSource, right now we carefully avoid
+            // the recursion, but can we do this in a robust way?  
+
+            IntPtr dataPointer = data->DataPointer;
+            // advance to next EventData in array
+            ++data;
+
+            Type dataType = GetDataType(m_eventData[eventId], parameterId);
+
+            Again:
+            if (dataType == typeof(IntPtr))
+            {
+                return *((IntPtr*)dataPointer);
+            }
+            else if (dataType == typeof(int))
+            {
+                return *((int*)dataPointer);
+            }
+            else if (dataType == typeof(uint))
+            {
+                return *((uint*)dataPointer);
+            }
+            else if (dataType == typeof(long))
+            {
+                return *((long*)dataPointer);
+            }
+            else if (dataType == typeof(ulong))
+            {
+                return *((ulong*)dataPointer);
+            }
+            else if (dataType == typeof(byte))
+            {
+                return *((byte*)dataPointer);
+            }
+            else if (dataType == typeof(sbyte))
+            {
+                return *((sbyte*)dataPointer);
+            }
+            else if (dataType == typeof(short))
+            {
+                return *((short*)dataPointer);
+            }
+            else if (dataType == typeof(ushort))
+            {
+                return *((ushort*)dataPointer);
+            }
+            else if (dataType == typeof(float))
+            {
+                return *((float*)dataPointer);
+            }
+            else if (dataType == typeof(double))
+            {
+                return *((double*)dataPointer);
+            }
+            else if (dataType == typeof(decimal))
+            {
+                return *((decimal*)dataPointer);
+            }
+            else if (dataType == typeof(bool))
+            {
+                // The manifest defines a bool as a 32bit type (WIN32 BOOL), not 1 bit as CLR Does.
+                if (*((int*)dataPointer) == 1)
+                {
+                    return true;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+            else if (dataType == typeof(Guid))
+            {
+                return *((Guid*)dataPointer);
+            }
+            else if (dataType == typeof(char))
+            {
+                return *((char*)dataPointer);
+            }
+            else if (dataType == typeof(DateTime))
+            {
+                long dateTimeTicks = *((long*)dataPointer);
+                return DateTime.FromFileTimeUtc(dateTimeTicks);
+            }
+            else if (dataType == typeof(byte[]))
+            {
+                // byte[] are written to EventData* as an int followed by a blob
+                int cbSize = *((int*)dataPointer);
+                byte[] blob = new byte[cbSize];
+                dataPointer = data->DataPointer;
+                data++;
+                for (int i = 0; i < cbSize; ++i)
+                    blob[i] = *((byte*)(dataPointer + i));
+                return blob;
+            }
+            else if (dataType == typeof(byte*))
+            {
+                // TODO: how do we want to handle this? For now we ignore it...
+                return null;
+            }
+            else
+            {
+                if (m_EventSourcePreventRecursion && m_EventSourceInDecodeObject)
+                {
+                    return null;
+                }
+
+                try
+                {
+                    m_EventSourceInDecodeObject = true;
+
+                    if (dataType.IsEnum())
+                    {
+                        dataType = Enum.GetUnderlyingType(dataType);
+                        goto Again;
+                    }
+
+
+                    // Everything else is marshaled as a string.
+                    // ETW strings are NULL-terminated, so marshal everything up to the first
+                    // null in the string.
+                    //return System.Runtime.InteropServices.Marshal.PtrToStringUni(dataPointer);
+                    if(dataPointer == IntPtr.Zero)
+                    {
+                        return null;
+                    }
+
+                    return new string((char *)dataPointer);
+
+                }
+                finally
+                {
+                    m_EventSourceInDecodeObject = false;
+                }
+            }
+        }
+
+        // Finds the Dispatcher (which holds the filtering state), for a given dispatcher for the current
+        // eventSource).  
+        private EventDispatcher GetDispatcher(EventListener listener)
+        {
+            EventDispatcher dispatcher = m_Dispatchers;
+            while (dispatcher != null)
+            {
+                if (dispatcher.m_Listener == listener)
+                    return dispatcher;
+                dispatcher = dispatcher.m_Next;
+            }
+            return dispatcher;
+        }
+
+        private unsafe void WriteEventVarargs(int eventId, Guid* childActivityID, object[] args)
+        {
+            if (m_eventSourceEnabled)
+            {
+                try
+                {
+                    Debug.Assert(m_eventData != null);  // You must have initialized this if you enabled the source.  
+                    if (childActivityID != null)
+                    {
+                        ValidateEventOpcodeForTransfer(ref m_eventData[eventId], m_eventData[eventId].Name);
+
+                        // If you use WriteEventWithRelatedActivityID you MUST declare the first argument to be a GUID 
+                        // with the name 'relatedActivityID, and NOT pass this argument to the WriteEvent method.  
+                        // During manifest creation we modify the ParameterInfo[] that we store to strip out any
+                        // first parameter that is of type Guid and named "relatedActivityId." Thus, if you call
+                        // WriteEventWithRelatedActivityID from a method that doesn't name its first parameter correctly
+                        // we can end up in a state where the ParameterInfo[] doesn't have its first parameter stripped,
+                        // and this leads to a mismatch between the number of arguments and the number of ParameterInfos,
+                        // which would cause a cryptic IndexOutOfRangeException later if we don't catch it here.
+                        if (!m_eventData[eventId].HasRelatedActivityID)
+                        {
+                            throw new ArgumentException(Resources.GetResourceString("EventSource_NoRelatedActivityId"));
+                        }
+                    }
+
+                    LogEventArgsMismatches(m_eventData[eventId].Parameters, args);
+
+                    Guid* pActivityId = null;
+                    Guid activityId = Guid.Empty;
+                    Guid relatedActivityId = Guid.Empty;
+                    EventOpcode opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode;
+                    EventActivityOptions activityOptions = m_eventData[eventId].ActivityOptions;
+
+                    if (childActivityID == null &&
+                       ((activityOptions & EventActivityOptions.Disable) == 0))
+                    {
+                        if (opcode == EventOpcode.Start)
+                        {
+                            m_activityTracker.OnStart(m_name, m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Task, ref activityId, ref relatedActivityId, m_eventData[eventId].ActivityOptions);
+                        }
+                        else if (opcode == EventOpcode.Stop)
+                        {
+                            m_activityTracker.OnStop(m_name, m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Task, ref activityId);
+                        }
+
+                        if (activityId != Guid.Empty)
+                            pActivityId = &activityId;
+                        if (relatedActivityId != Guid.Empty)
+                            childActivityID = &relatedActivityId;
+                    }
+
+#if FEATURE_MANAGED_ETW
+                    if (m_eventData[eventId].EnabledForETW)
+                    {
+#if FEATURE_ACTIVITYSAMPLING
+                        // this code should be kept in sync with WriteEventWithRelatedActivityIdCore().
+                        SessionMask etwSessions = SessionMask.All;
+                        // only compute etwSessions if there are *any* ETW filters enabled...
+                        if ((ulong)m_curLiveSessions != 0)
+                            etwSessions = GetEtwSessionMask(eventId, childActivityID);
+
+                        if ((ulong)etwSessions != 0 || m_legacySessions != null && m_legacySessions.Count > 0)
+                        {
+                            if (!SelfDescribingEvents)
+                            {
+                                if (etwSessions.IsEqualOrSupersetOf(m_curLiveSessions))
+                                {
+                                    // by default the Descriptor.Keyword will have the perEventSourceSessionId bit 
+                                    // mask set to 0x0f so, when all ETW sessions want the event we don't need to 
+                                    // synthesize a new one
+                                    if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, childActivityID, args))
+                                        ThrowEventSourceException(m_eventData[eventId].Name);
+                                }
+                                else
+                                {
+                                    long origKwd = unchecked((long)((ulong)m_eventData[eventId].Descriptor.Keywords & ~(SessionMask.All.ToEventKeywords())));
+                                    // only some of the ETW sessions will receive this event. Synthesize a new
+                                    // Descriptor whose Keywords field will have the appropriate bits set.
+                                    var desc = new EventDescriptor(
+                                        m_eventData[eventId].Descriptor.EventId,
+                                        m_eventData[eventId].Descriptor.Version,
+                                        m_eventData[eventId].Descriptor.Channel,
+                                        m_eventData[eventId].Descriptor.Level,
+                                        m_eventData[eventId].Descriptor.Opcode,
+                                        m_eventData[eventId].Descriptor.Task,
+                                        unchecked((long)etwSessions.ToEventKeywords() | origKwd));
+
+                                    if (!m_provider.WriteEvent(ref desc, pActivityId, childActivityID, args))
+                                        ThrowEventSourceException(m_eventData[eventId].Name);
+                                }
+                            }
+                            else
+                            {
+                                TraceLoggingEventTypes tlet = m_eventData[eventId].TraceLoggingEventTypes;
+                                if (tlet == null)
+                                {
+                                    tlet = new TraceLoggingEventTypes(m_eventData[eventId].Name,
+                                                                        EventTags.None,
+                                                                        m_eventData[eventId].Parameters);
+                                    Interlocked.CompareExchange(ref m_eventData[eventId].TraceLoggingEventTypes, tlet, null);
+
+                                }
+                                long origKwd = unchecked((long)((ulong)m_eventData[eventId].Descriptor.Keywords & ~(SessionMask.All.ToEventKeywords())));
+                                // TODO: activity ID support
+                                EventSourceOptions opt = new EventSourceOptions
+                                {
+                                    Keywords = (EventKeywords)unchecked((long)etwSessions.ToEventKeywords() | origKwd),
+                                    Level = (EventLevel)m_eventData[eventId].Descriptor.Level,
+                                    Opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode
+                                };
+
+                                WriteMultiMerge(m_eventData[eventId].Name, ref opt, tlet, pActivityId, childActivityID, args);
+                            }
+                        }
+#else
+                        if (!SelfDescribingEvents)
+                        {
+                            if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, childActivityID, args))
+                                ThrowEventSourceException(m_eventData[eventId].Name);
+                        }
+                        else
+                        {
+                            TraceLoggingEventTypes tlet = m_eventData[eventId].TraceLoggingEventTypes;
+                            if (tlet == null)
+                            {
+                                tlet = new TraceLoggingEventTypes(m_eventData[eventId].Name,
+                                                                    EventTags.None,
+                                                                    m_eventData[eventId].Parameters);
+                                Interlocked.CompareExchange(ref m_eventData[eventId].TraceLoggingEventTypes, tlet, null);
+
+                            }
+                            // TODO: activity ID support
+                            EventSourceOptions opt = new EventSourceOptions
+                            {
+                                Keywords = (EventKeywords)m_eventData[eventId].Descriptor.Keywords,
+                                Level = (EventLevel)m_eventData[eventId].Descriptor.Level,
+                                Opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode
+                            };
+
+                            WriteMultiMerge(m_eventData[eventId].Name, ref opt, tlet, pActivityId, childActivityID, args);
+                        }
+#endif // FEATURE_ACTIVITYSAMPLING
+                    }
+#endif // FEATURE_MANAGED_ETW
+                    if (m_Dispatchers != null && m_eventData[eventId].EnabledForAnyListener)
+                    {
+#if (!ES_BUILD_STANDALONE && !ES_BUILD_PN)
+                        // Maintain old behavior - object identity is preserved
+                        if (AppContextSwitches.PreserveEventListnerObjectIdentity)
+                        {
+                            WriteToAllListeners(eventId, childActivityID, args);
+                        }
+                        else
+#endif // !ES_BUILD_STANDALONE
+                        {
+                            object[] serializedArgs = SerializeEventArgs(eventId, args);
+                            WriteToAllListeners(eventId, childActivityID, serializedArgs);
+                        }
+                    }
+                }
+                catch (Exception ex)
+                {
+                    if (ex is EventSourceException)
+                        throw;
+                    else
+                        ThrowEventSourceException(m_eventData[eventId].Name, ex);
+                }
+            }
+        }
+
+        unsafe private object[] SerializeEventArgs(int eventId, object[] args)
+        {
+            TraceLoggingEventTypes eventTypes = m_eventData[eventId].TraceLoggingEventTypes;
+            if (eventTypes == null)
+            {
+                eventTypes = new TraceLoggingEventTypes(m_eventData[eventId].Name,
+                                                        EventTags.None,
+                                                        m_eventData[eventId].Parameters);
+                Interlocked.CompareExchange(ref m_eventData[eventId].TraceLoggingEventTypes, eventTypes, null);
+            }
+            var eventData = new object[eventTypes.typeInfos.Length];
+            for (int i = 0; i < eventTypes.typeInfos.Length; i++)
+            {
+                eventData[i] = eventTypes.typeInfos[i].GetData(args[i]);
+            }
+            return eventData;
+        }
+
+        /// <summary>
+        /// We expect that the arguments to the Event method and the arguments to WriteEvent match. This function 
+        /// checks that they in fact match and logs a warning to the debugger if they don't.
+        /// </summary>
+        /// <param name="infos"></param>
+        /// <param name="args"></param>
+        private void LogEventArgsMismatches(ParameterInfo[] infos, object[] args)
+        {
+#if (!ES_BUILD_PCL && !ES_BUILD_PN)
+            // It would be nice to have this on PCL builds, but it would be pointless since there isn't support for 
+            // writing to the debugger log on PCL.
+            bool typesMatch = args.Length == infos.Length;
+
+            int i = 0;
+            while (typesMatch && i < args.Length)
+            {
+                Type pType = infos[i].ParameterType;
+
+                // Checking to see if the Parameter types (from the Event method) match the supplied argument types.
+                // Fail if one of two things hold : either the argument type is not equal to the parameter type, or the 
+                // argument is null and the parameter type is non-nullable.
+                if ((args[i] != null && (args[i].GetType() != pType))
+                    || (args[i] == null && (!(pType.IsGenericType && pType.GetGenericTypeDefinition() == typeof(Nullable<>))))
+                    )
+                {
+                    typesMatch = false;
+                    break;
+                }
+
+                ++i;
+            }
+
+            if (!typesMatch)
+            {
+                System.Diagnostics.Debugger.Log(0, null, Resources.GetResourceString("EventSource_VarArgsParameterMismatch") + "\r\n");
+            }
+#endif //!ES_BUILD_PCL
+        }
+
+        private int GetParamLenghtIncludingByteArray(ParameterInfo[] parameters)
+        {
+            int sum = 0;
+            foreach (ParameterInfo info in parameters)
+            {
+                if (info.ParameterType == typeof(byte[]))
+                {
+                    sum += 2;
+                }
+                else
+                {
+                    sum++;
+                }
+            }
+
+            return sum;
+        }
+
+        unsafe private void WriteToAllListeners(int eventId, Guid* childActivityID, int eventDataCount, EventSource.EventData* data)
+        {
+            // We represent a byte[] as a integer denoting the length  and then a blob of bytes in the data pointer. This causes a spurious
+            // warning because eventDataCount is off by one for the byte[] case since a byte[] has 2 items associated it. So we want to check
+            // that the number of parameters is correct against the byte[] case, but also we the args array would be one too long if
+            // we just used the modifiedParamCount here -- so we need both.
+            int paramCount = m_eventData[eventId].Parameters.Length;
+            int modifiedParamCount = GetParamLenghtIncludingByteArray(m_eventData[eventId].Parameters);
+            if (eventDataCount != modifiedParamCount)
+            {
+                ReportOutOfBandMessage(Resources.GetResourceString("EventSource_EventParametersMismatch", eventId, eventDataCount, paramCount), true);
+                paramCount = Math.Min(paramCount, eventDataCount);
+            }
+
+            object[] args = new object[paramCount];
+
+            EventSource.EventData* dataPtr = data;
+            for (int i = 0; i < paramCount; i++)
+                args[i] = DecodeObject(eventId, i, ref dataPtr);
+            WriteToAllListeners(eventId, childActivityID, args);
+        }
+
+        // helper for writing to all EventListeners attached the current eventSource.  
+        unsafe private void WriteToAllListeners(int eventId, Guid* childActivityID, params object[] args)
+        {
+            EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this);
+            eventCallbackArgs.EventId = eventId;
+            if (childActivityID != null)
+                eventCallbackArgs.RelatedActivityId = *childActivityID;
+            eventCallbackArgs.EventName = m_eventData[eventId].Name;
+            eventCallbackArgs.Message = m_eventData[eventId].Message;
+            eventCallbackArgs.Payload = new ReadOnlyCollection<object>(args);
+
+            DispatchToAllListeners(eventId, childActivityID, eventCallbackArgs);
+        }
+
+        private unsafe void DispatchToAllListeners(int eventId, Guid* childActivityID, EventWrittenEventArgs eventCallbackArgs)
+        {
+            Exception lastThrownException = null;
+            for (EventDispatcher dispatcher = m_Dispatchers; dispatcher != null; dispatcher = dispatcher.m_Next)
+            {
+                Debug.Assert(dispatcher.m_EventEnabled != null);
+                if (eventId == -1 || dispatcher.m_EventEnabled[eventId])
+                {
+#if FEATURE_ACTIVITYSAMPLING
+                    var activityFilter = dispatcher.m_Listener.m_activityFilter;
+                    // order below is important as PassesActivityFilter will "flow" active activities
+                    // even when the current EventSource doesn't have filtering enabled. This allows
+                    // interesting activities to be updated so that sources that do sample can get
+                    // accurate data
+                    if (activityFilter == null ||
+                        ActivityFilter.PassesActivityFilter(activityFilter, childActivityID,
+                                                            m_eventData[eventId].TriggersActivityTracking > 0,
+                                                            this, eventId) ||
+                        !dispatcher.m_activityFilteringEnabled)
+#endif // FEATURE_ACTIVITYSAMPLING
+                    {
+                        try
+                        {
+                            dispatcher.m_Listener.OnEventWritten(eventCallbackArgs);
+                        }
+                        catch (Exception e)
+                        {
+                            ReportOutOfBandMessage("ERROR: Exception during EventSource.OnEventWritten: "
+                                 + e.Message, false);
+                            lastThrownException = e;
+                        }
+                    }
+                }
+            }
+
+            if (lastThrownException != null)
+            {
+                throw new EventSourceException(lastThrownException);
+            }
+        }
+
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        private unsafe void WriteEventString(EventLevel level, long keywords, string msgString)
+        {
+#if FEATURE_MANAGED_ETW
+            if (m_provider != null)
+            {
+                string eventName = "EventSourceMessage";
+                if (SelfDescribingEvents)
+                {
+                    EventSourceOptions opt = new EventSourceOptions
+                    {
+                        Keywords = (EventKeywords)unchecked(keywords),
+                        Level = level
+                    };
+                    var msg = new { message = msgString };
+                    var tlet = new TraceLoggingEventTypes(eventName, EventTags.None, new Type[] { msg.GetType() });
+                    WriteMultiMergeInner(eventName, ref opt, tlet, null, null, msg);
+                }
+                else
+                {
+                    // We want the name of the provider to show up so if we don't have a manifest we create 
+                    // on that at least has the provider name (I don't define any events).   
+                    if (m_rawManifest == null && m_outOfBandMessageCount == 1)
+                    {
+                        ManifestBuilder manifestBuilder = new ManifestBuilder(Name, Guid, Name, null, EventManifestOptions.None);
+                        manifestBuilder.StartEvent(eventName, new EventAttribute(0) { Level = EventLevel.LogAlways, Task = (EventTask)0xFFFE });
+                        manifestBuilder.AddEventParameter(typeof(string), "message");
+                        manifestBuilder.EndEvent();
+                        SendManifest(manifestBuilder.CreateManifest());
+                    }
+
+                    // We use this low level routine to to bypass the enabled checking, since the eventSource itself is only partially inited. 
+                    fixed (char* msgStringPtr = msgString)
+                    {
+                        EventDescriptor descr = new EventDescriptor(0, 0, 0, (byte)level, 0, 0, keywords);
+                        EventProvider.EventData data = new EventProvider.EventData();
+                        data.Ptr = (ulong)msgStringPtr;
+                        data.Size = (uint)(2 * (msgString.Length + 1));
+                        data.Reserved = 0;
+                        m_provider.WriteEvent(ref descr, null, null, 1, (IntPtr)((void*)&data));
+                    }
+                }
+            }
+#endif // FEATURE_MANAGED_ETW
+        }
+
+        /// <summary>
+        /// Since this is a means of reporting errors (see ReportoutOfBandMessage) any failure encountered 
+        /// while writing the message to any one of the listeners will be silently ignored.
+        /// </summary>
+        private void WriteStringToAllListeners(string eventName, string msg)
+        {
+            EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this);
+            eventCallbackArgs.EventId = 0;
+            eventCallbackArgs.Message = msg;
+            eventCallbackArgs.Payload = new ReadOnlyCollection<object>(new List<object>() { msg });
+            eventCallbackArgs.PayloadNames = new ReadOnlyCollection<string>(new List<string> { "message" });
+            eventCallbackArgs.EventName = eventName;
+
+            for (EventDispatcher dispatcher = m_Dispatchers; dispatcher != null; dispatcher = dispatcher.m_Next)
+            {
+                bool dispatcherEnabled = false;
+                if (dispatcher.m_EventEnabled == null)
+                {
+                    // if the listeners that weren't correctly initialized, we will send to it
+                    // since this is an error message and we want to see it go out. 
+                    dispatcherEnabled = true;
+                }
+                else
+                {
+                    // if there's *any* enabled event on the dispatcher we'll write out the string
+                    // otherwise we'll treat the listener as disabled and skip it
+                    for (int evtId = 0; evtId < dispatcher.m_EventEnabled.Length; ++evtId)
+                    {
+                        if (dispatcher.m_EventEnabled[evtId])
+                        {
+                            dispatcherEnabled = true;
+                            break;
+                        }
+                    }
+                }
+                try
+                {
+                    if (dispatcherEnabled)
+                        dispatcher.m_Listener.OnEventWritten(eventCallbackArgs);
+                }
+                catch
+                {
+                    // ignore any exceptions thrown by listeners' OnEventWritten
+                }
+            }
+        }
+
+#if FEATURE_ACTIVITYSAMPLING
+        unsafe private SessionMask GetEtwSessionMask(int eventId, Guid* childActivityID)
+        {
+            SessionMask etwSessions = new SessionMask();
+
+            for (int i = 0; i < SessionMask.MAX; ++i)
+            {
+                EtwSession etwSession = m_etwSessionIdMap[i];
+                if (etwSession != null)
+                {
+                    ActivityFilter activityFilter = etwSession.m_activityFilter;
+                    // PassesActivityFilter() will flow "interesting" activities, so make sure
+                    // to perform this test first, before ORing with ~m_activityFilteringForETWEnabled
+                    // (note: the first test for !m_activityFilteringForETWEnabled[i] ensures we
+                    //  do not fire events indiscriminately, when no filters are specified, but only 
+                    //  if, in addition, the session did not also enable ActivitySampling)
+                    if (activityFilter == null && !m_activityFilteringForETWEnabled[i] ||
+                        activityFilter != null &&
+                            ActivityFilter.PassesActivityFilter(activityFilter, childActivityID,
+                                m_eventData[eventId].TriggersActivityTracking > 0, this, eventId) ||
+                        !m_activityFilteringForETWEnabled[i])
+                    {
+                        etwSessions[i] = true;
+                    }
+                }
+            }
+            // flow "interesting" activities for all legacy sessions in which there's some 
+            // level of activity tracing enabled (even other EventSources)
+            if (m_legacySessions != null && m_legacySessions.Count > 0 &&
+                (EventOpcode)m_eventData[eventId].Descriptor.Opcode == EventOpcode.Send)
+            {
+                // only calculate InternalCurrentThreadActivityId once
+                Guid* pCurrentActivityId = null;
+                Guid currentActivityId;
+                foreach (var legacyEtwSession in m_legacySessions)
+                {
+                    if (legacyEtwSession == null)
+                        continue;
+
+                    ActivityFilter activityFilter = legacyEtwSession.m_activityFilter;
+                    if (activityFilter != null)
+                    {
+                        if (pCurrentActivityId == null)
+                        {
+                            currentActivityId = InternalCurrentThreadActivityId;
+                            pCurrentActivityId = &currentActivityId;
+                        }
+                        ActivityFilter.FlowActivityIfNeeded(activityFilter, pCurrentActivityId, childActivityID);
+                    }
+                }
+            }
+
+            return etwSessions;
+        }
+#endif // FEATURE_ACTIVITYSAMPLING
+
+        /// <summary>
+        /// Returns true if 'eventNum' is enabled if you only consider the level and matchAnyKeyword filters.
+        /// It is possible that eventSources turn off the event based on additional filtering criteria.  
+        /// </summary>
+        private bool IsEnabledByDefault(int eventNum, bool enable, EventLevel currentLevel, EventKeywords currentMatchAnyKeyword)
+        {
+            if (!enable)
+                return false;
+
+            EventLevel eventLevel = (EventLevel)m_eventData[eventNum].Descriptor.Level;
+            EventKeywords eventKeywords = unchecked((EventKeywords)((ulong)m_eventData[eventNum].Descriptor.Keywords & (~(SessionMask.All.ToEventKeywords()))));
+
+#if FEATURE_MANAGED_ETW_CHANNELS
+            EventChannel channel = unchecked((EventChannel)m_eventData[eventNum].Descriptor.Channel);
+#else
+            EventChannel channel = EventChannel.None;
+#endif
+
+            return IsEnabledCommon(enable, currentLevel, currentMatchAnyKeyword, eventLevel, eventKeywords, channel);
+        }
+
+        private bool IsEnabledCommon(bool enabled, EventLevel currentLevel, EventKeywords currentMatchAnyKeyword,
+                                                          EventLevel eventLevel, EventKeywords eventKeywords, EventChannel eventChannel)
+        {
+            if (!enabled)
+                return false;
+
+            // does is pass the level test?
+            if ((currentLevel != 0) && (currentLevel < eventLevel))
+                return false;
+
+            // if yes, does it pass the keywords test?
+            if (currentMatchAnyKeyword != 0 && eventKeywords != 0)
+            {
+#if FEATURE_MANAGED_ETW_CHANNELS
+                // is there a channel with keywords that match currentMatchAnyKeyword?
+                if (eventChannel != EventChannel.None && this.m_channelData != null && this.m_channelData.Length > (int)eventChannel)
+                {
+                    EventKeywords channel_keywords = unchecked((EventKeywords)(m_channelData[(int)eventChannel] | (ulong)eventKeywords));
+                    if (channel_keywords != 0 && (channel_keywords & currentMatchAnyKeyword) == 0)
+                        return false;
+                }
+                else
+#endif
+                {
+                    if ((unchecked((ulong)eventKeywords & (ulong)currentMatchAnyKeyword)) == 0)
+                        return false;
+                }
+            }
+            return true;
+
+        }
+        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
+        private void ThrowEventSourceException(string eventName, Exception innerEx = null)
+        {
+            // If we fail during out of band logging we may end up trying 
+            // to throw another EventSourceException, thus hitting a StackOverflowException. 
+            // Avoid StackOverflow by making sure we do not recursively call this method.
+            if (m_EventSourceExceptionRecurenceCount > 0)
+                return;
+            try
+            {
+                m_EventSourceExceptionRecurenceCount++;
+
+                string errorPrefix = "EventSourceException";
+                if (eventName != null)
+                {
+                    errorPrefix += " while processing event \"" + eventName + "\"";
+                }
+
+                // TODO Create variations of EventSourceException that indicate more information using the error code.
+                switch (EventProvider.GetLastWriteEventError())
+                {
+                    case EventProvider.WriteEventErrorCode.EventTooBig:
+                        ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_EventTooBig"), true);
+                        if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_EventTooBig"), innerEx);
+                        break;
+                    case EventProvider.WriteEventErrorCode.NoFreeBuffers:
+                        ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_NoFreeBuffers"), true);
+                        if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_NoFreeBuffers"), innerEx);
+                        break;
+                    case EventProvider.WriteEventErrorCode.NullInput:
+                        ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_NullInput"), true);
+                        if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_NullInput"), innerEx);
+                        break;
+                    case EventProvider.WriteEventErrorCode.TooManyArgs:
+                        ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_TooManyArgs"), true);
+                        if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_TooManyArgs"), innerEx);
+                        break;
+                    default:
+                        if (innerEx != null)
+                            ReportOutOfBandMessage(errorPrefix + ": " + innerEx.GetType() + ":" + innerEx.Message, true);
+                        else
+                            ReportOutOfBandMessage(errorPrefix, true);
+                        if (ThrowOnEventWriteErrors) throw new EventSourceException(innerEx);
+                        break;
+                }
+            }
+            finally
+            {
+                m_EventSourceExceptionRecurenceCount--;
+            }
+        }
+
+        private void ValidateEventOpcodeForTransfer(ref EventMetadata eventData, string eventName)
+        {
+            if ((EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Send &&
+                (EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Receive &&
+                (EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Start)
+            {
+                ThrowEventSourceException(eventName);
+            }
+        }
+
+        internal static EventOpcode GetOpcodeWithDefault(EventOpcode opcode, string eventName)
+        {
+            if (opcode == EventOpcode.Info && eventName != null)
+            {
+                if (eventName.EndsWith(s_ActivityStartSuffix, StringComparison.Ordinal))
+                {
+                    return EventOpcode.Start;
+                }
+                else if (eventName.EndsWith(s_ActivityStopSuffix, StringComparison.Ordinal))
+                {
+                    return EventOpcode.Stop;
+                }
+            }
+
+            return opcode;
+        }
+
+#if FEATURE_MANAGED_ETW
+        /// <summary>
+        /// This class lets us hook the 'OnEventCommand' from the eventSource.  
+        /// </summary>
+        private class OverideEventProvider : EventProvider
+        {
+            public OverideEventProvider(EventSource eventSource)
+            {
+                this.m_eventSource = eventSource;
+            }
+            protected override void OnControllerCommand(ControllerCommand command, IDictionary<string, string> arguments,
+                                                              int perEventSourceSessionId, int etwSessionId)
+            {
+                // We use null to represent the ETW EventListener.  
+                EventListener listener = null;
+                m_eventSource.SendCommand(listener, perEventSourceSessionId, etwSessionId,
+                                          (EventCommand)command, IsEnabled(), Level, MatchAnyKeyword, arguments);
+            }
+            private EventSource m_eventSource;
+        }
+#endif
+
+        /// <summary>
+        /// Used to hold all the static information about an event.  This includes everything in the event
+        /// descriptor as well as some stuff we added specifically for EventSource. see the
+        /// code:m_eventData for where we use this.  
+        /// </summary>
+        internal partial struct EventMetadata
+        {
+            public EventDescriptor Descriptor;
+            public EventTags Tags;
+            public bool EnabledForAnyListener;      // true if any dispatcher has this event turned on
+            public bool EnabledForETW;              // is this event on for the OS ETW data dispatcher?
+
+            public bool HasRelatedActivityID;       // Set if the event method's first parameter is a Guid named 'relatedActivityId'
+#if !FEATURE_ACTIVITYSAMPLING
+#pragma warning disable 0649
+#endif
+            public byte TriggersActivityTracking;   // count of listeners that marked this event as trigger for start of activity logging.
+#if !FEATURE_ACTIVITYSAMPLING
+#pragma warning restore 0649
+#endif
+            public string Name;                     // the name of the event
+            public string Message;                  // If the event has a message associated with it, this is it.  
+            public ParameterInfo[] Parameters;      // TODO can we remove? 
+
+            public TraceLoggingEventTypes TraceLoggingEventTypes;
+            public EventActivityOptions ActivityOptions;
+
+#if ES_BUILD_PN
+            public EventParameterType[] ParameterTypes;
+#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
+        // 
+        // * if Command == Update
+        //     * perEventSourceSessionId specifies the per-provider ETW session ID that the command applies 
+        //         to (if listener != null)
+        //         perEventSourceSessionId = 0 - reserved for EventListeners
+        //         perEventSourceSessionId = 1..SessionMask.MAX - reserved for activity tracing aware ETW sessions
+        //                  perEventSourceSessionId-1 represents the bit in the reserved field (bits 44..47) in 
+        //                  Keywords that identifies the session
+        //         perEventSourceSessionId = SessionMask.MAX+1 - reserved for legacy ETW sessions; these are 
+        //                  discriminated by etwSessionId
+        //     * etwSessionId specifies a machine-wide ETW session ID; this allows correlation of
+        //         activity tracing across different providers (which might have different sessionIds
+        //         for the same ETW session)
+        //     * enable, level, matchAnyKeywords are used to set a default for all events for the
+        //         eventSource.  In particular, if 'enabled' is false, 'level' and
+        //         'matchAnyKeywords' are not used.  
+        //     * OnEventCommand is invoked, which may cause calls to
+        //         code:EventSource.EnableEventForDispatcher which may cause changes in the filtering
+        //         depending on the logic in that routine.
+        // * else (command != Update)
+        //     * Simply call OnEventCommand. The expectation is that filtering is NOT changed.
+        //     * The 'enabled' 'level', matchAnyKeyword' arguments are ignored (must be true, 0, 0).  
+        // 
+        // dispatcher == null has special meaning. It is the 'ETW' dispatcher.
+        internal void SendCommand(EventListener listener, int perEventSourceSessionId, int etwSessionId,
+                                  EventCommand command, bool enable,
+                                  EventLevel level, EventKeywords matchAnyKeyword,
+                                  IDictionary<string, string> commandArguments)
+        {
+            var commandArgs = new EventCommandEventArgs(command, commandArguments, this, listener, perEventSourceSessionId, etwSessionId, enable, level, matchAnyKeyword);
+            lock (EventListener.EventListenersLock)
+            {
+                if (m_completelyInited)
+                {
+                    // After the first command arrive after construction, we are ready to get rid of the deferred commands
+                    this.m_deferredCommands = null;
+                    // We are fully initialized, do the command 
+                    DoCommand(commandArgs);
+                }
+                else
+                {
+                    // We can't do the command, simply remember it and we do it when we are fully constructed.  
+                    commandArgs.nextCommand = m_deferredCommands;
+                    m_deferredCommands = commandArgs;
+                }
+            }
+        }
+
+        /// <summary>
+        /// We want the eventSource to be fully initialized when we do commands because that way we can send 
+        /// error messages and other logging directly to the event stream.   Unfortunately we can get callbacks
+        /// when we are not fully initialized.  In that case we store them in 'commandArgs' and do them later. 
+        /// This helper actually does all actual command logic. 
+        /// </summary>
+        internal void DoCommand(EventCommandEventArgs commandArgs)
+        {
+            // PRECONDITION: We should be holding the EventListener.EventListenersLock
+            // We defer commands until we are completely inited.  This allows error messages to be sent.  
+            Debug.Assert(m_completelyInited);
+
+#if FEATURE_MANAGED_ETW
+            if (m_provider == null)     // If we failed to construct
+                return;
+#endif // FEATURE_MANAGED_ETW
+
+            m_outOfBandMessageCount = 0;
+            bool shouldReport = (commandArgs.perEventSourceSessionId > 0) && (commandArgs.perEventSourceSessionId <= SessionMask.MAX);
+            try
+            {
+                EnsureDescriptorsInitialized();
+                Debug.Assert(m_eventData != null);
+
+                // Find the per-EventSource dispatcher corresponding to registered dispatcher
+                commandArgs.dispatcher = GetDispatcher(commandArgs.listener);
+                if (commandArgs.dispatcher == null && commandArgs.listener != null)     // dispatcher == null means ETW dispatcher
+                {
+                    throw new ArgumentException(Resources.GetResourceString("EventSource_ListenerNotFound"));
+                }
+
+                if (commandArgs.Arguments == null)
+                    commandArgs.Arguments = new Dictionary<string, string>();
+
+                if (commandArgs.Command == EventCommand.Update)
+                {
+                    // Set it up using the 'standard' filtering bitfields (use the "global" enable, not session specific one)
+                    for (int i = 0; i < m_eventData.Length; i++)
+                        EnableEventForDispatcher(commandArgs.dispatcher, i, IsEnabledByDefault(i, commandArgs.enable, commandArgs.level, commandArgs.matchAnyKeyword));
+
+                    if (commandArgs.enable)
+                    {
+                        if (!m_eventSourceEnabled)
+                        {
+                            // EventSource turned on for the first time, simply copy the bits.  
+                            m_level = commandArgs.level;
+                            m_matchAnyKeyword = commandArgs.matchAnyKeyword;
+                        }
+                        else
+                        {
+                            // Already enabled, make it the most verbose of the existing and new filter
+                            if (commandArgs.level > m_level)
+                                m_level = commandArgs.level;
+                            if (commandArgs.matchAnyKeyword == 0)
+                                m_matchAnyKeyword = 0;
+                            else if (m_matchAnyKeyword != 0)
+                                m_matchAnyKeyword = unchecked(m_matchAnyKeyword | commandArgs.matchAnyKeyword);
+                        }
+                    }
+
+                    // interpret perEventSourceSessionId's sign, and adjust perEventSourceSessionId to 
+                    // represent 0-based positive values
+                    bool bSessionEnable = (commandArgs.perEventSourceSessionId >= 0);
+                    if (commandArgs.perEventSourceSessionId == 0 && commandArgs.enable == false)
+                        bSessionEnable = false;
+
+                    if (commandArgs.listener == null)
+                    {
+                        if (!bSessionEnable)
+                            commandArgs.perEventSourceSessionId = -commandArgs.perEventSourceSessionId;
+                        // for "global" enable/disable (passed in with listener == null and
+                        //  perEventSourceSessionId == 0) perEventSourceSessionId becomes -1
+                        --commandArgs.perEventSourceSessionId;
+                    }
+
+                    commandArgs.Command = bSessionEnable ? EventCommand.Enable : EventCommand.Disable;
+
+                    // perEventSourceSessionId = -1 when ETW sent a notification, but the set of active sessions
+                    // hasn't changed.
+                    // sesisonId = SessionMask.MAX when one of the legacy ETW sessions changed
+                    // 0 <= perEventSourceSessionId < SessionMask.MAX for activity-tracing aware sessions
+                    Debug.Assert(commandArgs.perEventSourceSessionId >= -1 && commandArgs.perEventSourceSessionId <= SessionMask.MAX);
+
+                    // Send the manifest if we are enabling an ETW session
+                    if (bSessionEnable && commandArgs.dispatcher == null)
+                    {
+                        // eventSourceDispatcher == null means this is the ETW manifest
+
+                        // Note that we unconditionally send the manifest whenever we are enabled, even if
+                        // we were already enabled.   This is because there may be multiple sessions active
+                        // and we can't know that all the sessions have seen the manifest.  
+                        if (!SelfDescribingEvents)
+                            SendManifest(m_rawManifest);
+                    }
+
+#if FEATURE_ACTIVITYSAMPLING
+                    if (bSessionEnable && commandArgs.perEventSourceSessionId != -1)
+                    {
+                        bool participateInSampling = false;
+                        string activityFilters;
+                        int sessionIdBit;
+
+                        ParseCommandArgs(commandArgs.Arguments, out participateInSampling,
+                                            out activityFilters, out sessionIdBit);
+
+                        if (commandArgs.listener == null && commandArgs.Arguments.Count > 0 && commandArgs.perEventSourceSessionId != sessionIdBit)
+                        {
+                            throw new ArgumentException(Resources.GetResourceString("EventSource_SessionIdError",
+                                                    commandArgs.perEventSourceSessionId + SessionMask.SHIFT_SESSION_TO_KEYWORD,
+                                                        sessionIdBit + SessionMask.SHIFT_SESSION_TO_KEYWORD));
+                        }
+
+                        if (commandArgs.listener == null)
+                        {
+                            UpdateEtwSession(commandArgs.perEventSourceSessionId, commandArgs.etwSessionId, true, activityFilters, participateInSampling);
+                        }
+                        else
+                        {
+                            ActivityFilter.UpdateFilter(ref commandArgs.listener.m_activityFilter, this, 0, activityFilters);
+                            commandArgs.dispatcher.m_activityFilteringEnabled = participateInSampling;
+                        }
+                    }
+                    else if (!bSessionEnable && commandArgs.listener == null)
+                    {
+                        // if we disable an ETW session, indicate that in a synthesized command argument
+                        if (commandArgs.perEventSourceSessionId >= 0 && commandArgs.perEventSourceSessionId < SessionMask.MAX)
+                        {
+                            commandArgs.Arguments["EtwSessionKeyword"] = (commandArgs.perEventSourceSessionId + SessionMask.SHIFT_SESSION_TO_KEYWORD).ToString(CultureInfo.InvariantCulture);
+                        }
+                    }
+#endif // FEATURE_ACTIVITYSAMPLING
+
+                    // Turn on the enable bit before making the OnEventCommand callback  This allows you to do useful
+                    // things like log messages, or test if keywords are enabled in the callback.  
+                    if (commandArgs.enable)
+                    {
+                        Debug.Assert(m_eventData != null);
+                        m_eventSourceEnabled = true;
+                    }
+
+                    this.OnEventCommand(commandArgs);
+                    var eventCommandCallback = this.m_eventCommandExecuted;
+                    if (eventCommandCallback != null)
+                        eventCommandCallback(this, commandArgs);
+
+#if FEATURE_ACTIVITYSAMPLING
+                    if (commandArgs.listener == null && !bSessionEnable && commandArgs.perEventSourceSessionId != -1)
+                    {
+                        // if we disable an ETW session, complete disabling it
+                        UpdateEtwSession(commandArgs.perEventSourceSessionId, commandArgs.etwSessionId, false, null, false);
+                    }
+#endif // FEATURE_ACTIVITYSAMPLING
+
+                    if (!commandArgs.enable)
+                    {
+                        // If we are disabling, maybe we can turn on 'quick checks' to filter
+                        // quickly.  These are all just optimizations (since later checks will still filter)
+
+#if FEATURE_ACTIVITYSAMPLING
+                        // Turn off (and forget) any information about Activity Tracing.  
+                        if (commandArgs.listener == null)
+                        {
+                            // reset all filtering information for activity-tracing-aware sessions
+                            for (int i = 0; i < SessionMask.MAX; ++i)
+                            {
+                                EtwSession etwSession = m_etwSessionIdMap[i];
+                                if (etwSession != null)
+                                    ActivityFilter.DisableFilter(ref etwSession.m_activityFilter, this);
+                            }
+                            m_activityFilteringForETWEnabled = new SessionMask(0);
+                            m_curLiveSessions = new SessionMask(0);
+                            // reset activity-tracing-aware sessions
+                            if (m_etwSessionIdMap != null)
+                                for (int i = 0; i < SessionMask.MAX; ++i)
+                                    m_etwSessionIdMap[i] = null;
+                            // reset legacy sessions
+                            if (m_legacySessions != null)
+                                m_legacySessions.Clear();
+                        }
+                        else
+                        {
+                            ActivityFilter.DisableFilter(ref commandArgs.listener.m_activityFilter, this);
+                            commandArgs.dispatcher.m_activityFilteringEnabled = false;
+                        }
+#endif // FEATURE_ACTIVITYSAMPLING
+
+                        // There is a good chance EnabledForAnyListener are not as accurate as
+                        // they could be, go ahead and get a better estimate.  
+                        for (int i = 0; i < m_eventData.Length; i++)
+                        {
+                            bool isEnabledForAnyListener = false;
+                            for (EventDispatcher dispatcher = m_Dispatchers; dispatcher != null; dispatcher = dispatcher.m_Next)
+                            {
+                                if (dispatcher.m_EventEnabled[i])
+                                {
+                                    isEnabledForAnyListener = true;
+                                    break;
+                                }
+                            }
+                            m_eventData[i].EnabledForAnyListener = isEnabledForAnyListener;
+                        }
+
+                        // If no events are enabled, disable the global enabled bit.
+                        if (!AnyEventEnabled())
+                        {
+                            m_level = 0;
+                            m_matchAnyKeyword = 0;
+                            m_eventSourceEnabled = false;
+                        }
+                    }
+#if FEATURE_ACTIVITYSAMPLING
+                    UpdateKwdTriggers(commandArgs.enable);
+#endif // FEATURE_ACTIVITYSAMPLING
+                }
+                else
+                {
+                    if (commandArgs.Command == EventCommand.SendManifest)
+                    {
+                        // TODO: should we generate the manifest here if we hadn't already?
+                        if (m_rawManifest != null)
+                            SendManifest(m_rawManifest);
+                    }
+
+                    // These are not used for non-update commands and thus should always be 'default' values
+                    // Debug.Assert(enable == true);
+                    // Debug.Assert(level == EventLevel.LogAlways);
+                    // Debug.Assert(matchAnyKeyword == EventKeywords.None);
+
+                    this.OnEventCommand(commandArgs);
+                    var eventCommandCallback = m_eventCommandExecuted;
+                    if (eventCommandCallback != null)
+                        eventCommandCallback(this, commandArgs);
+                }
+
+#if FEATURE_ACTIVITYSAMPLING
+                if (m_completelyInited && (commandArgs.listener != null || shouldReport))
+                {
+                    SessionMask m = SessionMask.FromId(commandArgs.perEventSourceSessionId);
+                    ReportActivitySamplingInfo(commandArgs.listener, m);
+                }
+#endif // FEATURE_ACTIVITYSAMPLING
+            }
+            catch (Exception e)
+            {
+                // When the ETW session is created after the EventSource has registered with the ETW system
+                // we can send any error messages here.
+                ReportOutOfBandMessage("ERROR: Exception in Command Processing for EventSource " + Name + ": " + e.Message, true);
+                // We never throw when doing a command.  
+            }
+        }
+
+#if FEATURE_ACTIVITYSAMPLING
+
+        internal void UpdateEtwSession(
+            int sessionIdBit,
+            int etwSessionId,
+            bool bEnable,
+            string activityFilters,
+            bool participateInSampling)
+        {
+            if (sessionIdBit < SessionMask.MAX)
+            {
+                // activity-tracing-aware etw session
+                if (bEnable)
+                {
+                    var etwSession = EtwSession.GetEtwSession(etwSessionId, true);
+                    ActivityFilter.UpdateFilter(ref etwSession.m_activityFilter, this, sessionIdBit, activityFilters);
+                    m_etwSessionIdMap[sessionIdBit] = etwSession;
+                    m_activityFilteringForETWEnabled[sessionIdBit] = participateInSampling;
+                }
+                else
+                {
+                    var etwSession = EtwSession.GetEtwSession(etwSessionId);
+                    m_etwSessionIdMap[sessionIdBit] = null;
+                    m_activityFilteringForETWEnabled[sessionIdBit] = false;
+                    if (etwSession != null)
+                    {
+                        ActivityFilter.DisableFilter(ref etwSession.m_activityFilter, this);
+                        // the ETW session is going away; remove it from the global list
+                        EtwSession.RemoveEtwSession(etwSession);
+                    }
+                }
+                m_curLiveSessions[sessionIdBit] = bEnable;
+            }
+            else
+            {
+                // legacy etw session    
+                if (bEnable)
+                {
+                    if (m_legacySessions == null)
+                        m_legacySessions = new List<EtwSession>(8);
+                    var etwSession = EtwSession.GetEtwSession(etwSessionId, true);
+                    if (!m_legacySessions.Contains(etwSession))
+                        m_legacySessions.Add(etwSession);
+                }
+                else
+                {
+                    var etwSession = EtwSession.GetEtwSession(etwSessionId);
+                    if (etwSession != null)
+                    {
+                        if (m_legacySessions != null)
+                            m_legacySessions.Remove(etwSession);
+                        // the ETW session is going away; remove it from the global list
+                        EtwSession.RemoveEtwSession(etwSession);
+                    }
+                }
+            }
+        }
+
+        internal static bool ParseCommandArgs(
+                        IDictionary<string, string> commandArguments,
+                        out bool participateInSampling,
+                        out string activityFilters,
+                        out int sessionIdBit)
+        {
+            bool res = true;
+            participateInSampling = false;
+            string activityFilterString;
+            if (commandArguments.TryGetValue("ActivitySamplingStartEvent", out activityFilters))
+            {
+                // if a start event is specified default the event source to participate in sampling
+                participateInSampling = true;
+            }
+
+            if (commandArguments.TryGetValue("ActivitySampling", out activityFilterString))
+            {
+                if (string.Compare(activityFilterString, "false", StringComparison.OrdinalIgnoreCase) == 0 ||
+                    activityFilterString == "0")
+                    participateInSampling = false;
+                else
+                    participateInSampling = true;
+            }
+
+            string sSessionKwd;
+            int sessionKwd = -1;
+            if (!commandArguments.TryGetValue("EtwSessionKeyword", out sSessionKwd) ||
+                !int.TryParse(sSessionKwd, out sessionKwd) ||
+                sessionKwd < SessionMask.SHIFT_SESSION_TO_KEYWORD ||
+                sessionKwd >= SessionMask.SHIFT_SESSION_TO_KEYWORD + SessionMask.MAX)
+            {
+                sessionIdBit = -1;
+                res = false;
+            }
+            else
+            {
+                sessionIdBit = sessionKwd - SessionMask.SHIFT_SESSION_TO_KEYWORD;
+            }
+            return res;
+        }
+
+        internal void UpdateKwdTriggers(bool enable)
+        {
+            if (enable)
+            {
+                // recompute m_keywordTriggers
+                ulong gKeywords = unchecked((ulong)m_matchAnyKeyword);
+                if (gKeywords == 0)
+                    gKeywords = 0xFFFFffffFFFFffff;
+
+                m_keywordTriggers = 0;
+                for (int sessId = 0; sessId < SessionMask.MAX; ++sessId)
+                {
+                    EtwSession etwSession = m_etwSessionIdMap[sessId];
+                    if (etwSession == null)
+                        continue;
+
+                    ActivityFilter activityFilter = etwSession.m_activityFilter;
+                    ActivityFilter.UpdateKwdTriggers(activityFilter, m_guid, this, unchecked((EventKeywords)gKeywords));
+                }
+            }
+            else
+            {
+                m_keywordTriggers = 0;
+            }
+        }
+
+#endif // FEATURE_ACTIVITYSAMPLING
+
+        /// <summary>
+        /// If 'value is 'true' then set the eventSource so that 'dispatcher' will receive event with the eventId
+        /// of 'eventId.  If value is 'false' disable the event for that dispatcher.   If 'eventId' is out of
+        /// range return false, otherwise true.  
+        /// </summary>
+        internal bool EnableEventForDispatcher(EventDispatcher dispatcher, int eventId, bool value)
+        {
+            if (dispatcher == null)
+            {
+                if (eventId >= m_eventData.Length)
+                    return false;
+#if FEATURE_MANAGED_ETW
+                if (m_provider != null)
+                    m_eventData[eventId].EnabledForETW = value;
+#endif
+            }
+            else
+            {
+                if (eventId >= dispatcher.m_EventEnabled.Length)
+                    return false;
+                dispatcher.m_EventEnabled[eventId] = value;
+                if (value)
+                    m_eventData[eventId].EnabledForAnyListener = true;
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Returns true if any event at all is on.  
+        /// </summary>
+        private bool AnyEventEnabled()
+        {
+            for (int i = 0; i < m_eventData.Length; i++)
+                if (m_eventData[i].EnabledForETW || m_eventData[i].EnabledForAnyListener)
+                    return true;
+            return false;
+        }
+
+        private bool IsDisposed
+        {
+            get { return m_eventSourceDisposed; }
+        }
+
+        private void EnsureDescriptorsInitialized()
+        {
+#if !ES_BUILD_STANDALONE
+            Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
+#endif
+            if (m_eventData == null)
+            {
+                Guid eventSourceGuid = Guid.Empty;
+                string eventSourceName = null;
+                EventMetadata[] eventData = null;
+                byte[] manifest = null;
+
+                // Try the GetMetadata provided by the ILTransform in ProjectN. The default sets all to null, and in that case we fall back
+                // to the reflection approach.
+                GetMetadata(out eventSourceGuid, out eventSourceName, out eventData, out manifest);
+
+                if (eventSourceGuid.Equals(Guid.Empty) || eventSourceName == null || eventData == null || manifest == null)
+                {
+                    // GetMetadata failed, so we have to set it via reflection.
+                    Debug.Assert(m_rawManifest == null);
+                    m_rawManifest = CreateManifestAndDescriptors(this.GetType(), Name, this);
+                    Debug.Assert(m_eventData != null);
+
+                }
+                else
+                {
+                    // GetMetadata worked, so set the fields as appropriate.
+                    m_name = eventSourceName;
+                    m_guid = eventSourceGuid;
+                    m_eventData = eventData;
+                    m_rawManifest = manifest;
+                }
+                // TODO Enforce singleton pattern 
+                foreach (WeakReference eventSourceRef in EventListener.s_EventSources)
+                {
+                    EventSource eventSource = eventSourceRef.Target as EventSource;
+                    if (eventSource != null && eventSource.Guid == m_guid && !eventSource.IsDisposed)
+                    {
+                        if (eventSource != this)
+                        {
+                            throw new ArgumentException(Resources.GetResourceString("EventSource_EventSourceGuidInUse", m_guid));
+                        }
+                    }
+                }
+
+                // Make certain all dispatchers also have their arrays initialized
+                EventDispatcher dispatcher = m_Dispatchers;
+                while (dispatcher != null)
+                {
+                    if (dispatcher.m_EventEnabled == null)
+                        dispatcher.m_EventEnabled = new bool[m_eventData.Length];
+                    dispatcher = dispatcher.m_Next;
+                }
+            }
+            if (s_currentPid == 0)
+            {
+#if ES_BUILD_STANDALONE && !ES_BUILD_PCL && !CORECLR
+                // for non-BCL EventSource we must assert SecurityPermission
+                new SecurityPermission(PermissionState.Unrestricted).Assert();
+#endif
+                s_currentPid = Win32Native.GetCurrentProcessId();
+            }
+        }
+
+        // Send out the ETW manifest XML out to ETW
+        // Today, we only send the manifest to ETW, custom listeners don't get it. 
+        private unsafe bool SendManifest(byte[] rawManifest)
+        {
+            bool success = true;
+
+            if (rawManifest == null)
+                return false;
+
+            Debug.Assert(!SelfDescribingEvents);
+
+#if FEATURE_MANAGED_ETW
+            fixed (byte* dataPtr = rawManifest)
+            {
+                // we don't want the manifest to show up in the event log channels so we specify as keywords 
+                // everything but the first 8 bits (reserved for the 8 channels)
+                var manifestDescr = new EventDescriptor(0xFFFE, 1, 0, 0, 0xFE, 0xFFFE, 0x00ffFFFFffffFFFF);
+                ManifestEnvelope envelope = new ManifestEnvelope();
+
+                envelope.Format = ManifestEnvelope.ManifestFormats.SimpleXmlFormat;
+                envelope.MajorVersion = 1;
+                envelope.MinorVersion = 0;
+                envelope.Magic = 0x5B;              // An unusual number that can be checked for consistency. 
+                int dataLeft = rawManifest.Length;
+                envelope.ChunkNumber = 0;
+
+                EventProvider.EventData* dataDescrs = stackalloc EventProvider.EventData[2];
+
+                dataDescrs[0].Ptr = (ulong)&envelope;
+                dataDescrs[0].Size = (uint)sizeof(ManifestEnvelope);
+                dataDescrs[0].Reserved = 0;
+
+                dataDescrs[1].Ptr = (ulong)dataPtr;
+                dataDescrs[1].Reserved = 0;
+
+                int chunkSize = ManifestEnvelope.MaxChunkSize;
+                TRY_AGAIN_WITH_SMALLER_CHUNK_SIZE:
+                envelope.TotalChunks = (ushort)((dataLeft + (chunkSize - 1)) / chunkSize);
+                while (dataLeft > 0)
+                {
+                    dataDescrs[1].Size = (uint)Math.Min(dataLeft, chunkSize);
+                    if (m_provider != null)
+                    {
+                        if (!m_provider.WriteEvent(ref manifestDescr, null, null, 2, (IntPtr)dataDescrs))
+                        {
+                            // Turns out that if users set the BufferSize to something less than 64K then WriteEvent
+                            // can fail.   If we get this failure on the first chunk try again with something smaller
+                            // The smallest BufferSize is 1K so if we get to 256 (to account for envelope overhead), we can give up making it smaller. 
+                            if (EventProvider.GetLastWriteEventError() == EventProvider.WriteEventErrorCode.EventTooBig)
+                            {
+                                if (envelope.ChunkNumber == 0 && chunkSize > 256)
+                                {
+                                    chunkSize = chunkSize / 2;
+                                    goto TRY_AGAIN_WITH_SMALLER_CHUNK_SIZE;
+                                }
+                            }
+                            success = false;
+                            if (ThrowOnEventWriteErrors)
+                                ThrowEventSourceException("SendManifest");
+                            break;
+                        }
+                    }
+                    dataLeft -= chunkSize;
+                    dataDescrs[1].Ptr += (uint)chunkSize;
+                    envelope.ChunkNumber++;
+
+                    // For large manifests we want to not overflow any receiver's buffer. Most manifests will fit within
+                    // 5 chunks, so only the largest manifests will hit the pause.
+                    if ((envelope.ChunkNumber % 5) == 0)
+                    {
+                        RuntimeThread.Sleep(15);
+                    }
+                }
+            }
+#endif // FEATURE_MANAGED_ETW
+            return success;
+        }
+
+#if (ES_BUILD_PCL)
+        internal static Attribute GetCustomAttributeHelper(Type type, Type attributeType, EventManifestOptions flags = EventManifestOptions.None)
+        {
+            return GetCustomAttributeHelper(type.GetTypeInfo(), attributeType, flags);
+        }
+#endif
+
+        // Helper to deal with the fact that the type we are reflecting over might be loaded in the ReflectionOnly context.
+        // When that is the case, we have the build the custom assemblies on a member by hand.         
+        internal static Attribute GetCustomAttributeHelper(MemberInfo member, Type attributeType, EventManifestOptions flags = EventManifestOptions.None)
+        {
+            if (!member.Module.Assembly.ReflectionOnly() && (flags & EventManifestOptions.AllowEventSourceOverride) == 0)
+            {
+                // Let the runtime to the work for us, since we can execute code in this context.
+                Attribute firstAttribute = null;
+                foreach (var attribute in member.GetCustomAttributes(attributeType, false))
+                {
+                    firstAttribute = (Attribute)attribute;
+                    break;
+                }
+                return firstAttribute;
+            }
+
+#if (!ES_BUILD_PCL && !ES_BUILD_PN)
+            // In the reflection only context, we have to do things by hand.
+            string fullTypeNameToFind = attributeType.FullName;
+
+#if EVENT_SOURCE_LEGACY_NAMESPACE_SUPPORT
+            fullTypeNameToFind = fullTypeNameToFind.Replace("System.Diagnostics.Eventing", "System.Diagnostics.Tracing");
+#endif
+
+            foreach (CustomAttributeData data in CustomAttributeData.GetCustomAttributes(member))
+            {
+                if (AttributeTypeNamesMatch(attributeType, data.Constructor.ReflectedType))
+                {
+                    Attribute attr = null;
+
+                    Debug.Assert(data.ConstructorArguments.Count <= 1);
+
+                    if (data.ConstructorArguments.Count == 1)
+                    {
+                        attr = (Attribute)Activator.CreateInstance(attributeType, new object[] { data.ConstructorArguments[0].Value });
+                    }
+                    else if (data.ConstructorArguments.Count == 0)
+                    {
+                        attr = (Attribute)Activator.CreateInstance(attributeType);
+                    }
+
+                    if (attr != null)
+                    {
+                        Type t = attr.GetType();
+
+                        foreach (CustomAttributeNamedArgument namedArgument in data.NamedArguments)
+                        {
+                            PropertyInfo p = t.GetProperty(namedArgument.MemberInfo.Name, BindingFlags.Public | BindingFlags.Instance);
+                            object value = namedArgument.TypedValue.Value;
+
+                            if (p.PropertyType.IsEnum)
+                            {
+                                value = Enum.Parse(p.PropertyType, value.ToString());
+                            }
+
+                            p.SetValue(attr, value, null);
+                        }
+
+                        return attr;
+                    }
+                }
+            }
+
+            return null;
+#else // ES_BUILD_PCL && ES_BUILD_PN
+            // Don't use nameof here because the resource doesn't exist on some platforms, which results in a compilation error.
+            throw new ArgumentException(Resources.GetResourceString("EventSource", "EventSource_PCLPlatformNotSupportedReflection"));
+#endif
+        }
+
+        /// <summary>
+        /// Evaluates if two related "EventSource"-domain types should be considered the same
+        /// </summary>
+        /// <param name="attributeType">The attribute type in the load context - it's associated with the running 
+        /// EventSource type. This type may be different fromt he base type of the user-defined EventSource.</param>
+        /// <param name="reflectedAttributeType">The attribute type in the reflection context - it's associated with
+        /// the user-defined EventSource, and is in the same assembly as the eventSourceType passed to 
+        /// </param>
+        /// <returns>True - if the types should be considered equivalent, False - otherwise</returns>
+        private static bool AttributeTypeNamesMatch(Type attributeType, Type reflectedAttributeType)
+        {
+            return
+                // are these the same type?
+                attributeType == reflectedAttributeType ||
+                // are the full typenames equal?
+                string.Equals(attributeType.FullName, reflectedAttributeType.FullName, StringComparison.Ordinal) ||
+                    // are the typenames equal and the namespaces under "Diagnostics.Tracing" (typically
+                    // either Microsoft.Diagnostics.Tracing or System.Diagnostics.Tracing)?
+                    string.Equals(attributeType.Name, reflectedAttributeType.Name, StringComparison.Ordinal) &&
+                    attributeType.Namespace.EndsWith("Diagnostics.Tracing", StringComparison.Ordinal) &&
+                    (reflectedAttributeType.Namespace.EndsWith("Diagnostics.Tracing", StringComparison.Ordinal)
+#if EVENT_SOURCE_LEGACY_NAMESPACE_SUPPORT
+                     || reflectedAttributeType.Namespace.EndsWith("Diagnostics.Eventing", StringComparison.Ordinal)
+#endif
+);
+        }
+
+        private static Type GetEventSourceBaseType(Type eventSourceType, bool allowEventSourceOverride, bool reflectionOnly)
+        {
+            // return false for "object" and interfaces
+            if (eventSourceType.BaseType() == null)
+                return null;
+
+            // now go up the inheritance chain until hitting a concrete type ("object" at worse)
+            do
+            {
+                eventSourceType = eventSourceType.BaseType();
+            }
+            while (eventSourceType != null && eventSourceType.IsAbstract());
+
+            if (eventSourceType != null)
+            {
+                if (!allowEventSourceOverride)
+                {
+                    if (reflectionOnly && eventSourceType.FullName != typeof(EventSource).FullName ||
+                        !reflectionOnly && eventSourceType != typeof(EventSource))
+                        return null;
+                }
+                else
+                {
+                    if (eventSourceType.Name != "EventSource")
+                        return null;
+                }
+            }
+            return eventSourceType;
+        }
+
+        // Use reflection to look at the attributes of a class, and generate a manifest for it (as UTF8) and
+        // return the UTF8 bytes.  It also sets up the code:EventData structures needed to dispatch events
+        // at run time.  'source' is the event source to place the descriptors.  If it is null,
+        // then the descriptors are not creaed, and just the manifest is generated.  
+        private static byte[] CreateManifestAndDescriptors(Type eventSourceType, string eventSourceDllName, EventSource source,
+            EventManifestOptions flags = EventManifestOptions.None)
+        {
+            ManifestBuilder manifest = null;
+            bool bNeedsManifest = source != null ? !source.SelfDescribingEvents : true;
+            Exception exception = null; // exception that might get raised during validation b/c we couldn't/didn't recover from a previous error
+            byte[] res = null;
+
+            if (eventSourceType.IsAbstract() && (flags & EventManifestOptions.Strict) == 0)
+                return null;
+
+#if DEBUG && ES_BUILD_STANDALONE
+            TestSupport.TestHooks.MaybeThrow(eventSourceType,
+                                        TestSupport.Category.ManifestError,
+                                        "EventSource_CreateManifestAndDescriptors",
+                                        new ArgumentException("EventSource_CreateManifestAndDescriptors"));
+#endif
+
+            try
+            {
+                MethodInfo[] methods = eventSourceType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
+                EventAttribute defaultEventAttribute;
+                int eventId = 1;        // The number given to an event that does not have a explicitly given ID. 
+                EventMetadata[] eventData = null;
+                Dictionary<string, string> eventsByName = null;
+                if (source != null || (flags & EventManifestOptions.Strict) != 0)
+                {
+                    eventData = new EventMetadata[methods.Length + 1];
+                    eventData[0].Name = "";         // Event 0 is the 'write messages string' event, and has an empty name.
+                }
+
+                // See if we have localization information.  
+                ResourceManager resources = null;
+                EventSourceAttribute eventSourceAttrib = (EventSourceAttribute)GetCustomAttributeHelper(eventSourceType, typeof(EventSourceAttribute), flags);
+                if (eventSourceAttrib != null && eventSourceAttrib.LocalizationResources != null)
+                    resources = new ResourceManager(eventSourceAttrib.LocalizationResources, eventSourceType.Assembly());
+
+                manifest = new ManifestBuilder(GetName(eventSourceType, flags), GetGuid(eventSourceType), eventSourceDllName,
+                                               resources, flags);
+
+                // Add an entry unconditionally for event ID 0 which will be for a string message.  
+                manifest.StartEvent("EventSourceMessage", new EventAttribute(0) { Level = EventLevel.LogAlways, Task = (EventTask)0xFFFE });
+                manifest.AddEventParameter(typeof(string), "message");
+                manifest.EndEvent();
+
+                // eventSourceType must be sealed and must derive from this EventSource
+                if ((flags & EventManifestOptions.Strict) != 0)
+                {
+                    bool typeMatch = GetEventSourceBaseType(eventSourceType, (flags & EventManifestOptions.AllowEventSourceOverride) != 0, eventSourceType.Assembly().ReflectionOnly()) != null;
+
+                    if (!typeMatch)
+                    {
+                        manifest.ManifestError(Resources.GetResourceString("EventSource_TypeMustDeriveFromEventSource"));
+                    }
+                    if (!eventSourceType.IsAbstract() && !eventSourceType.IsSealed())
+                    {
+                        manifest.ManifestError(Resources.GetResourceString("EventSource_TypeMustBeSealedOrAbstract"));
+                    }
+                }
+
+                // Collect task, opcode, keyword and channel information
+#if FEATURE_MANAGED_ETW_CHANNELS && FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
+                foreach (var providerEnumKind in new string[] { "Keywords", "Tasks", "Opcodes", "Channels" })
+#else
+                foreach (var providerEnumKind in new string[] { "Keywords", "Tasks", "Opcodes" })
+#endif
+                {
+                    Type nestedType = eventSourceType.GetNestedType(providerEnumKind);
+                    if (nestedType != null)
+                    {
+                        if (eventSourceType.IsAbstract())
+                        {
+                            manifest.ManifestError(Resources.GetResourceString("EventSource_AbstractMustNotDeclareKTOC", nestedType.Name));
+                        }
+                        else
+                        {
+                            foreach (FieldInfo staticField in nestedType.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static))
+                            {
+                                AddProviderEnumKind(manifest, staticField, providerEnumKind);
+                            }
+                        }
+                    }
+                }
+                // ensure we have keywords for the session-filtering reserved bits
+                {
+                    manifest.AddKeyword("Session3", (long)0x1000 << 32);
+                    manifest.AddKeyword("Session2", (long)0x2000 << 32);
+                    manifest.AddKeyword("Session1", (long)0x4000 << 32);
+                    manifest.AddKeyword("Session0", (long)0x8000 << 32);
+                }
+
+                if (eventSourceType != typeof(EventSource))
+                {
+                    for (int i = 0; i < methods.Length; i++)
+                    {
+                        MethodInfo method = methods[i];
+                        ParameterInfo[] args = method.GetParameters();
+
+                        // Get the EventDescriptor (from the Custom attributes)
+                        EventAttribute eventAttribute = (EventAttribute)GetCustomAttributeHelper(method, typeof(EventAttribute), flags);
+
+                        // Compat: until v4.5.1 we ignored any non-void returning methods as well as virtual methods for 
+                        // the only reason of limiting the number of methods considered to be events. This broke a common 
+                        // design of having event sources implement specific interfaces. To fix this in a compatible way
+                        // we will now allow both non-void returning and virtual methods to be Event methods, as long 
+                        // as they are marked with the [Event] attribute
+                        if (/* method.IsVirtual || */ method.IsStatic)
+                        {
+                            continue;
+                        }
+
+                        if (eventSourceType.IsAbstract())
+                        {
+                            if (eventAttribute != null)
+                            {
+                                manifest.ManifestError(Resources.GetResourceString("EventSource_AbstractMustNotDeclareEventMethods", method.Name, eventAttribute.EventId));
+                            }
+                            continue;
+                        }
+                        else if (eventAttribute == null)
+                        {
+                            // Methods that don't return void can't be events, if they're NOT marked with [Event].
+                            // (see Compat comment above)
+                            if (method.ReturnType != typeof(void))
+                            {
+                                continue;
+                            }
+
+                            // Continue to ignore virtual methods if they do NOT have the [Event] attribute
+                            // (see Compat comment above)
+                            if (method.IsVirtual)
+                            {
+                                continue;
+                            }
+
+                            // If we explicitly mark the method as not being an event, then honor that.  
+                            if (GetCustomAttributeHelper(method, typeof(NonEventAttribute), flags) != null)
+                                continue;
+
+                            defaultEventAttribute = new EventAttribute(eventId);
+                            eventAttribute = defaultEventAttribute;
+                        }
+                        else if (eventAttribute.EventId <= 0)
+                        {
+                            manifest.ManifestError(Resources.GetResourceString("EventSource_NeedPositiveId", method.Name), true);
+                            continue;   // don't validate anything else for this event
+                        }
+                        if (method.Name.LastIndexOf('.') >= 0)
+                        {
+                            manifest.ManifestError(Resources.GetResourceString("EventSource_EventMustNotBeExplicitImplementation", method.Name, eventAttribute.EventId));
+                        }
+
+                        eventId++;
+                        string eventName = method.Name;
+
+                        if (eventAttribute.Opcode == EventOpcode.Info)      // We are still using the default opcode. 
+                        {
+                            // By default pick a task ID derived from the EventID, starting with the highest task number and working back 
+                            bool noTask = (eventAttribute.Task == EventTask.None);
+                            if (noTask)
+                                eventAttribute.Task = (EventTask)(0xFFFE - eventAttribute.EventId);
+
+                            // Unless we explicitly set the opcode to Info (to override the auto-generate of Start or Stop opcodes, 
+                            // pick a default opcode based on the event name (either Info or start or stop if the name ends with that suffix).  
+                            if (!eventAttribute.IsOpcodeSet)
+                                eventAttribute.Opcode = GetOpcodeWithDefault(EventOpcode.Info, eventName);
+
+                            // Make the stop opcode have the same task as the start opcode.
+                            if (noTask)
+                            {
+                                if (eventAttribute.Opcode == EventOpcode.Start)
+                                {
+                                    string taskName = eventName.Substring(0, eventName.Length - s_ActivityStartSuffix.Length); // Remove the Stop suffix to get the task name
+                                    if (string.Compare(eventName, 0, taskName, 0, taskName.Length) == 0 &&
+                                        string.Compare(eventName, taskName.Length, s_ActivityStartSuffix, 0, Math.Max(eventName.Length - taskName.Length, s_ActivityStartSuffix.Length)) == 0)
+                                    {
+                                        // Add a task that is just the task name for the start event.   This suppress the auto-task generation
+                                        // That would otherwise happen (and create 'TaskName'Start as task name rather than just 'TaskName'
+                                        manifest.AddTask(taskName, (int)eventAttribute.Task);
+                                    }
+                                }
+                                else if (eventAttribute.Opcode == EventOpcode.Stop)
+                                {
+                                    // Find the start associated with this stop event.  We require start to be immediately before the stop
+                                    int startEventId = eventAttribute.EventId - 1;
+                                    if (eventData != null && startEventId < eventData.Length)
+                                    {
+                                        Debug.Assert(0 <= startEventId);                // Since we reserve id 0, we know that id-1 is <= 0
+                                        EventMetadata startEventMetadata = eventData[startEventId];
+
+                                        // If you remove the Stop and add a Start does that name match the Start Event's Name?
+                                        // Ideally we would throw an error 
+                                        string taskName = eventName.Substring(0, eventName.Length - s_ActivityStopSuffix.Length); // Remove the Stop suffix to get the task name
+                                        if (startEventMetadata.Descriptor.Opcode == (byte)EventOpcode.Start &&
+                                            string.Compare(startEventMetadata.Name, 0, taskName, 0, taskName.Length) == 0 &&
+                                            string.Compare(startEventMetadata.Name, taskName.Length, s_ActivityStartSuffix, 0, Math.Max(startEventMetadata.Name.Length - taskName.Length, s_ActivityStartSuffix.Length)) == 0)
+                                        {
+
+                                            // Make the stop event match the start event
+                                            eventAttribute.Task = (EventTask)startEventMetadata.Descriptor.Task;
+                                            noTask = false;
+                                        }
+                                    }
+                                    if (noTask && (flags & EventManifestOptions.Strict) != 0)        // Throw an error if we can compatibly.   
+                                    {
+                                        throw new ArgumentException(Resources.GetResourceString("EventSource_StopsFollowStarts"));
+                                    }
+                                }
+                            }
+                        }
+
+                        bool hasRelatedActivityID = RemoveFirstArgIfRelatedActivityId(ref args);
+                        if (!(source != null && source.SelfDescribingEvents))
+                        {
+                            manifest.StartEvent(eventName, eventAttribute);
+                            for (int fieldIdx = 0; fieldIdx < args.Length; fieldIdx++)
+                            {
+                                manifest.AddEventParameter(args[fieldIdx].ParameterType, args[fieldIdx].Name);
+                            }
+                            manifest.EndEvent();
+                        }
+
+                        if (source != null || (flags & EventManifestOptions.Strict) != 0)
+                        {
+                            // Do checking for user errors (optional, but not a big deal so we do it).  
+                            DebugCheckEvent(ref eventsByName, eventData, method, eventAttribute, manifest, flags);
+
+#if FEATURE_MANAGED_ETW_CHANNELS
+                            // add the channel keyword for Event Viewer channel based filters. This is added for creating the EventDescriptors only
+                            // and is not required for the manifest
+                            if (eventAttribute.Channel != EventChannel.None)
+                            {
+                                unchecked
+                                {
+                                    eventAttribute.Keywords |= (EventKeywords)manifest.GetChannelKeyword(eventAttribute.Channel, (ulong)eventAttribute.Keywords);
+                                }
+                            }
+#endif
+                            string eventKey = "event_" + eventName;
+                            string msg = manifest.GetLocalizedMessage(eventKey, CultureInfo.CurrentUICulture, etwFormat: false);
+                            // overwrite inline message with the localized message
+                            if (msg != null) eventAttribute.Message = msg;
+
+                            AddEventDescriptor(ref eventData, eventName, eventAttribute, args, hasRelatedActivityID);
+                        }
+                    }
+                }
+
+                // Tell the TraceLogging stuff where to start allocating its own IDs.  
+                NameInfo.ReserveEventIDsBelow(eventId);
+
+                if (source != null)
+                {
+                    TrimEventDescriptors(ref eventData);
+                    source.m_eventData = eventData;     // officially initialize it. We do this at most once (it is racy otherwise). 
+#if FEATURE_MANAGED_ETW_CHANNELS
+                    source.m_channelData = manifest.GetChannelData();
+#endif
+                }
+
+                // if this is an abstract event source we've already performed all the validation we can
+                if (!eventSourceType.IsAbstract() && (source == null || !source.SelfDescribingEvents))
+                {
+                    bNeedsManifest = (flags & EventManifestOptions.OnlyIfNeededForRegistration) == 0
+#if FEATURE_MANAGED_ETW_CHANNELS
+                                            || manifest.GetChannelData().Length > 0
+#endif
+;
+
+                    // if the manifest is not needed and we're not requested to validate the event source return early
+                    if (!bNeedsManifest && (flags & EventManifestOptions.Strict) == 0)
+                        return null;
+
+                    res = manifest.CreateManifest();
+                }
+            }
+            catch (Exception e)
+            {
+                // if this is a runtime manifest generation let the exception propagate
+                if ((flags & EventManifestOptions.Strict) == 0)
+                    throw;
+                // else store it to include it in the Argument exception we raise below
+                exception = e;
+            }
+
+            if ((flags & EventManifestOptions.Strict) != 0 && (manifest.Errors.Count > 0 || exception != null))
+            {
+                string msg = String.Empty;
+                if (manifest.Errors.Count > 0)
+                {
+                    bool firstError = true;
+                    foreach (string error in manifest.Errors)
+                    {
+                        if (!firstError)
+                            msg += Environment.NewLine;
+                        firstError = false;
+                        msg += error;
+                    }
+                }
+                else
+                    msg = "Unexpected error: " + exception.Message;
+
+                throw new ArgumentException(msg, exception);
+            }
+
+            return bNeedsManifest ? res : null;
+        }
+
+        private static bool RemoveFirstArgIfRelatedActivityId(ref ParameterInfo[] args)
+        {
+            // If the first parameter is (case insensitive) 'relatedActivityId' then skip it.  
+            if (args.Length > 0 && args[0].ParameterType == typeof(Guid) &&
+                string.Compare(args[0].Name, "relatedActivityId", StringComparison.OrdinalIgnoreCase) == 0)
+            {
+                var newargs = new ParameterInfo[args.Length - 1];
+                Array.Copy(args, 1, newargs, 0, args.Length - 1);
+                args = newargs;
+
+                return true;
+            }
+
+            return false;
+        }
+
+        // adds a enumeration (keyword, opcode, task or channel) represented by 'staticField'
+        // to the manifest.  
+        private static void AddProviderEnumKind(ManifestBuilder manifest, FieldInfo staticField, string providerEnumKind)
+        {
+            bool reflectionOnly = staticField.Module.Assembly.ReflectionOnly();
+            Type staticFieldType = staticField.FieldType;
+            if (!reflectionOnly && (staticFieldType == typeof(EventOpcode)) || AttributeTypeNamesMatch(staticFieldType, typeof(EventOpcode)))
+            {
+                if (providerEnumKind != "Opcodes") goto Error;
+                int value = (int)staticField.GetRawConstantValue();
+                manifest.AddOpcode(staticField.Name, value);
+            }
+            else if (!reflectionOnly && (staticFieldType == typeof(EventTask)) || AttributeTypeNamesMatch(staticFieldType, typeof(EventTask)))
+            {
+                if (providerEnumKind != "Tasks") goto Error;
+                int value = (int)staticField.GetRawConstantValue();
+                manifest.AddTask(staticField.Name, value);
+            }
+            else if (!reflectionOnly && (staticFieldType == typeof(EventKeywords)) || AttributeTypeNamesMatch(staticFieldType, typeof(EventKeywords)))
+            {
+                if (providerEnumKind != "Keywords") goto Error;
+                ulong value = unchecked((ulong)(long)staticField.GetRawConstantValue());
+                manifest.AddKeyword(staticField.Name, value);
+            }
+#if FEATURE_MANAGED_ETW_CHANNELS && FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
+            else if (!reflectionOnly && (staticFieldType == typeof(EventChannel)) || AttributeTypeNamesMatch(staticFieldType, typeof(EventChannel)))
+            {
+                if (providerEnumKind != "Channels") goto Error;
+                var channelAttribute = (EventChannelAttribute)GetCustomAttributeHelper(staticField, typeof(EventChannelAttribute));
+                manifest.AddChannel(staticField.Name, (byte)staticField.GetRawConstantValue(), channelAttribute);
+            }
+#endif
+            return;
+            Error:
+            manifest.ManifestError(Resources.GetResourceString("EventSource_EnumKindMismatch", staticField.Name, staticField.FieldType.Name, providerEnumKind));
+        }
+
+        // Helper used by code:CreateManifestAndDescriptors to add a code:EventData descriptor for a method
+        // with the code:EventAttribute 'eventAttribute'.  resourceManger may be null in which case we populate it
+        // it is populated if we need to look up message resources
+        private static void AddEventDescriptor(ref EventMetadata[] eventData, string eventName,
+                                EventAttribute eventAttribute, ParameterInfo[] eventParameters,
+                                bool hasRelatedActivityID)
+        {
+            if (eventData == null || eventData.Length <= eventAttribute.EventId)
+            {
+                EventMetadata[] newValues = new EventMetadata[Math.Max(eventData.Length + 16, eventAttribute.EventId + 1)];
+                Array.Copy(eventData, 0, newValues, 0, eventData.Length);
+                eventData = newValues;
+            }
+
+            eventData[eventAttribute.EventId].Descriptor = new EventDescriptor(
+                    eventAttribute.EventId,
+                    eventAttribute.Version,
+#if FEATURE_MANAGED_ETW_CHANNELS
+                    (byte)eventAttribute.Channel,
+#else
+                    (byte)0,
+#endif
+                    (byte)eventAttribute.Level,
+                    (byte)eventAttribute.Opcode,
+                    (int)eventAttribute.Task,
+                    unchecked((long)((ulong)eventAttribute.Keywords | SessionMask.All.ToEventKeywords())));
+
+            eventData[eventAttribute.EventId].Tags = eventAttribute.Tags;
+            eventData[eventAttribute.EventId].Name = eventName;
+            eventData[eventAttribute.EventId].Parameters = eventParameters;
+            eventData[eventAttribute.EventId].Message = eventAttribute.Message;
+            eventData[eventAttribute.EventId].ActivityOptions = eventAttribute.ActivityOptions;
+            eventData[eventAttribute.EventId].HasRelatedActivityID = hasRelatedActivityID;
+        }
+
+        // Helper used by code:CreateManifestAndDescriptors that trims the m_eventData array to the correct
+        // size after all event descriptors have been added. 
+        private static void TrimEventDescriptors(ref EventMetadata[] eventData)
+        {
+            int idx = eventData.Length;
+            while (0 < idx)
+            {
+                --idx;
+                if (eventData[idx].Descriptor.EventId != 0)
+                    break;
+            }
+            if (eventData.Length - idx > 2)      // allow one wasted slot. 
+            {
+                EventMetadata[] newValues = new EventMetadata[idx + 1];
+                Array.Copy(eventData, 0, newValues, 0, newValues.Length);
+                eventData = newValues;
+            }
+        }
+
+        // Helper used by code:EventListener.AddEventSource and code:EventListener.EventListener
+        // when a listener gets attached to a eventSource
+        internal void AddListener(EventListener listener)
+        {
+            lock (EventListener.EventListenersLock)
+            {
+                bool[] enabledArray = null;
+                if (m_eventData != null)
+                    enabledArray = new bool[m_eventData.Length];
+                m_Dispatchers = new EventDispatcher(m_Dispatchers, enabledArray, listener);
+                listener.OnEventSourceCreated(this);
+            }
+        }
+
+        // Helper used by code:CreateManifestAndDescriptors to find user mistakes like reusing an event
+        // index for two distinct events etc.  Throws exceptions when it finds something wrong. 
+        private static void DebugCheckEvent(ref Dictionary<string, string> eventsByName,
+            EventMetadata[] eventData, MethodInfo method, EventAttribute eventAttribute,
+            ManifestBuilder manifest, EventManifestOptions options)
+        {
+            int evtId = eventAttribute.EventId;
+            string evtName = method.Name;
+            int eventArg = GetHelperCallFirstArg(method);
+            if (eventArg >= 0 && evtId != eventArg)
+            {
+                manifest.ManifestError(Resources.GetResourceString("EventSource_MismatchIdToWriteEvent", evtName, evtId, eventArg), true);
+            }
+
+            if (evtId < eventData.Length && eventData[evtId].Descriptor.EventId != 0)
+            {
+                manifest.ManifestError(Resources.GetResourceString("EventSource_EventIdReused", evtName, evtId, eventData[evtId].Name), true);
+            }
+
+            // We give a task to things if they don't have one.  
+            // TODO this is moderately expensive (N*N).   We probably should not even bother....   
+            Debug.Assert(eventAttribute.Task != EventTask.None || eventAttribute.Opcode != EventOpcode.Info);
+            for (int idx = 0; idx < eventData.Length; ++idx)
+            {
+                // skip unused Event IDs. 
+                if (eventData[idx].Name == null)
+                    continue;
+
+                if (eventData[idx].Descriptor.Task == (int)eventAttribute.Task && eventData[idx].Descriptor.Opcode == (int)eventAttribute.Opcode)
+                {
+                    manifest.ManifestError(Resources.GetResourceString("EventSource_TaskOpcodePairReused",
+                                            evtName, evtId, eventData[idx].Name, idx));
+                    // If we are not strict stop on first error.   We have had problems with really large providers taking forever.  because of many errors.  
+                    if ((options & EventManifestOptions.Strict) == 0)
+                        break;
+                }
+            }
+
+            // for non-default event opcodes the user must define a task!
+            if (eventAttribute.Opcode != EventOpcode.Info)
+            {
+                bool failure = false;
+                if (eventAttribute.Task == EventTask.None)
+                    failure = true;
+                else
+                {
+                    // If you have the auto-assigned Task, then you did not explicitly set one.  
+                    // This is OK for Start events because we have special logic to assign the task to a prefix derived from the event name
+                    // But all other cases we want to catch the omission.  
+                    var autoAssignedTask = (EventTask)(0xFFFE - evtId);
+                    if ((eventAttribute.Opcode != EventOpcode.Start && eventAttribute.Opcode != EventOpcode.Stop) && eventAttribute.Task == autoAssignedTask)
+                        failure = true;
+                }
+                if (failure)
+                {
+                    manifest.ManifestError(Resources.GetResourceString("EventSource_EventMustHaveTaskIfNonDefaultOpcode", evtName, evtId));
+                }
+            }
+
+            // If we ever want to enforce the rule: MethodName = TaskName + OpcodeName here's how:
+            //  (the reason we don't is backwards compat and the need for handling this as a non-fatal error
+            //  by eventRegister.exe)
+            // taskName & opcodeName could be passed in by the caller which has opTab & taskTab handy
+            // if (!(((int)eventAttribute.Opcode == 0 && evtName == taskName) || (evtName == taskName+opcodeName)))
+            // {
+            //     throw new WarningException(Resources.GetResourceString("EventSource_EventNameDoesNotEqualTaskPlusOpcode"));
+            // }
+
+            if (eventsByName == null)
+                eventsByName = new Dictionary<string, string>();
+
+            if (eventsByName.ContainsKey(evtName))
+            {
+                manifest.ManifestError(Resources.GetResourceString("EventSource_EventNameReused", evtName), true);
+            }
+
+            eventsByName[evtName] = evtName;
+        }
+
+        /// <summary>
+        /// This method looks at the IL and tries to pattern match against the standard
+        /// 'boilerplate' event body 
+        /// <code>
+        ///     { if (Enabled()) WriteEvent(#, ...) } 
+        /// </code>
+        /// If the pattern matches, it returns the literal number passed as the first parameter to
+        /// the WriteEvent.  This is used to find common user errors (mismatching this
+        /// number with the EventAttribute ID).  It is only used for validation.   
+        /// </summary>
+        /// <param name="method">The method to probe.</param>
+        /// <returns>The literal value or -1 if the value could not be determined. </returns>
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Switch statement is clearer than alternatives")]
+        static private int GetHelperCallFirstArg(MethodInfo method)
+        {
+#if (!ES_BUILD_PCL && !ES_BUILD_PN)
+            // Currently searches for the following pattern
+            // 
+            // ...     // CAN ONLY BE THE INSTRUCTIONS BELOW
+            // LDARG0
+            // LDC.I4 XXX
+            // ...     // CAN ONLY BE THE INSTRUCTIONS BELOW CAN'T BE A BRANCH OR A CALL
+            // CALL 
+            // NOP     // 0 or more times
+            // RET
+            // 
+            // If we find this pattern we return the XXX.  Otherwise we return -1.  
+#if !CORECLR
+            (new ReflectionPermission(ReflectionPermissionFlag.MemberAccess)).Assert();
+#endif
+            byte[] instrs = method.GetMethodBody().GetILAsByteArray();
+            int retVal = -1;
+            for (int idx = 0; idx < instrs.Length;)
+            {
+                switch (instrs[idx])
+                {
+                    case 0: // NOP
+                    case 1: // BREAK
+                    case 2: // LDARG_0
+                    case 3: // LDARG_1
+                    case 4: // LDARG_2
+                    case 5: // LDARG_3
+                    case 6: // LDLOC_0
+                    case 7: // LDLOC_1
+                    case 8: // LDLOC_2
+                    case 9: // LDLOC_3
+                    case 10: // STLOC_0
+                    case 11: // STLOC_1
+                    case 12: // STLOC_2
+                    case 13: // STLOC_3
+                        break;
+                    case 14: // LDARG_S
+                    case 16: // STARG_S
+                        idx++;
+                        break;
+                    case 20: // LDNULL
+                        break;
+                    case 21: // LDC_I4_M1
+                    case 22: // LDC_I4_0
+                    case 23: // LDC_I4_1
+                    case 24: // LDC_I4_2
+                    case 25: // LDC_I4_3
+                    case 26: // LDC_I4_4
+                    case 27: // LDC_I4_5
+                    case 28: // LDC_I4_6
+                    case 29: // LDC_I4_7
+                    case 30: // LDC_I4_8
+                        if (idx > 0 && instrs[idx - 1] == 2)  // preceeded by LDARG0
+                            retVal = instrs[idx] - 22;
+                        break;
+                    case 31: // LDC_I4_S
+                        if (idx > 0 && instrs[idx - 1] == 2)  // preceeded by LDARG0
+                            retVal = instrs[idx + 1];
+                        idx++;
+                        break;
+                    case 32: // LDC_I4
+                        idx += 4;
+                        break;
+                    case 37: // DUP
+                        break;
+                    case 40: // CALL
+                        idx += 4;
+
+                        if (retVal >= 0)
+                        {
+                            // Is this call just before return?  
+                            for (int search = idx + 1; search < instrs.Length; search++)
+                            {
+                                if (instrs[search] == 42)  // RET
+                                    return retVal;
+                                if (instrs[search] != 0)   // NOP
+                                    break;
+                            }
+                        }
+                        retVal = -1;
+                        break;
+                    case 44: // BRFALSE_S
+                    case 45: // BRTRUE_S
+                        retVal = -1;
+                        idx++;
+                        break;
+                    case 57: // BRFALSE
+                    case 58: // BRTRUE
+                        retVal = -1;
+                        idx += 4;
+                        break;
+                    case 103: // CONV_I1
+                    case 104: // CONV_I2
+                    case 105: // CONV_I4
+                    case 106: // CONV_I8
+                    case 109: // CONV_U4
+                    case 110: // CONV_U8
+                        break;
+                    case 140: // BOX
+                    case 141: // NEWARR
+                        idx += 4;
+                        break;
+                    case 162: // STELEM_REF
+                        break;
+                    case 254: // PREFIX
+                        idx++;
+                        // Covers the CEQ instructions used in debug code for some reason.
+                        if (idx >= instrs.Length || instrs[idx] >= 6)
+                            goto default;
+                        break;
+                    default:
+                        /* Debug.Assert(false, "Warning: User validation code sub-optimial: Unsuported opcode " + instrs[idx] +
+                            " at " + idx + " in method " + method.Name); */
+                        return -1;
+                }
+                idx++;
+            }
+#endif
+            return -1;
+        }
+
+#if false // This routine is not needed at all, it was used for unit test debugging. 
+        [Conditional("DEBUG")]
+        private static void OutputDebugString(string msg)
+        {
+#if !ES_BUILD_PCL
+            msg = msg.TrimEnd('\r', '\n') +
+                    string.Format(CultureInfo.InvariantCulture, ", Thrd({0})" + Environment.NewLine, Thread.CurrentThread.ManagedThreadId);
+            System.Diagnostics.Debugger.Log(0, null, msg);
+#endif
+        }
+#endif
+
+        /// <summary>
+        /// Sends an error message to the debugger (outputDebugString), as well as the EventListeners 
+        /// It will do this even if the EventSource is not enabled.  
+        /// TODO remove flush parameter it is not used.  
+        /// </summary>
+        [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        internal void ReportOutOfBandMessage(string msg, bool flush)
+        {
+            try
+            {
+#if (!ES_BUILD_PCL && !ES_BUILD_PN)
+                // send message to debugger without delay
+                System.Diagnostics.Debugger.Log(0, null, String.Format("EventSource Error: {0}{1}", msg, Environment.NewLine));
+#endif
+
+                // Send it to all listeners.
+                if (m_outOfBandMessageCount < 16 - 1)     // Note this is only if size byte
+                    m_outOfBandMessageCount++;
+                else
+                {
+                    if (m_outOfBandMessageCount == 16)
+                        return;
+                    m_outOfBandMessageCount = 16;    // Mark that we hit the limit.  Notify them that this is the case. 
+                    msg = "Reached message limit.   End of EventSource error messages.";
+                }
+
+                WriteEventString(EventLevel.LogAlways, -1, msg);
+                WriteStringToAllListeners("EventSourceMessage", msg);
+            }
+            catch (Exception) { }      // If we fail during last chance logging, well, we have to give up....
+        }
+
+        private EventSourceSettings ValidateSettings(EventSourceSettings settings)
+        {
+            var evtFormatMask = EventSourceSettings.EtwManifestEventFormat |
+                                EventSourceSettings.EtwSelfDescribingEventFormat;
+            if ((settings & evtFormatMask) == evtFormatMask)
+            {
+                throw new ArgumentException(Resources.GetResourceString("EventSource_InvalidEventFormat"), nameof(settings));
+            }
+
+            // If you did not explicitly ask for manifest, you get self-describing.  
+            if ((settings & evtFormatMask) == 0)
+                settings |= EventSourceSettings.EtwSelfDescribingEventFormat;
+            return settings;
+        }
+
+        private bool ThrowOnEventWriteErrors
+        {
+            get { return (m_config & EventSourceSettings.ThrowOnEventWriteErrors) != 0; }
+            set
+            {
+                if (value) m_config |= EventSourceSettings.ThrowOnEventWriteErrors;
+                else m_config &= ~EventSourceSettings.ThrowOnEventWriteErrors;
+            }
+        }
+
+        private bool SelfDescribingEvents
+        {
+            get
+            {
+                Debug.Assert(((m_config & EventSourceSettings.EtwManifestEventFormat) != 0) !=
+                                ((m_config & EventSourceSettings.EtwSelfDescribingEventFormat) != 0));
+                return (m_config & EventSourceSettings.EtwSelfDescribingEventFormat) != 0;
+            }
+            set
+            {
+                if (!value)
+                {
+                    m_config |= EventSourceSettings.EtwManifestEventFormat;
+                    m_config &= ~EventSourceSettings.EtwSelfDescribingEventFormat;
+                }
+                else
+                {
+                    m_config |= EventSourceSettings.EtwSelfDescribingEventFormat;
+                    m_config &= ~EventSourceSettings.EtwManifestEventFormat;
+                }
+            }
+        }
+
+#if FEATURE_ACTIVITYSAMPLING
+        private void ReportActivitySamplingInfo(EventListener listener, SessionMask sessions)
+        {
+            Debug.Assert(listener == null || (uint)sessions == (uint)SessionMask.FromId(0));
+
+            for (int perEventSourceSessionId = 0; perEventSourceSessionId < SessionMask.MAX; ++perEventSourceSessionId)
+            {
+                if (!sessions[perEventSourceSessionId])
+                    continue;
+
+                ActivityFilter af;
+                if (listener == null)
+                {
+                    EtwSession etwSession = m_etwSessionIdMap[perEventSourceSessionId];
+                    Debug.Assert(etwSession != null);
+                    af = etwSession.m_activityFilter;
+                }
+                else
+                {
+                    af = listener.m_activityFilter;
+                }
+
+                if (af == null)
+                    continue;
+
+                SessionMask m = new SessionMask();
+                m[perEventSourceSessionId] = true;
+
+                foreach (var t in af.GetFilterAsTuple(m_guid))
+                {
+                    WriteStringToListener(listener, string.Format(CultureInfo.InvariantCulture, "Session {0}: {1} = {2}", perEventSourceSessionId, t.Item1, t.Item2), m);
+                }
+
+                bool participateInSampling = (listener == null) ?
+                                               m_activityFilteringForETWEnabled[perEventSourceSessionId] :
+                                               GetDispatcher(listener).m_activityFilteringEnabled;
+                WriteStringToListener(listener, string.Format(CultureInfo.InvariantCulture, "Session {0}: Activity Sampling support: {1}",
+                                          perEventSourceSessionId, participateInSampling ? "enabled" : "disabled"), m);
+            }
+        }
+#endif // FEATURE_ACTIVITYSAMPLING
+
+        // private instance state 
+        private string m_name;                          // My friendly name (privided in ctor)
+        internal int m_id;                              // A small integer that is unique to this instance.  
+        private Guid m_guid;                            // GUID representing the ETW eventSource to the OS.  
+        internal volatile EventMetadata[] m_eventData;  // None per-event data
+        private volatile byte[] m_rawManifest;          // Bytes to send out representing the event schema
+
+        private EventHandler<EventCommandEventArgs> m_eventCommandExecuted;
+
+        private EventSourceSettings m_config;      // configuration information
+
+        private bool m_eventSourceDisposed;              // has Dispose been called.
+
+        // Enabling bits
+        private bool m_eventSourceEnabled;              // am I enabled (any of my events are enabled for any dispatcher)
+        internal EventLevel m_level;                    // highest level enabled by any output dispatcher
+        internal EventKeywords m_matchAnyKeyword;       // the logical OR of all levels enabled by any output dispatcher (zero is a special case) meaning 'all keywords'
+
+        // Dispatching state 
+        internal volatile EventDispatcher m_Dispatchers;    // Linked list of code:EventDispatchers we write the data to (we also do ETW specially)
+#if FEATURE_MANAGED_ETW
+        private volatile OverideEventProvider m_provider;   // This hooks up ETW commands to our 'OnEventCommand' callback
+#endif
+        private bool m_completelyInited;                // The EventSource constructor has returned without exception.   
+        private Exception m_constructionException;      // If there was an exception construction, this is it 
+        private byte m_outOfBandMessageCount;           // The number of out of band messages sent (we throttle them
+        private EventCommandEventArgs m_deferredCommands;// If we get commands before we are fully we store them here and run the when we are fully inited.  
+
+        private string[] m_traits;                      // Used to implement GetTraits
+
+        internal static uint s_currentPid;              // current process id, used in synthesizing quasi-GUIDs
+        [ThreadStatic]
+        private static byte m_EventSourceExceptionRecurenceCount = 0; // current recursion count inside ThrowEventSourceException
+
+        [ThreadStatic]
+        private static bool m_EventSourceInDecodeObject = false;
+
+#if FEATURE_MANAGED_ETW_CHANNELS
+        internal volatile ulong[] m_channelData;
+#endif
+
+#if FEATURE_ACTIVITYSAMPLING
+        private SessionMask m_curLiveSessions;          // the activity-tracing aware sessions' bits
+        private EtwSession[] m_etwSessionIdMap;         // the activity-tracing aware sessions
+        private List<EtwSession> m_legacySessions;      // the legacy ETW sessions listening to this source
+        internal long m_keywordTriggers;                // a bit is set if it corresponds to a keyword that's part of an enabled triggering event
+        internal SessionMask m_activityFilteringForETWEnabled; // does THIS EventSource have activity filtering turned on for each ETW session
+        static internal Action<Guid> s_activityDying;   // Fires when something calls SetCurrentThreadToActivity()
+        // Also used to mark that activity tracing is on for some case
+#endif // FEATURE_ACTIVITYSAMPLING
+
+        // We use a single instance of ActivityTracker for all EventSources instances to allow correlation between multiple event providers.
+        // We have m_activityTracker field simply because instance field is more efficient than static field fetch.
+        ActivityTracker m_activityTracker;
+        internal const string s_ActivityStartSuffix = "Start";
+        internal const string s_ActivityStopSuffix = "Stop";
+
+        // used for generating GUID from eventsource name
+        private static readonly byte[] namespaceBytes = new byte[] {
+            0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8,
+            0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB,
+        };
+
+        #endregion
+    }
+
+    /// <summary>
+    /// Enables specifying event source configuration options to be used in the EventSource constructor.
+    /// </summary>
+    [Flags]
+    public enum EventSourceSettings
+    {
+        /// <summary>
+        /// This specifies none of the special configuration options should be enabled.
+        /// </summary>
+        Default = 0,
+        /// <summary>
+        /// Normally an EventSource NEVER throws; setting this option will tell it to throw when it encounters errors.  
+        /// </summary>
+        ThrowOnEventWriteErrors = 1,
+        /// <summary>
+        /// Setting this option is a directive to the ETW listener should use manifest-based format when
+        /// firing events. This is the default option when defining a type derived from EventSource 
+        /// (using the protected EventSource constructors).
+        /// Only one of EtwManifestEventFormat or EtwSelfDescribingEventFormat should be specified
+        /// </summary>
+        EtwManifestEventFormat = 4,
+        /// <summary>
+        /// Setting this option is a directive to the ETW listener should use self-describing event format
+        /// when firing events. This is the default option when creating a new instance of the EventSource
+        /// type (using the public EventSource constructors).  
+        /// Only one of EtwManifestEventFormat or EtwSelfDescribingEventFormat should be specified
+        /// </summary>
+        EtwSelfDescribingEventFormat = 8,
+    }
+
+    /// <summary>
+    /// An EventListener represents a target for the events generated by EventSources (that is subclasses
+    /// of <see cref="EventSource"/>), in the current appdomain. When a new EventListener is created
+    /// it is logically attached to all eventSources in that appdomain. When the EventListener is Disposed, then
+    /// it is disconnected from the event eventSources. Note that there is a internal list of STRONG references
+    /// to EventListeners, which means that relying on the lack of references to EventListeners to clean up
+    /// EventListeners will NOT work. You must call EventListener.Dispose explicitly when a dispatcher is no
+    /// longer needed.
+    /// <para>
+    /// Once created, EventListeners can enable or disable on a per-eventSource basis using verbosity levels
+    /// (<see cref="EventLevel"/>) and bitfields (<see cref="EventKeywords"/>) to further restrict the set of 
+    /// events to be sent to the dispatcher. The dispatcher can also send arbitrary commands to a particular 
+    /// eventSource using the 'SendCommand' method. The meaning of the commands are eventSource specific.
+    /// </para><para>
+    /// The Null Guid (that is (new Guid()) has special meaning as a wildcard for 'all current eventSources in
+    /// the appdomain'. Thus it is relatively easy to turn on all events in the appdomain if desired.
+    /// </para><para>
+    /// It is possible for there to be many EventListener's defined in a single appdomain. Each dispatcher is
+    /// logically independent of the other listeners. Thus when one dispatcher enables or disables events, it
+    /// affects only that dispatcher (other listeners get the events they asked for). It is possible that
+    /// commands sent with 'SendCommand' would do a semantic operation that would affect the other listeners
+    /// (like doing a GC, or flushing data ...), but this is the exception rather than the rule.
+    /// </para><para>
+    /// Thus the model is that each EventSource keeps a list of EventListeners that it is sending events
+    /// to. Associated with each EventSource-dispatcher pair is a set of filtering criteria that determine for
+    /// that eventSource what events that dispatcher will receive.
+    /// </para><para>
+    /// Listeners receive the events on their 'OnEventWritten' method. Thus subclasses of EventListener must
+    /// override this method to do something useful with the data.
+    /// </para><para>
+    /// In addition, when new eventSources are created, the 'OnEventSourceCreate' method is called. The
+    /// invariant associated with this callback is that every eventSource gets exactly one
+    /// 'OnEventSourceCreate' call for ever eventSource that can potentially send it log messages. In
+    /// particular when a EventListener is created, typically a series of OnEventSourceCreate' calls are
+    /// made to notify the new dispatcher of all the eventSources that existed before the EventListener was
+    /// created.
+    /// </para>
+    /// </summary>
+    public class EventListener : IDisposable
+    {
+        private event EventHandler<EventSourceCreatedEventArgs> _EventSourceCreated;
+
+        /// <summary>
+        /// This event is raised whenever a new eventSource is 'attached' to the dispatcher.
+        /// This can happen for all existing EventSources when the EventListener is created
+        /// as well as for any EventSources that come into existence after the EventListener
+        /// has been created.
+        /// 
+        /// These 'catch up' events are called during the construction of the EventListener.
+        /// Subclasses need to be prepared for that.
+        /// 
+        /// In a multi-threaded environment, it is possible that 'EventSourceEventWrittenCallback' 
+        /// events for a particular eventSource to occur BEFORE the EventSourceCreatedCallback is issued.
+        /// </summary>
+        public event EventHandler<EventSourceCreatedEventArgs> EventSourceCreated
+        {
+            add
+            {
+                CallBackForExistingEventSources(false, value);
+
+                this._EventSourceCreated = (EventHandler<EventSourceCreatedEventArgs>)Delegate.Combine(_EventSourceCreated, value);
+            }
+            remove
+            {
+                this._EventSourceCreated = (EventHandler<EventSourceCreatedEventArgs>)Delegate.Remove(_EventSourceCreated, value);
+            }
+        }
+
+        /// <summary>
+        /// This event is raised whenever an event has been written by a EventSource for which 
+        /// the EventListener has enabled events.  
+        /// </summary>
+        public event EventHandler<EventWrittenEventArgs> EventWritten;
+
+        /// <summary>
+        /// Create a new EventListener in which all events start off turned off (use EnableEvents to turn
+        /// them on).  
+        /// </summary>
+        public EventListener()
+        {
+            // This will cause the OnEventSourceCreated callback to fire. 
+            CallBackForExistingEventSources(true, (obj, args) => args.EventSource.AddListener((EventListener)obj));
+        }
+
+        /// <summary>
+        /// Dispose should be called when the EventListener no longer desires 'OnEvent*' callbacks. Because
+        /// there is an internal list of strong references to all EventListeners, calling 'Dispose' directly
+        /// is the only way to actually make the listen die. Thus it is important that users of EventListener
+        /// call Dispose when they are done with their logging.
+        /// </summary>
+#if ES_BUILD_STANDALONE
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")]
+#endif
+        public virtual void Dispose()
+        {
+            lock (EventListenersLock)
+            {
+                if (s_Listeners != null)
+                {
+                    if (this == s_Listeners)
+                    {
+                        EventListener cur = s_Listeners;
+                        s_Listeners = this.m_Next;
+                        RemoveReferencesToListenerInEventSources(cur);
+                    }
+                    else
+                    {
+                        // Find 'this' from the s_Listeners linked list.  
+                        EventListener prev = s_Listeners;
+                        for (;;)
+                        {
+                            EventListener cur = prev.m_Next;
+                            if (cur == null)
+                                break;
+                            if (cur == this)
+                            {
+                                // Found our Listener, remove references to to it in the eventSources
+                                prev.m_Next = cur.m_Next;       // Remove entry. 
+                                RemoveReferencesToListenerInEventSources(cur);
+                                break;
+                            }
+                            prev = cur;
+                        }
+                    }
+                }
+                Validate();
+            }
+        }
+        // We don't expose a Dispose(bool), because the contract is that you don't have any non-syncronous
+        // 'cleanup' associated with this object
+
+        /// <summary>
+        /// Enable all events from the eventSource identified by 'eventSource' to the current 
+        /// dispatcher that have a verbosity level of 'level' or lower.
+        ///   
+        /// This call can have the effect of REDUCING the number of events sent to the 
+        /// dispatcher if 'level' indicates a less verbose level than was previously enabled.
+        /// 
+        /// This call never has an effect on other EventListeners.
+        ///
+        /// </summary>
+        public void EnableEvents(EventSource eventSource, EventLevel level)
+        {
+            EnableEvents(eventSource, level, EventKeywords.None);
+        }
+        /// <summary>
+        /// Enable all events from the eventSource identified by 'eventSource' to the current
+        /// dispatcher that have a verbosity level of 'level' or lower and have a event keyword
+        /// matching any of the bits in 'matchAnyKeyword'.
+        /// 
+        /// This call can have the effect of REDUCING the number of events sent to the 
+        /// dispatcher if 'level' indicates a less verbose level than was previously enabled or
+        /// if 'matchAnyKeyword' has fewer keywords set than where previously set.
+        /// 
+        /// This call never has an effect on other EventListeners.
+        /// </summary>
+        public void EnableEvents(EventSource eventSource, EventLevel level, EventKeywords matchAnyKeyword)
+        {
+            EnableEvents(eventSource, level, matchAnyKeyword, null);
+        }
+        /// <summary>
+        /// Enable all events from the eventSource identified by 'eventSource' to the current
+        /// dispatcher that have a verbosity level of 'level' or lower and have a event keyword
+        /// matching any of the bits in 'matchAnyKeyword' as well as any (eventSource specific)
+        /// effect passing additional 'key-value' arguments 'arguments' might have.  
+        /// 
+        /// This call can have the effect of REDUCING the number of events sent to the 
+        /// dispatcher if 'level' indicates a less verbose level than was previously enabled or
+        /// if 'matchAnyKeyword' has fewer keywords set than where previously set.
+        /// 
+        /// This call never has an effect on other EventListeners.
+        /// </summary>       
+        public void EnableEvents(EventSource eventSource, EventLevel level, EventKeywords matchAnyKeyword, IDictionary<string, string> arguments)
+        {
+            if (eventSource == null)
+            {
+                throw new ArgumentNullException(nameof(eventSource));
+            }
+            Contract.EndContractBlock();
+
+            eventSource.SendCommand(this, 0, 0, EventCommand.Update, true, level, matchAnyKeyword, arguments);
+        }
+        /// <summary>
+        /// Disables all events coming from eventSource identified by 'eventSource'.  
+        /// 
+        /// This call never has an effect on other EventListeners.      
+        /// </summary>
+        public void DisableEvents(EventSource eventSource)
+        {
+            if (eventSource == null)
+            {
+                throw new ArgumentNullException(nameof(eventSource));
+            }
+            Contract.EndContractBlock();
+
+            eventSource.SendCommand(this, 0, 0, EventCommand.Update, false, EventLevel.LogAlways, EventKeywords.None, null);
+        }
+
+        /// <summary>
+        /// EventSourceIndex is small non-negative integer (suitable for indexing in an array)
+        /// identifying EventSource. It is unique per-appdomain. Some EventListeners might find
+        /// it useful to store additional information about each eventSource connected to it,
+        /// and EventSourceIndex allows this extra information to be efficiently stored in a
+        /// (growable) array (eg List(T)).
+        /// </summary>
+        public static int EventSourceIndex(EventSource eventSource) { return eventSource.m_id; }
+
+        /// <summary>
+        /// This method is called whenever a new eventSource is 'attached' to the dispatcher.
+        /// This can happen for all existing EventSources when the EventListener is created
+        /// as well as for any EventSources that come into existence after the EventListener
+        /// has been created.
+        /// 
+        /// These 'catch up' events are called during the construction of the EventListener.
+        /// Subclasses need to be prepared for that.
+        /// 
+        /// In a multi-threaded environment, it is possible that 'OnEventWritten' callbacks
+        /// for a particular eventSource to occur BEFORE the OnEventSourceCreated is issued.
+        /// </summary>
+        /// <param name="eventSource"></param>
+        internal protected virtual void OnEventSourceCreated(EventSource eventSource)
+        {
+            EventHandler<EventSourceCreatedEventArgs> callBack = this._EventSourceCreated;
+            if (callBack != null)
+            {
+                EventSourceCreatedEventArgs args = new EventSourceCreatedEventArgs();
+                args.EventSource = eventSource;
+                callBack(this, args);
+            }
+        }
+
+        /// <summary>
+        /// This method is called whenever an event has been written by a EventSource for which 
+        /// the EventListener has enabled events.  
+        /// </summary>
+        /// <param name="eventData"></param>
+        internal protected virtual void OnEventWritten(EventWrittenEventArgs eventData)
+        {
+            EventHandler<EventWrittenEventArgs> callBack = this.EventWritten;
+            if (callBack != null)
+            {
+                callBack(this, eventData);
+            }
+        }
+
+
+        #region private
+        /// <summary>
+        /// This routine adds newEventSource to the global list of eventSources, it also assigns the
+        /// ID to the eventSource (which is simply the ordinal in the global list).
+        /// 
+        /// EventSources currently do not pro-actively remove themselves from this list. Instead
+        /// when eventSources's are GCed, the weak handle in this list naturally gets nulled, and
+        /// we will reuse the slot. Today this list never shrinks (but we do reuse entries
+        /// that are in the list). This seems OK since the expectation is that EventSources
+        /// tend to live for the lifetime of the appdomain anyway (they tend to be used in
+        /// global variables).
+        /// </summary>
+        /// <param name="newEventSource"></param>
+        internal static void AddEventSource(EventSource newEventSource)
+        {
+            lock (EventListenersLock)
+            {
+                if (s_EventSources == null)
+                    s_EventSources = new List<WeakReference>(2);
+
+                if (!s_EventSourceShutdownRegistered)
+                {
+                    s_EventSourceShutdownRegistered = true;
+                }
+
+
+                // Periodically search the list for existing entries to reuse, this avoids
+                // unbounded memory use if we keep recycling eventSources (an unlikely thing). 
+                int newIndex = -1;
+                if (s_EventSources.Count % 64 == 63)   // on every block of 64, fill up the block before continuing
+                {
+                    int i = s_EventSources.Count;      // Work from the top down. 
+                    while (0 < i)
+                    {
+                        --i;
+                        WeakReference weakRef = s_EventSources[i];
+                        if (!weakRef.IsAlive)
+                        {
+                            newIndex = i;
+                            weakRef.Target = newEventSource;
+                            break;
+                        }
+                    }
+                }
+                if (newIndex < 0)
+                {
+                    newIndex = s_EventSources.Count;
+                    s_EventSources.Add(new WeakReference(newEventSource));
+                }
+                newEventSource.m_id = newIndex;
+
+                // Add every existing dispatcher to the new EventSource
+                for (EventListener listener = s_Listeners; listener != null; listener = listener.m_Next)
+                    newEventSource.AddListener(listener);
+
+                Validate();
+            }
+        }
+
+        // Whenver we have async callbacks from native code, there is an ugly issue where
+        // during .NET shutdown native code could be calling the callback, but the CLR
+        // has already prohibited callbacks to managed code in the appdomain, causing the CLR 
+        // to throw a COMPLUS_BOOT_EXCEPTION.   The guideline we give is that you must unregister
+        // such callbacks on process shutdown or appdomain so that unmanaged code will never 
+        // do this.  This is what this callback is for.  
+        // See bug 724140 for more
+        private static void DisposeOnShutdown(object sender, EventArgs e)
+        {
+            lock (EventListenersLock)
+            {
+                foreach (var esRef in s_EventSources)
+                {
+                    EventSource es = esRef.Target as EventSource;
+                    if (es != null)
+                        es.Dispose();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Helper used in code:Dispose that removes any references to 'listenerToRemove' in any of the
+        /// eventSources in the appdomain.  
+        /// 
+        /// The EventListenersLock must be held before calling this routine. 
+        /// </summary>
+        private static void RemoveReferencesToListenerInEventSources(EventListener listenerToRemove)
+        {
+#if !ES_BUILD_STANDALONE
+            Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
+#endif
+            // Foreach existing EventSource in the appdomain
+            foreach (WeakReference eventSourceRef in s_EventSources)
+            {
+                EventSource eventSource = eventSourceRef.Target as EventSource;
+                if (eventSource != null)
+                {
+                    // Is the first output dispatcher the dispatcher we are removing?
+                    if (eventSource.m_Dispatchers.m_Listener == listenerToRemove)
+                        eventSource.m_Dispatchers = eventSource.m_Dispatchers.m_Next;
+                    else
+                    {
+                        // Remove 'listenerToRemove' from the eventSource.m_Dispatchers linked list.  
+                        EventDispatcher prev = eventSource.m_Dispatchers;
+                        for (;;)
+                        {
+                            EventDispatcher cur = prev.m_Next;
+                            if (cur == null)
+                            {
+                                Debug.Assert(false, "EventSource did not have a registered EventListener!");
+                                break;
+                            }
+                            if (cur.m_Listener == listenerToRemove)
+                            {
+                                prev.m_Next = cur.m_Next;       // Remove entry. 
+                                break;
+                            }
+                            prev = cur;
+                        }
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Checks internal consistency of EventSources/Listeners. 
+        /// </summary>
+        [Conditional("DEBUG")]
+        internal static void Validate()
+        {
+            lock (EventListenersLock)
+            {
+                // Get all listeners 
+                Dictionary<EventListener, bool> allListeners = new Dictionary<EventListener, bool>();
+                EventListener cur = s_Listeners;
+                while (cur != null)
+                {
+                    allListeners.Add(cur, true);
+                    cur = cur.m_Next;
+                }
+
+                // For all eventSources 
+                int id = -1;
+                foreach (WeakReference eventSourceRef in s_EventSources)
+                {
+                    id++;
+                    EventSource eventSource = eventSourceRef.Target as EventSource;
+                    if (eventSource == null)
+                        continue;
+                    Debug.Assert(eventSource.m_id == id, "Unexpected event source ID.");
+
+                    // None listeners on eventSources exist in the dispatcher list.   
+                    EventDispatcher dispatcher = eventSource.m_Dispatchers;
+                    while (dispatcher != null)
+                    {
+                        Debug.Assert(allListeners.ContainsKey(dispatcher.m_Listener), "EventSource has a listener not on the global list.");
+                        dispatcher = dispatcher.m_Next;
+                    }
+
+                    // Every dispatcher is on Dispatcher List of every eventSource. 
+                    foreach (EventListener listener in allListeners.Keys)
+                    {
+                        dispatcher = eventSource.m_Dispatchers;
+                        for (;;)
+                        {
+                            Debug.Assert(dispatcher != null, "Listener is not on all eventSources.");
+                            if (dispatcher.m_Listener == listener)
+                                break;
+                            dispatcher = dispatcher.m_Next;
+                        }
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets a global lock that is intended to protect the code:s_Listeners linked list and the
+        /// code:s_EventSources WeakReference list.  (We happen to use the s_EventSources list as
+        /// the lock object)
+        /// </summary>
+        internal static object EventListenersLock
+        {
+            get
+            {
+                if (s_EventSources == null)
+                    Interlocked.CompareExchange(ref s_EventSources, new List<WeakReference>(2), null);
+                return s_EventSources;
+            }
+        }
+
+        private void CallBackForExistingEventSources(bool addToListenersList, EventHandler<EventSourceCreatedEventArgs> callback)
+        {
+            lock (EventListenersLock)
+            {
+                // Disallow creating EventListener reentrancy. 
+                if (s_CreatingListener)
+                {
+                    throw new InvalidOperationException(Resources.GetResourceString("EventSource_ListenerCreatedInsideCallback"));
+                }
+
+                try
+                {
+                    s_CreatingListener = true;
+
+                    if (addToListenersList)
+                    {
+                        // Add to list of listeners in the system, do this BEFORE firing the 'OnEventSourceCreated' so that 
+                        // Those added sources see this listener.
+                        this.m_Next = s_Listeners;
+                        s_Listeners = this;
+                    }
+
+                    // Find all existing eventSources call OnEventSourceCreated to 'catchup'
+                    // Note that we DO have reentrancy here because 'AddListener' calls out to user code (via OnEventSourceCreated callback) 
+                    // We tolerate this by iterating over a copy of the list here. New event sources will take care of adding listeners themselves
+                    // EventSources are not guaranteed to be added at the end of the s_EventSource list -- We re-use slots when a new source
+                    // is created.
+                    WeakReference[] eventSourcesSnapshot = s_EventSources.ToArray();
+
+                    for (int i = 0; i < eventSourcesSnapshot.Length; i++)
+                    {
+                        WeakReference eventSourceRef = eventSourcesSnapshot[i];
+                        EventSource eventSource = eventSourceRef.Target as EventSource;
+                        if (eventSource != null)
+                        {
+                            EventSourceCreatedEventArgs args = new EventSourceCreatedEventArgs();
+                            args.EventSource = eventSource;
+                            callback(this, args);
+                        }
+                    }
+
+                    Validate();
+                }
+                finally
+                {
+                    s_CreatingListener = false;
+                }
+            }
+
+        }
+
+        // Instance fields
+        internal volatile EventListener m_Next;                         // These form a linked list in s_Listeners
+#if FEATURE_ACTIVITYSAMPLING
+        internal ActivityFilter m_activityFilter;                       // If we are filtering by activity on this Listener, this keeps track of it. 
+#endif // FEATURE_ACTIVITYSAMPLING
+
+        // static fields
+
+        /// <summary>
+        /// The list of all listeners in the appdomain.  Listeners must be explicitly disposed to remove themselves 
+        /// from this list.   Note that EventSources point to their listener but NOT the reverse.  
+        /// </summary>
+        internal static EventListener s_Listeners;
+        /// <summary>
+        /// The list of all active eventSources in the appdomain.  Note that eventSources do NOT 
+        /// remove themselves from this list this is a weak list and the GC that removes them may
+        /// not have happened yet.  Thus it can contain event sources that are dead (thus you have 
+        /// to filter those out.  
+        /// </summary>
+        internal static List<WeakReference> s_EventSources;
+
+        /// <summary>
+        /// Used to disallow reentrancy.  
+        /// </summary>
+        private static bool s_CreatingListener = false;
+
+        /// <summary>
+        /// Used to register AD/Process shutdown callbacks.
+        /// </summary>
+        private static bool s_EventSourceShutdownRegistered = false;
+        #endregion
+    }
+
+    /// <summary>
+    /// Passed to the code:EventSource.OnEventCommand callback
+    /// </summary>
+    public class EventCommandEventArgs : EventArgs
+    {
+        /// <summary>
+        /// Gets the command for the callback.
+        /// </summary>
+        public EventCommand Command { get; internal set; }
+
+        /// <summary>
+        /// Gets the arguments for the callback.
+        /// </summary>
+        public IDictionary<String, String> Arguments { get; internal set; }
+
+        /// <summary>
+        /// Enables the event that has the specified identifier.
+        /// </summary>
+        /// <param name="eventId">Event ID of event to be enabled</param>
+        /// <returns>true if eventId is in range</returns>
+        public bool EnableEvent(int eventId)
+        {
+            if (Command != EventCommand.Enable && Command != EventCommand.Disable)
+                throw new InvalidOperationException();
+            return eventSource.EnableEventForDispatcher(dispatcher, eventId, true);
+        }
+
+        /// <summary>
+        /// Disables the event that have the specified identifier.
+        /// </summary>
+        /// <param name="eventId">Event ID of event to be disabled</param>
+        /// <returns>true if eventId is in range</returns>
+        public bool DisableEvent(int eventId)
+        {
+            if (Command != EventCommand.Enable && Command != EventCommand.Disable)
+                throw new InvalidOperationException();
+            return eventSource.EnableEventForDispatcher(dispatcher, eventId, false);
+        }
+
+        #region private
+
+        internal EventCommandEventArgs(EventCommand command, IDictionary<string, string> arguments, EventSource eventSource,
+            EventListener listener, int perEventSourceSessionId, int etwSessionId, bool enable, EventLevel level, EventKeywords matchAnyKeyword)
+        {
+            this.Command = command;
+            this.Arguments = arguments;
+            this.eventSource = eventSource;
+            this.listener = listener;
+            this.perEventSourceSessionId = perEventSourceSessionId;
+            this.etwSessionId = etwSessionId;
+            this.enable = enable;
+            this.level = level;
+            this.matchAnyKeyword = matchAnyKeyword;
+        }
+
+        internal EventSource eventSource;
+        internal EventDispatcher dispatcher;
+
+        // These are the arguments of sendCommand and are only used for deferring commands until after we are fully initialized. 
+        internal EventListener listener;
+        internal int perEventSourceSessionId;
+        internal int etwSessionId;
+        internal bool enable;
+        internal EventLevel level;
+        internal EventKeywords matchAnyKeyword;
+        internal EventCommandEventArgs nextCommand;     // We form a linked list of these deferred commands.      
+
+        #endregion
+    }
+
+    /// <summary>
+    /// EventSourceCreatedEventArgs is passed to <see cref="EventListener.EventSourceCreated"/>
+    /// </summary>
+    public class EventSourceCreatedEventArgs : EventArgs
+    {
+        /// <summary>
+        /// The EventSource that is attaching to the listener.
+        /// </summary>
+        public EventSource EventSource
+        {
+            get;
+            internal set;
+        }
+    }
+
+    /// <summary>
+    /// EventWrittenEventArgs is passed to the user-provided override for
+    /// <see cref="EventListener.OnEventWritten"/> when an event is fired.
+    /// </summary>
+    public class EventWrittenEventArgs : EventArgs
+    {
+        /// <summary>
+        /// The name of the event.   
+        /// </summary>
+        public string EventName
+        {
+            get
+            {
+                if (m_eventName != null || EventId < 0)      // TraceLogging convention EventID == -1
+                {
+                    return m_eventName;
+                }
+                else
+                    return m_eventSource.m_eventData[EventId].Name;
+            }
+            internal set
+            {
+                m_eventName = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets the event ID for the event that was written.
+        /// </summary>
+        public int EventId { get; internal set; }
+
+        /// <summary>
+        /// Gets the activity ID for the thread on which the event was written.
+        /// </summary>
+        public Guid ActivityId
+        {
+            get { return EventSource.CurrentThreadActivityId; }
+        }
+
+        /// <summary>
+        /// Gets the related activity ID if one was specified when the event was written.
+        /// </summary>
+        public Guid RelatedActivityId
+        {
+            get;
+            internal set;
+        }
+
+        /// <summary>
+        /// Gets the payload for the event.
+        /// </summary>
+        public ReadOnlyCollection<Object> Payload { get; internal set; }
+
+        /// <summary>
+        /// Gets the payload argument names.
+        /// </summary>
+        public ReadOnlyCollection<string> PayloadNames
+        {
+            get
+            {
+                // For contract based events we create the list lazily.
+                if (m_payloadNames == null)
+                {
+                    // Self described events are identified by id -1.
+                    Debug.Assert(EventId != -1);
+
+                    var names = new List<string>();
+                    foreach (var parameter in m_eventSource.m_eventData[EventId].Parameters)
+                    {
+                        names.Add(parameter.Name);
+                    }
+                    m_payloadNames = new ReadOnlyCollection<string>(names);
+                }
+
+                return m_payloadNames;
+            }
+
+            internal set
+            {
+                m_payloadNames = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets the event source object.
+        /// </summary>
+        public EventSource EventSource { get { return m_eventSource; } }
+
+        /// <summary>
+        /// Gets the keywords for the event.
+        /// </summary>
+        public EventKeywords Keywords
+        {
+            get
+            {
+                if (EventId < 0)      // TraceLogging convention EventID == -1
+                    return m_keywords;
+
+                return (EventKeywords)m_eventSource.m_eventData[EventId].Descriptor.Keywords;
+            }
+        }
+
+        /// <summary>
+        /// Gets the operation code for the event.
+        /// </summary>
+        public EventOpcode Opcode
+        {
+            get
+            {
+                if (EventId <= 0)      // TraceLogging convention EventID == -1
+                    return m_opcode;
+                return (EventOpcode)m_eventSource.m_eventData[EventId].Descriptor.Opcode;
+            }
+        }
+
+        /// <summary>
+        /// Gets the task for the event.
+        /// </summary>
+        public EventTask Task
+        {
+            get
+            {
+                if (EventId <= 0)      // TraceLogging convention EventID == -1
+                    return EventTask.None;
+
+                return (EventTask)m_eventSource.m_eventData[EventId].Descriptor.Task;
+            }
+        }
+
+        /// <summary>
+        /// Any provider/user defined options associated with the event.  
+        /// </summary>
+        public EventTags Tags
+        {
+            get
+            {
+                if (EventId <= 0)      // TraceLogging convention EventID == -1
+                    return m_tags;
+                return m_eventSource.m_eventData[EventId].Tags;
+            }
+        }
+
+        /// <summary>
+        /// Gets the message for the event.  If the message has {N} parameters they are NOT substituted.  
+        /// </summary>
+        public string Message
+        {
+            get
+            {
+                if (EventId <= 0)      // TraceLogging convention EventID == -1
+                    return m_message;
+                else
+                    return m_eventSource.m_eventData[EventId].Message;
+            }
+            internal set
+            {
+                m_message = value;
+            }
+        }
+
+
+#if FEATURE_MANAGED_ETW_CHANNELS
+        /// <summary>
+        /// Gets the channel for the event.
+        /// </summary>
+        public EventChannel Channel
+        {
+            get
+            {
+                if (EventId <= 0)      // TraceLogging convention EventID == -1
+                    return EventChannel.None;
+                return (EventChannel)m_eventSource.m_eventData[EventId].Descriptor.Channel;
+            }
+        }
+#endif
+
+        /// <summary>
+        /// Gets the version of the event.
+        /// </summary>
+        public byte Version
+        {
+            get
+            {
+                if (EventId <= 0)      // TraceLogging convention EventID == -1
+                    return 0;
+                return m_eventSource.m_eventData[EventId].Descriptor.Version;
+            }
+        }
+
+        /// <summary>
+        /// Gets the level for the event.
+        /// </summary>
+        public EventLevel Level
+        {
+            get
+            {
+                if (EventId <= 0)      // TraceLogging convention EventID == -1
+                    return m_level;
+                return (EventLevel)m_eventSource.m_eventData[EventId].Descriptor.Level;
+            }
+        }
+
+        #region private
+        internal EventWrittenEventArgs(EventSource eventSource)
+        {
+            m_eventSource = eventSource;
+        }
+        private string m_message;
+        private string m_eventName;
+        private EventSource m_eventSource;
+        private ReadOnlyCollection<string> m_payloadNames;
+        internal EventTags m_tags;
+        internal EventOpcode m_opcode;
+        internal EventLevel m_level;
+        internal EventKeywords m_keywords;
+        #endregion
+    }
+
+    /// <summary>
+    /// Allows customizing defaults and specifying localization support for the event source class to which it is applied. 
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Class)]
+    public sealed class EventSourceAttribute : Attribute
+    {
+        /// <summary>
+        /// Overrides the ETW name of the event source (which defaults to the class name)
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Overrides the default (calculated) Guid of an EventSource type. Explicitly defining a GUID is discouraged, 
+        /// except when upgrading existing ETW providers to using event sources.
+        /// </summary>
+        public string Guid { get; set; }
+
+        /// <summary>
+        /// <para>
+        /// EventSources support localization of events. The names used for events, opcodes, tasks, keywords and maps 
+        /// can be localized to several languages if desired. This works by creating a ResX style string table 
+        /// (by simply adding a 'Resource File' to your project). This resource file is given a name e.g. 
+        /// 'DefaultNameSpace.ResourceFileName' which can be passed to the ResourceManager constructor to read the 
+        /// resources. This name is the value of the LocalizationResources property. 
+        /// </para><para>
+        /// If LocalizationResources property is non-null, then EventSource will look up the localized strings for events by 
+        /// using the following resource naming scheme
+        /// </para>
+        ///     <para>* event_EVENTNAME</para>
+        ///     <para>* task_TASKNAME</para>
+        ///     <para>* keyword_KEYWORDNAME</para>
+        ///     <para>* map_MAPNAME</para>
+        /// <para>
+        /// where the capitalized name is the name of the event, task, keyword, or map value that should be localized.   
+        /// Note that the localized string for an event corresponds to the Message string, and can have {0} values 
+        /// which represent the payload values.  
+        /// </para>
+        /// </summary>
+        public string LocalizationResources { get; set; }
+    }
+
+    /// <summary>
+    /// Any instance methods in a class that subclasses <see cref="EventSource"/> and that return void are
+    /// assumed by default to be methods that generate an ETW event. Enough information can be deduced from the
+    /// name of the method and its signature to generate basic schema information for the event. The
+    /// <see cref="EventAttribute"/> class allows you to specify additional event schema information for an event if
+    /// desired.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Method)]
+    public sealed class EventAttribute : Attribute
+    {
+        /// <summary>Construct an EventAttribute with specified eventId</summary>
+        /// <param name="eventId">ID of the ETW event (an integer between 1 and 65535)</param>
+        public EventAttribute(int eventId) { this.EventId = eventId; Level = EventLevel.Informational; this.m_opcodeSet = false; }
+        /// <summary>Event's ID</summary>
+        public int EventId { get; private set; }
+        /// <summary>Event's severity level: indicates the severity or verbosity of the event</summary>
+        public EventLevel Level { get; set; }
+        /// <summary>Event's keywords: allows classification of events by "categories"</summary>
+        public EventKeywords Keywords { get; set; }
+        /// <summary>Event's operation code: allows defining operations, generally used with Tasks</summary>
+        public EventOpcode Opcode
+        {
+            get
+            {
+                return m_opcode;
+            }
+            set
+            {
+                this.m_opcode = value;
+                this.m_opcodeSet = true;
+            }
+        }
+
+        internal bool IsOpcodeSet
+        {
+            get
+            {
+                return m_opcodeSet;
+            }
+        }
+
+        /// <summary>Event's task: allows logical grouping of events</summary>
+        public EventTask Task { get; set; }
+#if FEATURE_MANAGED_ETW_CHANNELS
+        /// <summary>Event's channel: defines an event log as an additional destination for the event</summary>
+        public EventChannel Channel { get; set; }
+#endif
+        /// <summary>Event's version</summary>
+        public byte Version { get; set; }
+
+        /// <summary>
+        /// This can be specified to enable formatting and localization of the event's payload. You can 
+        /// use standard .NET substitution operators (eg {1}) in the string and they will be replaced 
+        /// with the 'ToString()' of the corresponding part of the  event payload.   
+        /// </summary>
+        public string Message { get; set; }
+
+        /// <summary>
+        /// User defined options associated with the event.  These do not have meaning to the EventSource but
+        /// are passed through to listeners which given them semantics.  
+        /// </summary>
+        public EventTags Tags { get; set; }
+
+        /// <summary>
+        /// Allows fine control over the Activity IDs generated by start and stop events
+        /// </summary>
+        public EventActivityOptions ActivityOptions { get; set; }
+
+        #region private
+        EventOpcode m_opcode;
+        private bool m_opcodeSet;
+        #endregion
+    }
+
+    /// <summary>
+    /// By default all instance methods in a class that subclasses code:EventSource that and return
+    /// void are assumed to be methods that generate an event. This default can be overridden by specifying
+    /// the code:NonEventAttribute
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Method)]
+    public sealed class NonEventAttribute : Attribute
+    {
+        /// <summary>
+        /// Constructs a default NonEventAttribute
+        /// </summary>
+        public NonEventAttribute() { }
+    }
+
+    // FUTURE we may want to expose this at some point once we have a partner that can help us validate the design.
+#if FEATURE_MANAGED_ETW_CHANNELS
+    /// <summary>
+    /// EventChannelAttribute allows customizing channels supported by an EventSource. This attribute must be
+    /// applied to an member of type EventChannel defined in a Channels class nested in the EventSource class:
+    /// <code>
+    ///     public static class Channels
+    ///     {
+    ///         [Channel(Enabled = true, EventChannelType = EventChannelType.Admin)]
+    ///         public const EventChannel Admin = (EventChannel)16;
+    ///     
+    ///         [Channel(Enabled = false, EventChannelType = EventChannelType.Operational)]
+    ///         public const EventChannel Operational = (EventChannel)17;
+    ///     }
+    /// </code>
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Field)]
+#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
+    public 
+#endif
+    class EventChannelAttribute : Attribute
+    {
+        /// <summary>
+        /// Specified whether the channel is enabled by default
+        /// </summary>
+        public bool Enabled { get; set; }
+
+        /// <summary>
+        /// Legal values are in EventChannelType
+        /// </summary>
+        public EventChannelType EventChannelType { get; set; }
+
+#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
+        /// <summary>
+        /// Specifies the isolation for the channel
+        /// </summary>
+        public EventChannelIsolation Isolation { get; set; }
+
+        /// <summary>
+        /// Specifies an SDDL access descriptor that controls access to the log file that backs the channel.
+        /// See MSDN ((http://msdn.microsoft.com/en-us/library/windows/desktop/aa382741.aspx) for details.
+        /// </summary>
+        public string Access { get; set; } 
+
+        /// <summary>
+        /// Allows importing channels defined in external manifests
+        /// </summary>
+        public string ImportChannel { get; set; }
+#endif
+
+        // TODO: there is a convention that the name is the Provider/Type   Should we provide an override?
+        // public string Name { get; set; }
+    }
+
+    /// <summary>
+    /// Allowed channel types
+    /// </summary>
+#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
+    public 
+#endif
+    enum EventChannelType
+    {
+        /// <summary>The admin channel</summary>
+        Admin = 1,
+        /// <summary>The operational channel</summary>
+        Operational,
+        /// <summary>The Analytic channel</summary>
+        Analytic,
+        /// <summary>The debug channel</summary>
+        Debug,
+    }
+
+#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
+    /// <summary>
+    /// Allowed isolation levels. See MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/aa382741.aspx) 
+    /// for the default permissions associated with each level. EventChannelIsolation and Access allows control over the 
+    /// access permissions for the channel and backing file.
+    /// </summary>
+    public 
+    enum EventChannelIsolation
+    {
+        /// <summary>
+        /// This is the default isolation level. All channels that specify Application isolation use the same ETW session
+        /// </summary>
+        Application = 1,
+        /// <summary>
+        /// All channels that specify System isolation use the same ETW session
+        /// </summary>
+        System,
+        /// <summary>
+        /// Use sparingly! When specifying Custom isolation, a separate ETW session is created for the channel.
+        /// Using Custom isolation lets you control the access permissions for the channel and backing file.
+        /// Because there are only 64 ETW sessions available, you should limit your use of Custom isolation.
+        /// </summary>
+        Custom,
+    }
+#endif
+#endif
+
+    /// <summary>
+    /// Describes the pre-defined command (EventCommandEventArgs.Command property) that is passed to the OnEventCommand callback.
+    /// </summary>
+    public enum EventCommand
+    {
+        /// <summary>
+        /// Update EventSource state
+        /// </summary>
+        Update = 0,
+        /// <summary>
+        /// Request EventSource to generate and send its manifest
+        /// </summary>
+        SendManifest = -1,
+        /// <summary>
+        /// Enable event
+        /// </summary>
+        Enable = -2,
+        /// <summary>
+        /// Disable event
+        /// </summary>
+        Disable = -3
+    };
+
+
+    #region private classes
+
+#if FEATURE_ACTIVITYSAMPLING
+
+    /// <summary>
+    /// ActivityFilter is a helper structure that is used to keep track of run-time state
+    /// associated with activity filtering. It is 1-1 with EventListeners (logically
+    /// every listener has one of these, however we actually allocate them lazily), as well
+    /// as 1-to-1 with tracing-aware EtwSessions.
+    /// 
+    /// This structure also keeps track of the sampling counts associated with 'trigger'
+    /// events.  Because these trigger events are rare, and you typically only have one of
+    /// them, we store them here as a linked list.
+    /// </summary>
+    internal sealed class ActivityFilter : IDisposable
+    {
+        /// <summary>
+        /// Disable all activity filtering for the listener associated with 'filterList', 
+        /// (in the session associated with it) that is triggered by any event in 'source'.
+        /// </summary>
+        public static void DisableFilter(ref ActivityFilter filterList, EventSource source)
+        {
+#if !ES_BUILD_STANDALONE
+            Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
+#endif
+
+            if (filterList == null)
+                return;
+
+            ActivityFilter cur;
+            // Remove it from anywhere in the list (except the first element, which has to 
+            // be treated specially)
+            ActivityFilter prev = filterList;
+            cur = prev.m_next;
+            while (cur != null)
+            {
+                if (cur.m_providerGuid == source.Guid)
+                {
+                    // update TriggersActivityTracking bit
+                    if (cur.m_eventId >= 0 && cur.m_eventId < source.m_eventData.Length)
+                        --source.m_eventData[cur.m_eventId].TriggersActivityTracking;
+
+                    // Remove it from the linked list.
+                    prev.m_next = cur.m_next;
+                    // dispose of the removed node
+                    cur.Dispose();
+                    // update cursor
+                    cur = prev.m_next;
+                }
+                else
+                {
+                    // update cursors
+                    prev = cur;
+                    cur = prev.m_next;
+                }
+            }
+
+            // Sadly we have to treat the first element specially in linked list removal in C#
+            if (filterList.m_providerGuid == source.Guid)
+            {
+                // update TriggersActivityTracking bit
+                if (filterList.m_eventId >= 0 && filterList.m_eventId < source.m_eventData.Length)
+                    --source.m_eventData[filterList.m_eventId].TriggersActivityTracking;
+
+                // We are the first element in the list.   
+                var first = filterList;
+                filterList = first.m_next;
+                // dispose of the removed node
+                first.Dispose();
+            }
+            // the above might have removed the one ActivityFilter in the session that contains the 
+            // cleanup delegate; re-create the delegate if needed
+            if (filterList != null)
+            {
+                EnsureActivityCleanupDelegate(filterList);
+            }
+        }
+
+        /// <summary>
+        /// Currently this has "override" semantics. We first disable all filters
+        /// associated with 'source', and next we add new filters for each entry in the 
+        /// string 'startEvents'. participateInSampling specifies whether non-startEvents 
+        /// always trigger or only trigger when current activity is 'active'.
+        /// </summary>
+        public static void UpdateFilter(
+                                    ref ActivityFilter filterList,
+                                    EventSource source,
+                                    int perEventSourceSessionId,
+                                    string startEvents)
+        {
+#if !ES_BUILD_STANDALONE
+            Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
+#endif
+
+            // first remove all filters associated with 'source'
+            DisableFilter(ref filterList, source);
+
+            if (!string.IsNullOrEmpty(startEvents))
+            {
+                // ActivitySamplingStartEvents is a space-separated list of Event:Frequency pairs.
+                // The Event may be specified by name or by ID. Errors in parsing such a pair 
+                // result in the error being reported to the listeners, and the pair being ignored.
+                // E.g. "CustomActivityStart:1000 12:10" specifies that for event CustomActivityStart
+                // we should initiate activity tracing once every 1000 events, *and* for event ID 12
+                // we should initiate activity tracing once every 10 events.
+                string[] activityFilterStrings = startEvents.Split(' ');
+
+                for (int i = 0; i < activityFilterStrings.Length; ++i)
+                {
+                    string activityFilterString = activityFilterStrings[i];
+                    int sampleFreq = 1;
+                    int eventId = -1;
+                    int colonIdx = activityFilterString.IndexOf(':');
+                    if (colonIdx < 0)
+                    {
+                        source.ReportOutOfBandMessage("ERROR: Invalid ActivitySamplingStartEvent specification: " +
+                            activityFilterString, false);
+                        // ignore failure...
+                        continue;
+                    }
+                    string sFreq = activityFilterString.Substring(colonIdx + 1);
+                    if (!int.TryParse(sFreq, out sampleFreq))
+                    {
+                        source.ReportOutOfBandMessage("ERROR: Invalid sampling frequency specification: " + sFreq, false);
+                        continue;
+                    }
+                    activityFilterString = activityFilterString.Substring(0, colonIdx);
+                    if (!int.TryParse(activityFilterString, out eventId))
+                    {
+                        // reset eventId
+                        eventId = -1;
+                        // see if it's an event name
+                        for (int j = 0; j < source.m_eventData.Length; j++)
+                        {
+                            EventSource.EventMetadata[] ed = source.m_eventData;
+                            if (ed[j].Name != null && ed[j].Name.Length == activityFilterString.Length &&
+                                string.Compare(ed[j].Name, activityFilterString, StringComparison.OrdinalIgnoreCase) == 0)
+                            {
+                                eventId = ed[j].Descriptor.EventId;
+                                break;
+                            }
+                        }
+                    }
+                    if (eventId < 0 || eventId >= source.m_eventData.Length)
+                    {
+                        source.ReportOutOfBandMessage("ERROR: Invalid eventId specification: " + activityFilterString, false);
+                        continue;
+                    }
+                    EnableFilter(ref filterList, source, perEventSourceSessionId, eventId, sampleFreq);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Returns the first ActivityFilter from 'filterList' corresponding to 'source'.
+        /// </summary>
+        public static ActivityFilter GetFilter(ActivityFilter filterList, EventSource source)
+        {
+            for (var af = filterList; af != null; af = af.m_next)
+            {
+                if (af.m_providerGuid == source.Guid && af.m_samplingFreq != -1)
+                    return af;
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Returns a session mask representing all sessions in which the activity 
+        /// associated with the current thread is allowed  through the activity filter. 
+        /// If 'triggeringEvent' is true the event MAY be a triggering event. Ideally 
+        /// most of the time this is false as you can guarentee this event is NOT a 
+        /// triggering event. If 'triggeringEvent' is true, then it checks the 
+        /// 'EventSource' and 'eventID' of the event being logged to see if it is actually
+        /// a trigger. If so it activates the current activity. 
+        /// 
+        /// If 'childActivityID' is present, it will be added to the active set if the 
+        /// current activity is active.  
+        /// </summary>
+        unsafe public static bool PassesActivityFilter(
+                                    ActivityFilter filterList,
+                                    Guid* childActivityID,
+                                    bool triggeringEvent,
+                                    EventSource source,
+                                    int eventId)
+        {
+            Debug.Assert(filterList != null && filterList.m_activeActivities != null);
+            bool shouldBeLogged = false;
+            if (triggeringEvent)
+            {
+                for (ActivityFilter af = filterList; af != null; af = af.m_next)
+                {
+                    if (eventId == af.m_eventId && source.Guid == af.m_providerGuid)
+                    {
+                        // Update the sampling count with wrap-around
+                        int curSampleCount, newSampleCount;
+                        do
+                        {
+                            curSampleCount = af.m_curSampleCount;
+                            if (curSampleCount <= 1)
+                                newSampleCount = af.m_samplingFreq;        // Wrap around, counting down to 1
+                            else
+                                newSampleCount = curSampleCount - 1;
+                        }
+                        while (Interlocked.CompareExchange(ref af.m_curSampleCount, newSampleCount, curSampleCount) != curSampleCount);
+                        // If we hit zero, then start tracking the activity.  
+                        if (curSampleCount <= 1)
+                        {
+                            Guid currentActivityId = EventSource.InternalCurrentThreadActivityId;
+                            Tuple<Guid, int> startId;
+                            // only add current activity if it's not already a root activity
+                            if (!af.m_rootActiveActivities.TryGetValue(currentActivityId, out startId))
+                            {
+                                // EventSource.OutputDebugString(string.Format("  PassesAF - Triggering(session {0}, evt {1})", af.m_perEventSourceSessionId, eventId));
+                                shouldBeLogged = true;
+                                af.m_activeActivities[currentActivityId] = Environment.TickCount;
+                                af.m_rootActiveActivities[currentActivityId] = Tuple.Create(source.Guid, eventId);
+                            }
+                        }
+                        else
+                        {
+                            // a start event following a triggering start event
+                            Guid currentActivityId = EventSource.InternalCurrentThreadActivityId;
+                            Tuple<Guid, int> startId;
+                            // only remove current activity if we added it
+                            if (af.m_rootActiveActivities.TryGetValue(currentActivityId, out startId) &&
+                                startId.Item1 == source.Guid && startId.Item2 == eventId)
+                            {
+                                // EventSource.OutputDebugString(string.Format("Activity dying: {0} -> StartEvent({1})", currentActivityId, eventId));
+                                // remove activity only from current logging scope (af)
+                                int dummy;
+                                af.m_activeActivities.TryRemove(currentActivityId, out dummy);
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+
+            var activeActivities = GetActiveActivities(filterList);
+            if (activeActivities != null)
+            {
+                // if we hadn't already determined this should be logged, test further
+                if (!shouldBeLogged)
+                {
+                    shouldBeLogged = !activeActivities.IsEmpty &&
+                                     activeActivities.ContainsKey(EventSource.InternalCurrentThreadActivityId);
+                }
+                if (shouldBeLogged && childActivityID != null &&
+                    ((EventOpcode)source.m_eventData[eventId].Descriptor.Opcode == EventOpcode.Send))
+                {
+                    FlowActivityIfNeeded(filterList, null, childActivityID);
+                    // EventSource.OutputDebugString(string.Format("  PassesAF - activity {0}", *childActivityID));
+                }
+            }
+            // EventSource.OutputDebugString(string.Format("  PassesAF - shouldBeLogged(evt {0}) = {1:x}", eventId, shouldBeLogged));
+            return shouldBeLogged;
+        }
+
+        public static bool IsCurrentActivityActive(ActivityFilter filterList)
+        {
+            var activeActivities = GetActiveActivities(filterList);
+            if (activeActivities != null &&
+                activeActivities.ContainsKey(EventSource.InternalCurrentThreadActivityId))
+                return true;
+
+            return false;
+        }
+
+        /// <summary>
+        /// For the EventListener/EtwSession associated with 'filterList', add 'childActivityid'
+        /// to list of active activities IF 'currentActivityId' is also active. Passing in a null
+        /// value for  'currentActivityid' is an indication tha caller has already verified
+        /// that the current activity is active.
+        /// </summary>
+        unsafe public static void FlowActivityIfNeeded(ActivityFilter filterList, Guid* currentActivityId, Guid* childActivityID)
+        {
+            Debug.Assert(childActivityID != null);
+
+            var activeActivities = GetActiveActivities(filterList);
+            Debug.Assert(activeActivities != null);
+
+            // take currentActivityId == null to mean we *know* the current activity is "active"
+            if (currentActivityId != null && !activeActivities.ContainsKey(*currentActivityId))
+                return;
+
+            if (activeActivities.Count > MaxActivityTrackCount)
+            {
+                TrimActiveActivityStore(activeActivities);
+                // make sure current activity is still in the set:
+                activeActivities[EventSource.InternalCurrentThreadActivityId] = Environment.TickCount;
+            }
+            // add child activity to list of actives
+            activeActivities[*childActivityID] = Environment.TickCount;
+
+        }
+
+        /// <summary>
+        /// </summary>
+        public static void UpdateKwdTriggers(ActivityFilter activityFilter, Guid sourceGuid, EventSource source, EventKeywords sessKeywords)
+        {
+            for (var af = activityFilter; af != null; af = af.m_next)
+            {
+                if ((sourceGuid == af.m_providerGuid) &&
+                    (source.m_eventData[af.m_eventId].TriggersActivityTracking > 0 ||
+                    ((EventOpcode)source.m_eventData[af.m_eventId].Descriptor.Opcode == EventOpcode.Send)))
+                {
+                    // we could be more precise here, if we tracked 'anykeywords' per session
+                    unchecked
+                    {
+                        source.m_keywordTriggers |= (source.m_eventData[af.m_eventId].Descriptor.Keywords & (long)sessKeywords);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// For the EventSource specified by 'sourceGuid' and the EventListener/EtwSession 
+        /// associated with 'this' ActivityFilter list, return configured sequence of 
+        /// [eventId, sampleFreq] pairs that defines the sampling policy.
+        /// </summary>
+        public IEnumerable<Tuple<int, int>> GetFilterAsTuple(Guid sourceGuid)
+        {
+            for (ActivityFilter af = this; af != null; af = af.m_next)
+            {
+                if (af.m_providerGuid == sourceGuid)
+                    yield return Tuple.Create(af.m_eventId, af.m_samplingFreq);
+            }
+        }
+
+        /// <summary>
+        /// The cleanup being performed consists of removing the m_myActivityDelegate from
+        /// the static s_activityDying, therefore allowing the ActivityFilter to be reclaimed.
+        /// </summary>
+        public void Dispose()
+        {
+#if !ES_BUILD_STANDALONE
+            Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
+#endif
+            // m_myActivityDelegate is still alive (held by the static EventSource.s_activityDying). 
+            // Therefore we are ok to take a dependency on m_myActivityDelegate being valid even 
+            // during the finalization of the ActivityFilter
+            if (m_myActivityDelegate != null)
+            {
+                EventSource.s_activityDying = (Action<Guid>)Delegate.Remove(EventSource.s_activityDying, m_myActivityDelegate);
+                m_myActivityDelegate = null;
+            }
+        }
+
+        #region private
+
+        /// <summary>
+        /// Creates a new ActivityFilter that is triggered by 'eventId' from 'source' ever
+        /// 'samplingFreq' times the event fires. You can have several of these forming a 
+        /// linked list.
+        /// </summary>
+        private ActivityFilter(EventSource source, int perEventSourceSessionId, int eventId, int samplingFreq, ActivityFilter existingFilter = null)
+        {
+            m_providerGuid = source.Guid;
+            m_perEventSourceSessionId = perEventSourceSessionId;
+            m_eventId = eventId;
+            m_samplingFreq = samplingFreq;
+            m_next = existingFilter;
+
+            Debug.Assert(existingFilter == null ||
+                            (existingFilter.m_activeActivities == null) == (existingFilter.m_rootActiveActivities == null));
+
+            // if this is the first filter we add for this session, we need to create a new 
+            // table of activities. m_activeActivities is common across EventSources in the same
+            // session
+            ConcurrentDictionary<Guid, int> activeActivities = null;
+            if (existingFilter == null ||
+                (activeActivities = GetActiveActivities(existingFilter)) == null)
+            {
+                m_activeActivities = new ConcurrentDictionary<Guid, int>();
+                m_rootActiveActivities = new ConcurrentDictionary<Guid, Tuple<Guid, int>>();
+
+                // Add a delegate to the 'SetCurrentThreadToActivity callback so that I remove 'dead' activities
+                m_myActivityDelegate = GetActivityDyingDelegate(this);
+                EventSource.s_activityDying = (Action<Guid>)Delegate.Combine(EventSource.s_activityDying, m_myActivityDelegate);
+            }
+            else
+            {
+                m_activeActivities = activeActivities;
+                m_rootActiveActivities = existingFilter.m_rootActiveActivities;
+            }
+
+        }
+
+        /// <summary>
+        /// Ensure there's at least one ActivityFilter in the 'filterList' that contains an
+        /// activity-removing delegate for the listener/session associated with 'filterList'.
+        /// </summary>
+        private static void EnsureActivityCleanupDelegate(ActivityFilter filterList)
+        {
+            if (filterList == null)
+                return;
+
+            for (ActivityFilter af = filterList; af != null; af = af.m_next)
+            {
+                if (af.m_myActivityDelegate != null)
+                    return;
+            }
+
+            // we didn't find a delegate
+            filterList.m_myActivityDelegate = GetActivityDyingDelegate(filterList);
+            EventSource.s_activityDying = (Action<Guid>)Delegate.Combine(EventSource.s_activityDying, filterList.m_myActivityDelegate);
+        }
+
+        /// <summary>
+        /// Builds the delegate to be called when an activity is dying. This is responsible
+        /// for performing whatever cleanup is needed for the ActivityFilter list passed in.
+        /// This gets "added" to EventSource.s_activityDying and ends up being called from
+        /// EventSource.SetCurrentThreadActivityId and ActivityFilter.PassesActivityFilter.
+        /// </summary>
+        /// <returns>The delegate to be called when an activity is dying</returns>
+        private static Action<Guid> GetActivityDyingDelegate(ActivityFilter filterList)
+        {
+            return (Guid oldActivity) =>
+            {
+                int dummy;
+                filterList.m_activeActivities.TryRemove(oldActivity, out dummy);
+                Tuple<Guid, int> dummyTuple;
+                filterList.m_rootActiveActivities.TryRemove(oldActivity, out dummyTuple);
+            };
+        }
+
+        /// <summary>
+        /// Enables activity filtering for the listener associated with 'filterList', triggering on
+        /// the event 'eventID' from 'source' with a sampling frequency of 'samplingFreq'
+        /// 
+        /// if 'eventID' is out of range (e.g. negative), it means we are not triggering (but we are 
+        /// activitySampling if something else triggered).  
+        /// </summary>
+        /// <returns>true if activity sampling is enabled the samplingFreq is non-zero </returns>
+        private static bool EnableFilter(ref ActivityFilter filterList, EventSource source, int perEventSourceSessionId, int eventId, int samplingFreq)
+        {
+#if !ES_BUILD_STANDALONE
+            Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
+#endif
+            Debug.Assert(samplingFreq > 0);
+            Debug.Assert(eventId >= 0);
+
+            filterList = new ActivityFilter(source, perEventSourceSessionId, eventId, samplingFreq, filterList);
+
+            // Mark the 'quick Check' that indicates this is a trigger event.  
+            // If eventId is out of range then this mark is not done which has the effect of ignoring 
+            // the trigger.
+            if (0 <= eventId && eventId < source.m_eventData.Length)
+                ++source.m_eventData[eventId].TriggersActivityTracking;
+
+            return true;
+        }
+
+        /// <summary>
+        /// Normally this code never runs, it is here just to prevent run-away resource usage.  
+        /// </summary>
+        private static void TrimActiveActivityStore(ConcurrentDictionary<Guid, int> activities)
+        {
+            if (activities.Count > MaxActivityTrackCount)
+            {
+                // Remove half of the oldest activity ids.  
+                var keyValues = activities.ToArray();
+                var tickNow = Environment.TickCount;
+
+                // Sort by age, taking into account wrap-around.   As long as x and y are within 
+                // 23 days of now then (0x7FFFFFFF & (tickNow - x.Value)) is the delta (even if 
+                // TickCount wraps).  I then sort by DESCENDING age.  (that is oldest value first)
+                Array.Sort(keyValues, (x, y) => (0x7FFFFFFF & (tickNow - y.Value)) - (0x7FFFFFFF & (tickNow - x.Value)));
+                for (int i = 0; i < keyValues.Length / 2; i++)
+                {
+                    int dummy;
+                    activities.TryRemove(keyValues[i].Key, out dummy);
+                }
+            }
+        }
+
+        private static ConcurrentDictionary<Guid, int> GetActiveActivities(
+                                    ActivityFilter filterList)
+        {
+            for (ActivityFilter af = filterList; af != null; af = af.m_next)
+            {
+                if (af.m_activeActivities != null)
+                    return af.m_activeActivities;
+            }
+            return null;
+        }
+
+        // m_activeActivities always points to the sample dictionary for EVERY ActivityFilter  
+        // in the m_next list. The 'int' value in the m_activities set is a timestamp 
+        // (Environment.TickCount) of when the entry was put in the system and is used to 
+        // remove 'old' entries that if the set gets too big.
+        ConcurrentDictionary<Guid, int> m_activeActivities;
+
+        // m_rootActiveActivities holds the "root" active activities, i.e. the activities 
+        // that were marked as active because a Start event fired on them. We need to keep
+        // track of these to enable sampling in the scenario of an app's main thread that 
+        // never explicitly sets distinct activity IDs as it executes. To handle these
+        // situations we manufacture a Guid from the thread's ID, and:
+        //   (a) we consider the firing of a start event when the sampling counter reaches 
+        //       zero to mark the beginning of an interesting activity, and 
+        //   (b) we consider the very next firing of the same start event to mark the
+        //       ending of that activity.
+        // We use a ConcurrentDictionary to avoid taking explicit locks.
+        //   The key (a guid) represents the activity ID of the root active activity
+        //   The value is made up of the Guid of the event provider and the eventId of
+        //      the start event.
+        ConcurrentDictionary<Guid, Tuple<Guid, int>> m_rootActiveActivities;
+        Guid m_providerGuid;        // We use the GUID rather than object identity because we don't want to keep the eventSource alive
+        int m_eventId;              // triggering event
+        int m_samplingFreq;         // Counter reset to this when it hits 0
+        int m_curSampleCount;       // We count down to 0 and then activate the activity. 
+        int m_perEventSourceSessionId;  // session ID bit for ETW, 0 for EventListeners
+
+        const int MaxActivityTrackCount = 100000;   // maximum number of tracked activities
+
+        ActivityFilter m_next;      // We create a linked list of these
+        Action<Guid> m_myActivityDelegate;
+        #endregion
+    };
+
+
+    /// <summary>
+    /// An EtwSession instance represents an activity-tracing-aware ETW session. Since these
+    /// are limited to 8 concurrent sessions per machine (currently) we're going to store
+    /// the active ones in a singly linked list.
+    /// </summary>
+    internal class EtwSession
+    {
+        public static EtwSession GetEtwSession(int etwSessionId, bool bCreateIfNeeded = false)
+        {
+            if (etwSessionId < 0)
+                return null;
+
+            EtwSession etwSession;
+            foreach (var wrEtwSession in s_etwSessions)
+            {
+#if ES_BUILD_STANDALONE
+                if ((etwSession = (EtwSession) wrEtwSession.Target) != null && etwSession.m_etwSessionId == etwSessionId)
+                    return etwSession;
+#else
+                if (wrEtwSession.TryGetTarget(out etwSession) && etwSession.m_etwSessionId == etwSessionId)
+                    return etwSession;
+#endif
+            }
+
+            if (!bCreateIfNeeded)
+                return null;
+
+#if ES_BUILD_STANDALONE
+            if (s_etwSessions == null)
+                s_etwSessions = new List<WeakReference>();
+
+            etwSession = new EtwSession(etwSessionId);
+            s_etwSessions.Add(new WeakReference(etwSession));
+#else
+            if (s_etwSessions == null)
+                s_etwSessions = new List<WeakReference<EtwSession>>();
+
+            etwSession = new EtwSession(etwSessionId);
+            s_etwSessions.Add(new WeakReference<EtwSession>(etwSession));
+#endif
+
+            if (s_etwSessions.Count > s_thrSessionCount)
+                TrimGlobalList();
+
+            return etwSession;
+
+        }
+
+        public static void RemoveEtwSession(EtwSession etwSession)
+        {
+            Debug.Assert(etwSession != null);
+            if (s_etwSessions == null || etwSession == null)
+                return;
+
+            s_etwSessions.RemoveAll((wrEtwSession) =>
+                {
+                    EtwSession session;
+#if ES_BUILD_STANDALONE
+                    return (session = (EtwSession) wrEtwSession.Target) != null &&
+                           (session.m_etwSessionId == etwSession.m_etwSessionId);
+#else
+                    return wrEtwSession.TryGetTarget(out session) &&
+                           (session.m_etwSessionId == etwSession.m_etwSessionId);
+#endif
+                });
+
+            if (s_etwSessions.Count > s_thrSessionCount)
+                TrimGlobalList();
+        }
+
+        private static void TrimGlobalList()
+        {
+            if (s_etwSessions == null)
+                return;
+
+            s_etwSessions.RemoveAll((wrEtwSession) =>
+                {
+#if ES_BUILD_STANDALONE
+                    return wrEtwSession.Target == null;
+#else
+                    EtwSession session;
+                    return !wrEtwSession.TryGetTarget(out session);
+#endif
+                });
+        }
+
+        private EtwSession(int etwSessionId)
+        {
+            m_etwSessionId = etwSessionId;
+        }
+
+        public readonly int m_etwSessionId;        // ETW session ID (as retrieved by EventProvider)
+        public ActivityFilter m_activityFilter;    // all filters enabled for this session
+
+#if ES_BUILD_STANDALONE
+        private static List<WeakReference> s_etwSessions = new List<WeakReference>();
+#else
+        private static List<WeakReference<EtwSession>> s_etwSessions = new List<WeakReference<EtwSession>>();
+#endif
+        private const int s_thrSessionCount = 16;
+    }
+
+#endif // FEATURE_ACTIVITYSAMPLING
+
+    // holds a bitfield representing a session mask
+    /// <summary>
+    /// A SessionMask represents a set of (at most MAX) sessions as a bit mask. The perEventSourceSessionId
+    /// is the index in the SessionMask of the bit that will be set. These can translate to
+    /// EventSource's reserved keywords bits using the provided ToEventKeywords() and
+    /// FromEventKeywords() methods.
+    /// </summary>
+    internal struct SessionMask
+    {
+        public SessionMask(SessionMask m)
+        { m_mask = m.m_mask; }
+
+        public SessionMask(uint mask = 0)
+        { m_mask = mask & MASK; }
+
+        public bool IsEqualOrSupersetOf(SessionMask m)
+        {
+            return (this.m_mask | m.m_mask) == this.m_mask;
+        }
+
+        public static SessionMask All
+        {
+            get { return new SessionMask(MASK); }
+        }
+
+        public static SessionMask FromId(int perEventSourceSessionId)
+        {
+            Debug.Assert(perEventSourceSessionId < MAX);
+            return new SessionMask((uint)1 << perEventSourceSessionId);
+        }
+
+        public ulong ToEventKeywords()
+        {
+            return (ulong)m_mask << SHIFT_SESSION_TO_KEYWORD;
+        }
+
+        public static SessionMask FromEventKeywords(ulong m)
+        {
+            return new SessionMask((uint)(m >> SHIFT_SESSION_TO_KEYWORD));
+        }
+
+        public bool this[int perEventSourceSessionId]
+        {
+            get
+            {
+                Debug.Assert(perEventSourceSessionId < MAX);
+                return (m_mask & (1 << perEventSourceSessionId)) != 0;
+            }
+            set
+            {
+                Debug.Assert(perEventSourceSessionId < MAX);
+                if (value) m_mask |= ((uint)1 << perEventSourceSessionId);
+                else m_mask &= ~((uint)1 << perEventSourceSessionId);
+            }
+        }
+
+        public static SessionMask operator |(SessionMask m1, SessionMask m2)
+        {
+            return new SessionMask(m1.m_mask | m2.m_mask);
+        }
+
+        public static SessionMask operator &(SessionMask m1, SessionMask m2)
+        {
+            return new SessionMask(m1.m_mask & m2.m_mask);
+        }
+
+        public static SessionMask operator ^(SessionMask m1, SessionMask m2)
+        {
+            return new SessionMask(m1.m_mask ^ m2.m_mask);
+        }
+
+        public static SessionMask operator ~(SessionMask m)
+        {
+            return new SessionMask(MASK & ~(m.m_mask));
+        }
+
+        public static explicit operator ulong(SessionMask m)
+        { return m.m_mask; }
+
+        public static explicit operator uint(SessionMask m)
+        { return m.m_mask; }
+
+        private uint m_mask;
+
+        internal const int SHIFT_SESSION_TO_KEYWORD = 44;         // bits 44-47 inclusive are reserved
+        internal const uint MASK = 0x0fU;                         // the mask of 4 reserved bits
+        internal const uint MAX = 4;                              // maximum number of simultaneous ETW sessions supported
+    }
+
+    /// <summary>
+    /// code:EventDispatchers are a simple 'helper' structure that holds the filtering state
+    /// (m_EventEnabled) for a particular EventSource X EventListener tuple
+    /// 
+    /// Thus a single EventListener may have many EventDispatchers (one for every EventSource 
+    /// that that EventListener has activate) and a Single EventSource may also have many
+    /// event Dispatchers (one for every EventListener that has activated it). 
+    /// 
+    /// Logically a particular EventDispatcher belongs to exactly one EventSource and exactly  
+    /// one EventListener (alhtough EventDispatcher does not 'remember' the EventSource it is
+    /// associated with. 
+    /// </summary>
+    internal class EventDispatcher
+    {
+        internal EventDispatcher(EventDispatcher next, bool[] eventEnabled, EventListener listener)
+        {
+            m_Next = next;
+            m_EventEnabled = eventEnabled;
+            m_Listener = listener;
+        }
+
+        // Instance fields
+        readonly internal EventListener m_Listener;   // The dispatcher this entry is for
+        internal bool[] m_EventEnabled;               // For every event in a the eventSource, is it enabled?
+#if FEATURE_ACTIVITYSAMPLING
+        internal bool m_activityFilteringEnabled;     // does THIS EventSource have activity filtering turned on for this listener?
+#endif // FEATURE_ACTIVITYSAMPLING
+
+        // Only guaranteed to exist after a InsureInit()
+        internal EventDispatcher m_Next;              // These form a linked list in code:EventSource.m_Dispatchers
+        // Of all listeners for that eventSource.  
+    }
+
+    /// <summary>
+    /// Flags that can be used with EventSource.GenerateManifest to control how the ETW manifest for the EventSource is
+    /// generated.
+    /// </summary>
+    [Flags]
+    public enum EventManifestOptions
+    {
+        /// <summary>
+        /// Only the resources associated with current UI culture are included in the  manifest
+        /// </summary>
+        None = 0x0,
+        /// <summary>
+        /// Throw exceptions for any inconsistency encountered
+        /// </summary>
+        Strict = 0x1,
+        /// <summary>
+        /// Generate a "resources" node under "localization" for every satellite assembly provided
+        /// </summary>
+        AllCultures = 0x2,
+        /// <summary>
+        /// Generate the manifest only if the event source needs to be registered on the machine,
+        /// otherwise return null (but still perform validation if Strict is specified)
+        /// </summary>
+        OnlyIfNeededForRegistration = 0x4,
+        /// <summary>
+        /// When generating the manifest do *not* enforce the rule that the current EventSource class
+        /// must be the base class for the user-defined type passed in. This allows validation of .net
+        /// event sources using the new validation code
+        /// </summary>
+        AllowEventSourceOverride = 0x8,
+    }
+
+    /// <summary>
+    /// ManifestBuilder is designed to isolate the details of the message of the event from the
+    /// rest of EventSource.  This one happens to create XML. 
+    /// </summary>
+    internal partial class ManifestBuilder
+    {
+        /// <summary>
+        /// Build a manifest for 'providerName' with the given GUID, which will be packaged into 'dllName'.
+        /// 'resources, is a resource manager.  If specified all messages are localized using that manager.  
+        /// </summary>
+        public ManifestBuilder(string providerName, Guid providerGuid, string dllName, ResourceManager resources,
+                               EventManifestOptions flags)
+        {
+#if FEATURE_MANAGED_ETW_CHANNELS
+            this.providerName = providerName;
+#endif
+            this.flags = flags;
+
+            this.resources = resources;
+            sb = new StringBuilder();
+            events = new StringBuilder();
+            templates = new StringBuilder();
+            opcodeTab = new Dictionary<int, string>();
+            stringTab = new Dictionary<string, string>();
+            errors = new List<string>();
+            perEventByteArrayArgIndices = new Dictionary<string, List<int>>();
+
+            sb.AppendLine("<instrumentationManifest xmlns=\"http://schemas.microsoft.com/win/2004/08/events\">");
+            sb.AppendLine(" <instrumentation xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:win=\"http://manifests.microsoft.com/win/2004/08/windows/events\">");
+            sb.AppendLine("  <events xmlns=\"http://schemas.microsoft.com/win/2004/08/events\">");
+            sb.Append("<provider name=\"").Append(providerName).
+               Append("\" guid=\"{").Append(providerGuid.ToString()).Append("}");
+            if (dllName != null)
+                sb.Append("\" resourceFileName=\"").Append(dllName).Append("\" messageFileName=\"").Append(dllName);
+
+            var symbolsName = providerName.Replace("-", "").Replace(".", "_");  // Period and - are illegal replace them.
+            sb.Append("\" symbol=\"").Append(symbolsName);
+            sb.Append("\">").AppendLine();
+        }
+
+        public void AddOpcode(string name, int value)
+        {
+            if ((flags & EventManifestOptions.Strict) != 0)
+            {
+                if (value <= 10 || value >= 239)
+                {
+                    ManifestError(Resources.GetResourceString("EventSource_IllegalOpcodeValue", name, value));
+                }
+                string prevName;
+                if (opcodeTab.TryGetValue(value, out prevName) && !name.Equals(prevName, StringComparison.Ordinal))
+                {
+                    ManifestError(Resources.GetResourceString("EventSource_OpcodeCollision", name, prevName, value));
+                }
+            }
+            opcodeTab[value] = name;
+        }
+        public void AddTask(string name, int value)
+        {
+            if ((flags & EventManifestOptions.Strict) != 0)
+            {
+                if (value <= 0 || value >= 65535)
+                {
+                    ManifestError(Resources.GetResourceString("EventSource_IllegalTaskValue", name, value));
+                }
+                string prevName;
+                if (taskTab != null && taskTab.TryGetValue(value, out prevName) && !name.Equals(prevName, StringComparison.Ordinal))
+                {
+                    ManifestError(Resources.GetResourceString("EventSource_TaskCollision", name, prevName, value));
+                }
+            }
+            if (taskTab == null)
+                taskTab = new Dictionary<int, string>();
+            taskTab[value] = name;
+        }
+        public void AddKeyword(string name, ulong value)
+        {
+            if ((value & (value - 1)) != 0)   // Is it a power of 2?
+            {
+                ManifestError(Resources.GetResourceString("EventSource_KeywordNeedPowerOfTwo", "0x" + value.ToString("x", CultureInfo.CurrentCulture), name), true);
+            }
+            if ((flags & EventManifestOptions.Strict) != 0)
+            {
+                if (value >= 0x0000100000000000UL && !name.StartsWith("Session", StringComparison.Ordinal))
+                {
+                    ManifestError(Resources.GetResourceString("EventSource_IllegalKeywordsValue", name, "0x" + value.ToString("x", CultureInfo.CurrentCulture)));
+                }
+                string prevName;
+                if (keywordTab != null && keywordTab.TryGetValue(value, out prevName) && !name.Equals(prevName, StringComparison.Ordinal))
+                {
+                    ManifestError(Resources.GetResourceString("EventSource_KeywordCollision", name, prevName, "0x" + value.ToString("x", CultureInfo.CurrentCulture)));
+                }
+            }
+            if (keywordTab == null)
+                keywordTab = new Dictionary<ulong, string>();
+            keywordTab[value] = name;
+        }
+
+#if FEATURE_MANAGED_ETW_CHANNELS
+        /// <summary>
+        /// Add a channel.  channelAttribute can be null
+        /// </summary>
+        public void AddChannel(string name, int value, EventChannelAttribute channelAttribute)
+        {
+            EventChannel chValue = (EventChannel)value;
+            if (value < (int)EventChannel.Admin || value > 255)
+                ManifestError(Resources.GetResourceString("EventSource_EventChannelOutOfRange", name, value));
+            else if (chValue >= EventChannel.Admin && chValue <= EventChannel.Debug &&
+                     channelAttribute != null && EventChannelToChannelType(chValue) != channelAttribute.EventChannelType)
+            {
+                // we want to ensure developers do not define EventChannels that conflict with the builtin ones,
+                // but we want to allow them to override the default ones...
+                ManifestError(Resources.GetResourceString("EventSource_ChannelTypeDoesNotMatchEventChannelValue",
+                                                                            name, ((EventChannel)value).ToString()));
+            }
+
+            // TODO: validate there are no conflicting manifest exposed names (generally following the format "provider/type")
+
+            ulong kwd = GetChannelKeyword(chValue);
+
+            if (channelTab == null)
+                channelTab = new Dictionary<int, ChannelInfo>(4);
+            channelTab[value] = new ChannelInfo { Name = name, Keywords = kwd, Attribs = channelAttribute };
+        }
+
+        private EventChannelType EventChannelToChannelType(EventChannel channel)
+        {
+#if !ES_BUILD_STANDALONE
+            Debug.Assert(channel >= EventChannel.Admin && channel <= EventChannel.Debug);
+#endif
+            return (EventChannelType)((int)channel - (int)EventChannel.Admin + (int)EventChannelType.Admin);
+        }
+        private EventChannelAttribute GetDefaultChannelAttribute(EventChannel channel)
+        {
+            EventChannelAttribute attrib = new EventChannelAttribute();
+            attrib.EventChannelType = EventChannelToChannelType(channel);
+            if (attrib.EventChannelType <= EventChannelType.Operational)
+                attrib.Enabled = true;
+            return attrib;
+        }
+
+        public ulong[] GetChannelData()
+        {
+            if (this.channelTab == null)
+            {
+                return new ulong[0];
+            }
+
+            // We create an array indexed by the channel id for fast look up.
+            // E.g. channelMask[Admin] will give you the bit mask for Admin channel.
+            int maxkey = -1;
+            foreach (var item in this.channelTab.Keys)
+            {
+                if (item > maxkey)
+                {
+                    maxkey = item;
+                }
+            }
+
+            ulong[] channelMask = new ulong[maxkey + 1];
+            foreach (var item in this.channelTab)
+            {
+                channelMask[item.Key] = item.Value.Keywords;
+            }
+
+            return channelMask;
+        }
+
+#endif
+        public void StartEvent(string eventName, EventAttribute eventAttribute)
+        {
+            Debug.Assert(numParams == 0);
+            Debug.Assert(this.eventName == null);
+            this.eventName = eventName;
+            numParams = 0;
+            byteArrArgIndices = null;
+
+            events.Append("  <event").
+                 Append(" value=\"").Append(eventAttribute.EventId).Append("\"").
+                 Append(" version=\"").Append(eventAttribute.Version).Append("\"").
+                 Append(" level=\"").Append(GetLevelName(eventAttribute.Level)).Append("\"").
+                 Append(" symbol=\"").Append(eventName).Append("\"");
+
+            // at this point we add to the manifest's stringTab a message that is as-of-yet 
+            // "untranslated to manifest convention", b/c we don't have the number or position 
+            // of any byte[] args (which require string format index updates)
+            WriteMessageAttrib(events, "event", eventName, eventAttribute.Message);
+
+            if (eventAttribute.Keywords != 0)
+                events.Append(" keywords=\"").Append(GetKeywords((ulong)eventAttribute.Keywords, eventName)).Append("\"");
+            if (eventAttribute.Opcode != 0)
+                events.Append(" opcode=\"").Append(GetOpcodeName(eventAttribute.Opcode, eventName)).Append("\"");
+            if (eventAttribute.Task != 0)
+                events.Append(" task=\"").Append(GetTaskName(eventAttribute.Task, eventName)).Append("\"");
+#if FEATURE_MANAGED_ETW_CHANNELS
+            if (eventAttribute.Channel != 0)
+            {
+                events.Append(" channel=\"").Append(GetChannelName(eventAttribute.Channel, eventName, eventAttribute.Message)).Append("\"");
+            }
+#endif
+        }
+
+        public void AddEventParameter(Type type, string name)
+        {
+            if (numParams == 0)
+                templates.Append("  <template tid=\"").Append(eventName).Append("Args\">").AppendLine();
+            if (type == typeof(byte[]))
+            {
+                // mark this index as "extraneous" (it has no parallel in the managed signature)
+                // we use these values in TranslateToManifestConvention()
+                if (byteArrArgIndices == null)
+                    byteArrArgIndices = new List<int>(4);
+                byteArrArgIndices.Add(numParams);
+
+                // add an extra field to the template representing the length of the binary blob
+                numParams++;
+                templates.Append("   <data name=\"").Append(name).Append("Size\" inType=\"win:UInt32\"/>").AppendLine();
+            }
+            numParams++;
+            templates.Append("   <data name=\"").Append(name).Append("\" inType=\"").Append(GetTypeName(type)).Append("\"");
+            // TODO: for 'byte*' types it assumes the user provided length is named using the same naming convention
+            //       as for 'byte[]' args (blob_arg_name + "Size")
+            if ((type.IsArray || type.IsPointer) && type.GetElementType() == typeof(byte))
+            {
+                // add "length" attribute to the "blob" field in the template (referencing the field added above)
+                templates.Append(" length=\"").Append(name).Append("Size\"");
+            }
+            // ETW does not support 64-bit value maps, so we don't specify these as ETW maps
+            if (type.IsEnum() && Enum.GetUnderlyingType(type) != typeof(UInt64) && Enum.GetUnderlyingType(type) != typeof(Int64))
+            {
+                templates.Append(" map=\"").Append(type.Name).Append("\"");
+                if (mapsTab == null)
+                    mapsTab = new Dictionary<string, Type>();
+                if (!mapsTab.ContainsKey(type.Name))
+                    mapsTab.Add(type.Name, type);        // Remember that we need to dump the type enumeration  
+            }
+
+            templates.Append("/>").AppendLine();
+        }
+        public void EndEvent()
+        {
+            if (numParams > 0)
+            {
+                templates.Append("  </template>").AppendLine();
+                events.Append(" template=\"").Append(eventName).Append("Args\"");
+            }
+            events.Append("/>").AppendLine();
+
+            if (byteArrArgIndices != null)
+                perEventByteArrayArgIndices[eventName] = byteArrArgIndices;
+
+            // at this point we have all the information we need to translate the C# Message
+            // to the manifest string we'll put in the stringTab
+            string msg;
+            if (stringTab.TryGetValue("event_" + eventName, out msg))
+            {
+                msg = TranslateToManifestConvention(msg, eventName);
+                stringTab["event_" + eventName] = msg;
+            }
+
+            eventName = null;
+            numParams = 0;
+            byteArrArgIndices = null;
+        }
+
+#if FEATURE_MANAGED_ETW_CHANNELS
+        // Channel keywords are generated one per channel to allow channel based filtering in event viewer. These keywords are autogenerated
+        // by mc.exe for compiling a manifest and are based on the order of the channels (fields) in the Channels inner class (when advanced
+        // channel support is enabled), or based on the order the predefined channels appear in the EventAttribute properties (for simple 
+        // support). The manifest generated *MUST* have the channels specified in the same order (that's how our computed keywords are mapped
+        // to channels by the OS infrastructure).
+        // If channelKeyworkds is present, and has keywords bits in the ValidPredefinedChannelKeywords then it is 
+        // assumed that that the keyword for that channel should be that bit.   
+        // otherwise we allocate a channel bit for the channel.  
+        // explicit channel bits are only used by WCF to mimic an existing manifest, 
+        // so we don't dont do error checking.  
+        public ulong GetChannelKeyword(EventChannel channel, ulong channelKeyword = 0)
+        {
+            // strip off any non-channel keywords, since we are only interested in channels here.  
+            channelKeyword &= ValidPredefinedChannelKeywords;
+            if (channelTab == null)
+            {
+                channelTab = new Dictionary<int, ChannelInfo>(4);
+            }
+
+            if (channelTab.Count == MaxCountChannels)
+                ManifestError(Resources.GetResourceString("EventSource_MaxChannelExceeded"));
+
+            ChannelInfo info;
+            if (!channelTab.TryGetValue((int)channel, out info))
+            {
+                // If we were not given an explicit channel, allocate one.  
+                if (channelKeyword != 0)
+                {
+                    channelKeyword = nextChannelKeywordBit;
+                    nextChannelKeywordBit >>= 1;
+                }
+            }
+            else
+            {
+                channelKeyword = info.Keywords;
+            }
+
+            return channelKeyword;
+        }
+#endif
+
+        public byte[] CreateManifest()
+        {
+            string str = CreateManifestString();
+            return Encoding.UTF8.GetBytes(str);
+        }
+
+        public IList<string> Errors { get { return errors; } }
+
+        /// <summary>
+        /// When validating an event source it adds the error to the error collection.
+        /// When not validating it throws an exception if runtimeCritical is "true".
+        /// Otherwise the error is ignored.
+        /// </summary>
+        /// <param name="msg"></param>
+        /// <param name="runtimeCritical"></param>
+        public void ManifestError(string msg, bool runtimeCritical = false)
+        {
+            if ((flags & EventManifestOptions.Strict) != 0)
+                errors.Add(msg);
+            else if (runtimeCritical)
+                throw new ArgumentException(msg);
+        }
+
+        private string CreateManifestString()
+        {
+
+#if FEATURE_MANAGED_ETW_CHANNELS
+            // Write out the channels
+            if (channelTab != null)
+            {
+                sb.Append(" <channels>").AppendLine();
+                var sortedChannels = new List<KeyValuePair<int, ChannelInfo>>();
+                foreach (KeyValuePair<int, ChannelInfo> p in channelTab) { sortedChannels.Add(p); }
+                sortedChannels.Sort((p1, p2) => -Comparer<ulong>.Default.Compare(p1.Value.Keywords, p2.Value.Keywords));
+                foreach (var kvpair in sortedChannels)
+                {
+                    int channel = kvpair.Key;
+                    ChannelInfo channelInfo = kvpair.Value;
+
+                    string channelType = null;
+                    string elementName = "channel";
+                    bool enabled = false;
+                    string fullName = null;
+#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
+                    string isolation = null;
+                    string access = null;
+#endif
+                    if (channelInfo.Attribs != null)
+                    {
+                        var attribs = channelInfo.Attribs;
+                        if (Enum.IsDefined(typeof(EventChannelType), attribs.EventChannelType))
+                            channelType = attribs.EventChannelType.ToString();
+                        enabled = attribs.Enabled;
+#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
+                        if (attribs.ImportChannel != null)
+                        {
+                            fullName = attribs.ImportChannel;
+                            elementName = "importChannel";
+                        }
+                        if (Enum.IsDefined(typeof(EventChannelIsolation), attribs.Isolation))
+                            isolation = attribs.Isolation.ToString();
+                        access = attribs.Access;
+#endif
+                    }
+                    if (fullName == null)
+                        fullName = providerName + "/" + channelInfo.Name;
+
+                    sb.Append("  <").Append(elementName);
+                    sb.Append(" chid=\"").Append(channelInfo.Name).Append("\"");
+                    sb.Append(" name=\"").Append(fullName).Append("\"");
+                    if (elementName == "channel")   // not applicable to importChannels.
+                    {
+                        WriteMessageAttrib(sb, "channel", channelInfo.Name, null);
+                        sb.Append(" value=\"").Append(channel).Append("\"");
+                        if (channelType != null)
+                            sb.Append(" type=\"").Append(channelType).Append("\"");
+                        sb.Append(" enabled=\"").Append(enabled.ToString().ToLower()).Append("\"");
+#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
+                        if (access != null)
+                            sb.Append(" access=\"").Append(access).Append("\"");
+                        if (isolation != null)
+                            sb.Append(" isolation=\"").Append(isolation).Append("\"");
+#endif
+                    }
+                    sb.Append("/>").AppendLine();
+                }
+                sb.Append(" </channels>").AppendLine();
+            }
+#endif
+
+            // Write out the tasks
+            if (taskTab != null)
+            {
+
+                sb.Append(" <tasks>").AppendLine();
+                var sortedTasks = new List<int>(taskTab.Keys);
+                sortedTasks.Sort();
+                foreach (int task in sortedTasks)
+                {
+                    sb.Append("  <task");
+                    WriteNameAndMessageAttribs(sb, "task", taskTab[task]);
+                    sb.Append(" value=\"").Append(task).Append("\"/>").AppendLine();
+                }
+                sb.Append(" </tasks>").AppendLine();
+            }
+
+            // Write out the maps
+            if (mapsTab != null)
+            {
+                sb.Append(" <maps>").AppendLine();
+                foreach (Type enumType in mapsTab.Values)
+                {
+                    bool isbitmap = EventSource.GetCustomAttributeHelper(enumType, typeof(FlagsAttribute), flags) != null;
+                    string mapKind = isbitmap ? "bitMap" : "valueMap";
+                    sb.Append("  <").Append(mapKind).Append(" name=\"").Append(enumType.Name).Append("\">").AppendLine();
+
+                    // write out each enum value 
+                    FieldInfo[] staticFields = enumType.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static);
+                    foreach (FieldInfo staticField in staticFields)
+                    {
+                        object constantValObj = staticField.GetRawConstantValue();
+                        if (constantValObj != null)
+                        {
+                            long hexValue;
+                            if (constantValObj is int)
+                                hexValue = ((int)constantValObj);
+                            else if (constantValObj is long)
+                                hexValue = ((long)constantValObj);
+                            else
+                                continue;
+
+                            // ETW requires all bitmap values to be powers of 2.  Skip the ones that are not. 
+                            // TODO: Warn people about the dropping of values. 
+                            if (isbitmap && ((hexValue & (hexValue - 1)) != 0 || hexValue == 0))
+                                continue;
+
+                            sb.Append("   <map value=\"0x").Append(hexValue.ToString("x", CultureInfo.InvariantCulture)).Append("\"");
+                            WriteMessageAttrib(sb, "map", enumType.Name + "." + staticField.Name, staticField.Name);
+                            sb.Append("/>").AppendLine();
+                        }
+                    }
+                    sb.Append("  </").Append(mapKind).Append(">").AppendLine();
+                }
+                sb.Append(" </maps>").AppendLine();
+            }
+
+            // Write out the opcodes
+            sb.Append(" <opcodes>").AppendLine();
+            var sortedOpcodes = new List<int>(opcodeTab.Keys);
+            sortedOpcodes.Sort();
+            foreach (int opcode in sortedOpcodes)
+            {
+                sb.Append("  <opcode");
+                WriteNameAndMessageAttribs(sb, "opcode", opcodeTab[opcode]);
+                sb.Append(" value=\"").Append(opcode).Append("\"/>").AppendLine();
+            }
+            sb.Append(" </opcodes>").AppendLine();
+
+            // Write out the keywords
+            if (keywordTab != null)
+            {
+                sb.Append(" <keywords>").AppendLine();
+                var sortedKeywords = new List<ulong>(keywordTab.Keys);
+                sortedKeywords.Sort();
+                foreach (ulong keyword in sortedKeywords)
+                {
+                    sb.Append("  <keyword");
+                    WriteNameAndMessageAttribs(sb, "keyword", keywordTab[keyword]);
+                    sb.Append(" mask=\"0x").Append(keyword.ToString("x", CultureInfo.InvariantCulture)).Append("\"/>").AppendLine();
+                }
+                sb.Append(" </keywords>").AppendLine();
+            }
+
+            sb.Append(" <events>").AppendLine();
+            sb.Append(events);
+            sb.Append(" </events>").AppendLine();
+
+            sb.Append(" <templates>").AppendLine();
+            if (templates.Length > 0)
+            {
+                sb.Append(templates);
+            }
+            else
+            {
+                // Work around a cornercase ETW issue where a manifest with no templates causes 
+                // ETW events to not get sent to their associated channel.
+                sb.Append("    <template tid=\"_empty\"></template>").AppendLine();
+            }
+            sb.Append(" </templates>").AppendLine();
+
+            sb.Append("</provider>").AppendLine();
+            sb.Append("</events>").AppendLine();
+            sb.Append("</instrumentation>").AppendLine();
+
+            // Output the localization information.  
+            sb.Append("<localization>").AppendLine();
+
+            List<CultureInfo> cultures = null;
+            if (resources != null && (flags & EventManifestOptions.AllCultures) != 0)
+            {
+                cultures = GetSupportedCultures(resources);
+            }
+            else
+            {
+                cultures = new List<CultureInfo>();
+                cultures.Add(CultureInfo.CurrentUICulture);
+            }
+#if ES_BUILD_STANDALONE || ES_BUILD_PN
+            var sortedStrings = new List<string>(stringTab.Keys);
+            sortedStrings.Sort();
+#else
+            // DD 947936
+            var sortedStrings = new string[stringTab.Keys.Count];
+            stringTab.Keys.CopyTo(sortedStrings, 0);
+            // Avoid using public Array.Sort as that attempts to access BinaryCompatibility. Unfortunately FrameworkEventSource gets called 
+            // 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.
+            ArraySortHelper<string>.IntrospectiveSort(sortedStrings, 0, sortedStrings.Length, string.Compare);
+#endif
+            foreach (var ci in cultures)
+            {
+                sb.Append(" <resources culture=\"").Append(ci.Name).Append("\">").AppendLine();
+                sb.Append("  <stringTable>").AppendLine();
+
+                foreach (var stringKey in sortedStrings)
+                {
+                    string val = GetLocalizedMessage(stringKey, ci, etwFormat: true);
+                    sb.Append("   <string id=\"").Append(stringKey).Append("\" value=\"").Append(val).Append("\"/>").AppendLine();
+                }
+                sb.Append("  </stringTable>").AppendLine();
+                sb.Append(" </resources>").AppendLine();
+            }
+            sb.Append("</localization>").AppendLine();
+            sb.AppendLine("</instrumentationManifest>");
+            return sb.ToString();
+        }
+
+        #region private
+        private void WriteNameAndMessageAttribs(StringBuilder stringBuilder, string elementName, string name)
+        {
+            stringBuilder.Append(" name=\"").Append(name).Append("\"");
+            WriteMessageAttrib(sb, elementName, name, name);
+        }
+        private void WriteMessageAttrib(StringBuilder stringBuilder, string elementName, string name, string value)
+        {
+            string key = elementName + "_" + name;
+            // See if the user wants things localized.  
+            if (resources != null)
+            {
+                // resource fallback: strings in the neutral culture will take precedence over inline strings
+                string localizedString = resources.GetString(key, CultureInfo.InvariantCulture);
+                if (localizedString != null)
+                    value = localizedString;
+            }
+            if (value == null)
+                return;
+
+            stringBuilder.Append(" message=\"$(string.").Append(key).Append(")\"");
+            string prevValue;
+            if (stringTab.TryGetValue(key, out prevValue) && !prevValue.Equals(value))
+            {
+                ManifestError(Resources.GetResourceString("EventSource_DuplicateStringKey", key), true);
+                return;
+            }
+
+            stringTab[key] = value;
+        }
+        internal string GetLocalizedMessage(string key, CultureInfo ci, bool etwFormat)
+        {
+            string value = null;
+            if (resources != null)
+            {
+                string localizedString = resources.GetString(key, ci);
+                if (localizedString != null)
+                {
+                    value = localizedString;
+                    if (etwFormat && key.StartsWith("event_", StringComparison.Ordinal))
+                    {
+                        var evtName = key.Substring("event_".Length);
+                        value = TranslateToManifestConvention(value, evtName);
+                    }
+                }
+            }
+            if (etwFormat && value == null)
+                stringTab.TryGetValue(key, out value);
+
+            return value;
+        }
+
+        /// <summary>
+        /// There's no API to enumerate all languages an assembly is localized into, so instead
+        /// we enumerate through all the "known" cultures and attempt to load a corresponding satellite 
+        /// assembly
+        /// </summary>
+        /// <param name="resources"></param>
+        /// <returns></returns>
+        private static List<CultureInfo> GetSupportedCultures(ResourceManager resources)
+        {
+            var cultures = new List<CultureInfo>();
+
+            if (!cultures.Contains(CultureInfo.CurrentUICulture))
+                cultures.Insert(0, CultureInfo.CurrentUICulture);
+            return cultures;
+        }
+
+        private static string GetLevelName(EventLevel level)
+        {
+            return (((int)level >= 16) ? "" : "win:") + level.ToString();
+        }
+
+#if FEATURE_MANAGED_ETW_CHANNELS
+        private string GetChannelName(EventChannel channel, string eventName, string eventMessage)
+        {
+            ChannelInfo info = null;
+            if (channelTab == null || !channelTab.TryGetValue((int)channel, out info))
+            {
+                if (channel < EventChannel.Admin) // || channel > EventChannel.Debug)
+                    ManifestError(Resources.GetResourceString("EventSource_UndefinedChannel", channel, eventName));
+
+                // allow channels to be auto-defined.  The well known ones get their well known names, and the
+                // rest get names Channel<N>.  This allows users to modify the Manifest if they want more advanced features. 
+                if (channelTab == null)
+                    channelTab = new Dictionary<int, ChannelInfo>(4);
+
+                string channelName = channel.ToString();        // For well know channels this is a nice name, otherwise a number 
+                if (EventChannel.Debug < channel)
+                    channelName = "Channel" + channelName;      // Add a 'Channel' prefix for numbers.  
+
+                AddChannel(channelName, (int)channel, GetDefaultChannelAttribute(channel));
+                if (!channelTab.TryGetValue((int)channel, out info))
+                    ManifestError(Resources.GetResourceString("EventSource_UndefinedChannel", channel, eventName));
+            }
+            // events that specify admin channels *must* have non-null "Message" attributes
+            if (resources != null && eventMessage == null)
+                eventMessage = resources.GetString("event_" + eventName, CultureInfo.InvariantCulture);
+            if (info.Attribs.EventChannelType == EventChannelType.Admin && eventMessage == null)
+                ManifestError(Resources.GetResourceString("EventSource_EventWithAdminChannelMustHaveMessage", eventName, info.Name));
+            return info.Name;
+        }
+#endif
+        private string GetTaskName(EventTask task, string eventName)
+        {
+            if (task == EventTask.None)
+                return "";
+
+            string ret;
+            if (taskTab == null)
+                taskTab = new Dictionary<int, string>();
+            if (!taskTab.TryGetValue((int)task, out ret))
+                ret = taskTab[(int)task] = eventName;
+            return ret;
+        }
+
+        private string GetOpcodeName(EventOpcode opcode, string eventName)
+        {
+            switch (opcode)
+            {
+                case EventOpcode.Info:
+                    return "win:Info";
+                case EventOpcode.Start:
+                    return "win:Start";
+                case EventOpcode.Stop:
+                    return "win:Stop";
+                case EventOpcode.DataCollectionStart:
+                    return "win:DC_Start";
+                case EventOpcode.DataCollectionStop:
+                    return "win:DC_Stop";
+                case EventOpcode.Extension:
+                    return "win:Extension";
+                case EventOpcode.Reply:
+                    return "win:Reply";
+                case EventOpcode.Resume:
+                    return "win:Resume";
+                case EventOpcode.Suspend:
+                    return "win:Suspend";
+                case EventOpcode.Send:
+                    return "win:Send";
+                case EventOpcode.Receive:
+                    return "win:Receive";
+            }
+
+            string ret;
+            if (opcodeTab == null || !opcodeTab.TryGetValue((int)opcode, out ret))
+            {
+                ManifestError(Resources.GetResourceString("EventSource_UndefinedOpcode", opcode, eventName), true);
+                ret = null;
+            }
+            return ret;
+        }
+
+        private string GetKeywords(ulong keywords, string eventName)
+        {
+#if FEATURE_MANAGED_ETW_CHANNELS
+            // ignore keywords associate with channels
+            // See ValidPredefinedChannelKeywords def for more. 
+            keywords &= ~ValidPredefinedChannelKeywords;
+#endif
+
+            string ret = "";
+            for (ulong bit = 1; bit != 0; bit <<= 1)
+            {
+                if ((keywords & bit) != 0)
+                {
+                    string keyword = null;
+                    if ((keywordTab == null || !keywordTab.TryGetValue(bit, out keyword)) &&
+                        (bit >= (ulong)0x1000000000000))
+                    {
+                        // do not report Windows reserved keywords in the manifest (this allows the code
+                        // to be resilient to potential renaming of these keywords)
+                        keyword = string.Empty;
+                    }
+                    if (keyword == null)
+                    {
+                        ManifestError(Resources.GetResourceString("EventSource_UndefinedKeyword", "0x" + bit.ToString("x", CultureInfo.CurrentCulture), eventName), true);
+                        keyword = string.Empty;
+                    }
+                    if (ret.Length != 0 && keyword.Length != 0)
+                        ret = ret + " ";
+                    ret = ret + keyword;
+                }
+            }
+            return ret;
+        }
+
+        private string GetTypeName(Type type)
+        {
+            if (type.IsEnum())
+            {
+                FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
+                var typeName = GetTypeName(fields[0].FieldType);
+                return typeName.Replace("win:Int", "win:UInt"); // ETW requires enums to be unsigned.  
+            }
+
+            return GetTypeNameHelper(type);
+        }
+
+        private static void UpdateStringBuilder(ref StringBuilder stringBuilder, string eventMessage, int startIndex, int count)
+        {
+            if (stringBuilder == null)
+                stringBuilder = new StringBuilder();
+            stringBuilder.Append(eventMessage, startIndex, count);
+        }
+
+        private static readonly string[] s_escapes = { "&amp;", "&lt;", "&gt;", "&apos;", "&quot;", "%r", "%n", "%t" };
+        // Manifest messages use %N conventions for their message substitutions.   Translate from
+        // .NET conventions.   We can't use RegEx for this (we are in mscorlib), so we do it 'by hand' 
+        private string TranslateToManifestConvention(string eventMessage, string evtName)
+        {
+            StringBuilder stringBuilder = null;        // We lazily create this 
+            int writtenSoFar = 0;
+            int chIdx = -1;
+            for (int i = 0; ;)
+            {
+                if (i >= eventMessage.Length)
+                {
+                    if (stringBuilder == null)
+                        return eventMessage;
+                    UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar);
+                    return stringBuilder.ToString();
+                }
+
+                if (eventMessage[i] == '%')
+                {
+                    // handle format message escaping character '%' by escaping it
+                    UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar);
+                    stringBuilder.Append("%%");
+                    i++;
+                    writtenSoFar = i;
+                }
+                else if (i < eventMessage.Length - 1 &&
+                    (eventMessage[i] == '{' && eventMessage[i + 1] == '{' || eventMessage[i] == '}' && eventMessage[i + 1] == '}'))
+                {
+                    // handle C# escaped '{" and '}'
+                    UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar);
+                    stringBuilder.Append(eventMessage[i]);
+                    i++; i++;
+                    writtenSoFar = i;
+                }
+                else if (eventMessage[i] == '{')
+                {
+                    int leftBracket = i;
+                    i++;
+                    int argNum = 0;
+                    while (i < eventMessage.Length && Char.IsDigit(eventMessage[i]))
+                    {
+                        argNum = argNum * 10 + eventMessage[i] - '0';
+                        i++;
+                    }
+                    if (i < eventMessage.Length && eventMessage[i] == '}')
+                    {
+                        i++;
+                        UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, leftBracket - writtenSoFar);
+                        int manIndex = TranslateIndexToManifestConvention(argNum, evtName);
+                        stringBuilder.Append('%').Append(manIndex);
+                        // An '!' after the insert specifier {n} will be interpreted as a literal.
+                        // We'll escape it so that mc.exe does not attempt to consider it the 
+                        // beginning of a format string.
+                        if (i < eventMessage.Length && eventMessage[i] == '!')
+                        {
+                            i++;
+                            stringBuilder.Append("%!");
+                        }
+                        writtenSoFar = i;
+                    }
+                    else
+                    {
+                        ManifestError(Resources.GetResourceString("EventSource_UnsupportedMessageProperty", evtName, eventMessage));
+                    }
+                }
+                else if ((chIdx = "&<>'\"\r\n\t".IndexOf(eventMessage[i])) >= 0)
+                {
+                    UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar);
+                    i++;
+                    stringBuilder.Append(s_escapes[chIdx]);
+                    writtenSoFar = i;
+                }
+                else
+                    i++;
+            }
+        }
+
+        private int TranslateIndexToManifestConvention(int idx, string evtName)
+        {
+            List<int> byteArrArgIndices;
+            if (perEventByteArrayArgIndices.TryGetValue(evtName, out byteArrArgIndices))
+            {
+                foreach (var byArrIdx in byteArrArgIndices)
+                {
+                    if (idx >= byArrIdx)
+                        ++idx;
+                    else
+                        break;
+                }
+            }
+            return idx + 1;
+        }
+
+#if FEATURE_MANAGED_ETW_CHANNELS
+        class ChannelInfo
+        {
+            public string Name;
+            public ulong Keywords;
+            public EventChannelAttribute Attribs;
+        }
+#endif
+
+        Dictionary<int, string> opcodeTab;
+        Dictionary<int, string> taskTab;
+#if FEATURE_MANAGED_ETW_CHANNELS
+        Dictionary<int, ChannelInfo> channelTab;
+#endif
+        Dictionary<ulong, string> keywordTab;
+        Dictionary<string, Type> mapsTab;
+
+        Dictionary<string, string> stringTab;       // Maps unlocalized strings to localized ones  
+
+#if FEATURE_MANAGED_ETW_CHANNELS
+        // WCF used EventSource to mimic a existing ETW manifest.   To support this
+        // in just their case, we allowed them to specify the keywords associated 
+        // with their channels explicitly.   ValidPredefinedChannelKeywords is 
+        // this set of channel keywords that we allow to be explicitly set.  You
+        // can ignore these bits otherwise.  
+        internal const ulong ValidPredefinedChannelKeywords = 0xF000000000000000;
+        ulong nextChannelKeywordBit = 0x8000000000000000;   // available Keyword bit to be used for next channel definition, grows down
+        const int MaxCountChannels = 8; // a manifest can defined at most 8 ETW channels
+#endif
+
+        StringBuilder sb;               // Holds the provider information. 
+        StringBuilder events;           // Holds the events. 
+        StringBuilder templates;
+
+#if FEATURE_MANAGED_ETW_CHANNELS
+        string providerName;
+#endif
+        ResourceManager resources;      // Look up localized strings here.  
+        EventManifestOptions flags;
+        IList<string> errors;           // list of currently encountered errors
+        Dictionary<string, List<int>> perEventByteArrayArgIndices;  // "event_name" -> List_of_Indices_of_Byte[]_Arg
+
+        // State we track between StartEvent and EndEvent.  
+        string eventName;               // Name of the event currently being processed. 
+        int numParams;                  // keeps track of the number of args the event has. 
+        List<int> byteArrArgIndices;    // keeps track of the index of each byte[] argument
+        #endregion
+    }
+
+    /// <summary>
+    /// Used to send the m_rawManifest into the event dispatcher as a series of events.  
+    /// </summary>
+    internal struct ManifestEnvelope
+    {
+        public const int MaxChunkSize = 0xFF00;
+        public enum ManifestFormats : byte
+        {
+            SimpleXmlFormat = 1,          // simply dump the XML manifest as UTF8
+        }
+
+#if FEATURE_MANAGED_ETW
+        public ManifestFormats Format;
+        public byte MajorVersion;
+        public byte MinorVersion;
+        public byte Magic;
+        public ushort TotalChunks;
+        public ushort ChunkNumber;
+#endif
+    };
+
+    #endregion
+}
+
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventSourceException.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventSourceException.cs
new file mode 100644 (file)
index 0000000..89d3ee5
--- /dev/null
@@ -0,0 +1,53 @@
+// 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.Serialization;
+
+#if ES_BUILD_STANDALONE
+using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
+#endif
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// Exception that is thrown when an error occurs during EventSource operation.
+    /// </summary>
+#if (!ES_BUILD_PCL && !ES_BUILD_PN)
+    [Serializable]
+#endif
+    public class EventSourceException : Exception
+    {
+        /// <summary>
+        /// Initializes a new instance of the EventSourceException class.
+        /// </summary>
+        public EventSourceException() :
+            base(Resources.GetResourceString("EventSource_ListenerWriteFailure")) { }
+
+        /// <summary>
+        /// Initializes a new instance of the EventSourceException class with a specified error message.
+        /// </summary>
+        public EventSourceException(string message) : base(message) { }
+
+        /// <summary>
+        /// Initializes a new instance of the EventSourceException class with a specified error message 
+        /// and a reference to the inner exception that is the cause of this exception.
+        /// </summary>
+        public EventSourceException(string message, Exception innerException) : base(message, innerException) { }
+
+#if (!ES_BUILD_PCL && !ES_BUILD_PN)
+        /// <summary>
+        /// Initializes a new instance of the EventSourceException class with serialized data.
+        /// </summary>
+        protected EventSourceException(SerializationInfo info, StreamingContext context) : base(info, context) { }
+#endif
+
+        internal EventSourceException(Exception innerException) :
+            base(Resources.GetResourceString("EventSource_ListenerWriteFailure"), innerException) { }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/FrameworkEventSource.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/FrameworkEventSource.cs
new file mode 100644 (file)
index 0000000..80c524b
--- /dev/null
@@ -0,0 +1,662 @@
+// 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.
+
+//
+// ResourcesEtwProvider.cs
+//
+//
+// Managed event source for things that can version with MSCORLIB.  
+//
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Reflection;
+using System.Text;
+using System.Runtime.CompilerServices;
+
+namespace System.Diagnostics.Tracing {
+
+    // To use the framework provider
+    // 
+    //     \\clrmain\tools\Perfmonitor /nokernel /noclr /provider:8E9F5090-2D75-4d03-8A81-E5AFBF85DAF1 start
+    //     Run run your app
+    //     \\clrmain\tools\Perfmonitor stop
+    //     \\clrmain\tools\Perfmonitor print
+    //
+    // This will produce an XML file, where each event is pretty-printed with all its arguments nicely parsed.
+    //
+    [FriendAccessAllowed]
+    [EventSource(Guid = "8E9F5090-2D75-4d03-8A81-E5AFBF85DAF1", Name = "System.Diagnostics.Eventing.FrameworkEventSource")]
+    sealed internal class FrameworkEventSource : EventSource {
+        // Defines the singleton instance for the Resources ETW provider
+        public static readonly FrameworkEventSource Log = new FrameworkEventSource();
+
+        // Keyword definitions.  These represent logical groups of events that can be turned on and off independently
+        // Often each task has a keyword, but where tasks are determined by subsystem, keywords are determined by
+        // usefulness to end users to filter.  Generally users don't mind extra events if they are not high volume
+        // so grouping low volume events together in a single keywords is OK (users can post-filter by task if desired)
+        public static class Keywords {
+            public const EventKeywords Loader     = (EventKeywords)0x0001; // This is bit 0
+            public const EventKeywords ThreadPool = (EventKeywords)0x0002; 
+            public const EventKeywords NetClient  = (EventKeywords)0x0004;
+            //
+            // This is a private event we do not want to expose to customers.  It is to be used for profiling
+            // uses of dynamic type loading by ProjectN applications running on the desktop CLR
+            //
+            public const EventKeywords DynamicTypeUsage = (EventKeywords)0x0008;
+            public const EventKeywords ThreadTransfer   = (EventKeywords)0x0010;
+        }
+
+        /// <summary>ETW tasks that have start/stop events.</summary>
+        [FriendAccessAllowed]
+        public static class Tasks // this name is important for EventSource
+        {
+            /// <summary>Begin / End - GetResponse.</summary>
+            public const EventTask GetResponse      = (EventTask)1;
+            /// <summary>Begin / End - GetRequestStream</summary>
+            public const EventTask GetRequestStream = (EventTask)2;
+            /// <summary>Send / Receive - begin transfer/end transfer</summary>
+            public const EventTask ThreadTransfer = (EventTask)3;
+        }
+
+        [FriendAccessAllowed]
+        public static class Opcodes
+        {
+            public const EventOpcode ReceiveHandled = (EventOpcode)11;
+        }
+
+        // This predicate is used by consumers of this class to deteremine if the class has actually been initialized,
+        // and therefore if the public statics are available for use. This is typically not a problem... if the static
+        // class constructor fails, then attempts to access the statics (or even this property) will result in a 
+        // TypeInitializationException. However, that is not the case while the class loader is actually trying to construct
+        // the TypeInitializationException instance to represent that failure, and some consumers of this class are on
+        // that code path, specifically the resource manager. 
+        public static bool IsInitialized
+        {
+            get
+            {
+                return Log != null;
+            }
+        }
+
+        // The FrameworkEventSource GUID is {8E9F5090-2D75-4d03-8A81-E5AFBF85DAF1}
+        private FrameworkEventSource() : base(new Guid(0x8e9f5090, 0x2d75, 0x4d03, 0x8a, 0x81, 0xe5, 0xaf, 0xbf, 0x85, 0xda, 0xf1), "System.Diagnostics.Eventing.FrameworkEventSource") { }
+
+        // WriteEvent overloads (to avoid the "params" EventSource.WriteEvent
+
+        // optimized for common signatures (used by the ThreadTransferSend/Receive events)
+        [NonEvent]
+#if !CORECLR
+        [System.Security.SecuritySafeCritical]
+#endif // !CORECLR
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        private unsafe void WriteEvent(int eventId, long arg1, int arg2, string arg3, bool arg4)
+        {
+            if (IsEnabled())
+            {
+                if (arg3 == null) arg3 = "";
+                fixed (char* string3Bytes = arg3)
+                {
+                    EventSource.EventData* descrs = stackalloc EventSource.EventData[4];
+                    descrs[0].DataPointer = (IntPtr)(&arg1);
+                    descrs[0].Size = 8;
+                    descrs[1].DataPointer = (IntPtr)(&arg2);
+                    descrs[1].Size = 4;
+                    descrs[2].DataPointer = (IntPtr)string3Bytes;
+                    descrs[2].Size = ((arg3.Length + 1) * 2);
+                    descrs[3].DataPointer = (IntPtr)(&arg4);
+                    descrs[3].Size = 4;
+                    WriteEventCore(eventId, 4, descrs);
+                }
+            }
+        }
+
+        // optimized for common signatures (used by the ThreadTransferSend/Receive events)
+        [NonEvent]
+#if !CORECLR
+        [System.Security.SecuritySafeCritical]
+#endif // !CORECLR
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        private unsafe void WriteEvent(int eventId, long arg1, int arg2, string arg3)
+        {
+            if (IsEnabled())
+            {
+                if (arg3 == null) arg3 = "";
+                fixed (char* string3Bytes = arg3)
+                {
+                    EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
+                    descrs[0].DataPointer = (IntPtr)(&arg1);
+                    descrs[0].Size = 8;
+                    descrs[1].DataPointer = (IntPtr)(&arg2);
+                    descrs[1].Size = 4;
+                    descrs[2].DataPointer = (IntPtr)string3Bytes;
+                    descrs[2].Size = ((arg3.Length + 1) * 2);
+                    WriteEventCore(eventId, 3, descrs);
+                }
+            }
+        }
+
+        // optimized for common signatures (used by the BeginGetResponse/BeginGetRequestStream events)
+        [NonEvent]
+#if !CORECLR
+        [System.Security.SecuritySafeCritical]
+#endif // !CORECLR
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        private unsafe void WriteEvent(int eventId, long arg1, string arg2, bool arg3, bool arg4)
+        {
+            if (IsEnabled())
+            {
+                if (arg2 == null) arg2 = "";
+                fixed (char* string2Bytes = arg2)
+                {
+                    EventSource.EventData* descrs = stackalloc EventSource.EventData[4];
+                    descrs[0].DataPointer = (IntPtr)(&arg1);
+                    descrs[0].Size = 8;
+                    descrs[1].DataPointer = (IntPtr)string2Bytes;
+                    descrs[1].Size = ((arg2.Length + 1) * 2);
+                    descrs[2].DataPointer = (IntPtr)(&arg3);
+                    descrs[2].Size = 4;
+                    descrs[3].DataPointer = (IntPtr)(&arg4);
+                    descrs[3].Size = 4;
+                    WriteEventCore(eventId, 4, descrs);
+                }
+            }
+        }
+
+        // optimized for common signatures (used by the EndGetRequestStream event)
+        [NonEvent]
+#if !CORECLR
+        [System.Security.SecuritySafeCritical]
+#endif // !CORECLR
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        private unsafe void WriteEvent(int eventId, long arg1, bool arg2, bool arg3)
+        {
+            if (IsEnabled())
+            {
+                EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
+                descrs[0].DataPointer = (IntPtr)(&arg1);
+                descrs[0].Size = 8;
+                descrs[1].DataPointer = (IntPtr)(&arg2);
+                descrs[1].Size = 4;
+                descrs[2].DataPointer = (IntPtr)(&arg3);
+                descrs[2].Size = 4;
+                WriteEventCore(eventId, 3, descrs);
+            }
+        }
+
+        // optimized for common signatures (used by the EndGetResponse event)
+        [NonEvent]
+#if !CORECLR
+        [System.Security.SecuritySafeCritical]
+#endif // !CORECLR
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
+        private unsafe void WriteEvent(int eventId, long arg1, bool arg2, bool arg3, int arg4)
+        {
+            if (IsEnabled())
+            {
+                EventSource.EventData* descrs = stackalloc EventSource.EventData[4];
+                descrs[0].DataPointer = (IntPtr)(&arg1);
+                descrs[0].Size = 8;
+                descrs[1].DataPointer = (IntPtr)(&arg2);
+                descrs[1].Size = 4;
+                descrs[2].DataPointer = (IntPtr)(&arg3);
+                descrs[2].Size = 4;
+                descrs[3].DataPointer = (IntPtr)(&arg4);
+                descrs[3].Size = 4;
+                WriteEventCore(eventId, 4, descrs);
+            }
+        }
+
+        // ResourceManager Event Definitions 
+
+        [Event(1, Level = EventLevel.Informational, Keywords = Keywords.Loader)]
+        public void ResourceManagerLookupStarted(String baseName, String mainAssemblyName, String cultureName) {
+            WriteEvent(1, baseName, mainAssemblyName, cultureName);
+        }
+
+        [Event(2, Level = EventLevel.Informational, Keywords = Keywords.Loader)]
+        public void ResourceManagerLookingForResourceSet(String baseName, String mainAssemblyName, String cultureName) {
+            if (IsEnabled())
+                WriteEvent(2, baseName, mainAssemblyName, cultureName);
+        }
+
+        [Event(3, Level = EventLevel.Informational, Keywords = Keywords.Loader)]
+        public void ResourceManagerFoundResourceSetInCache(String baseName, String mainAssemblyName, String cultureName) {
+            if (IsEnabled())
+                WriteEvent(3, baseName, mainAssemblyName, cultureName);
+        }
+
+        // After loading a satellite assembly, we already have the ResourceSet for this culture in
+        // the cache. This can happen if you have an assembly load callback that called into this
+        // instance of the ResourceManager.
+        [Event(4, Level = EventLevel.Warning, Keywords = Keywords.Loader)]
+        public void ResourceManagerFoundResourceSetInCacheUnexpected(String baseName, String mainAssemblyName, String cultureName) {
+            if (IsEnabled())
+                WriteEvent(4, baseName, mainAssemblyName, cultureName);
+        }
+
+        // manifest resource stream lookup succeeded
+        [Event(5, Level = EventLevel.Informational, Keywords = Keywords.Loader)]
+        public void ResourceManagerStreamFound(String baseName, String mainAssemblyName, String cultureName, String loadedAssemblyName, String resourceFileName) {
+            if (IsEnabled())
+                WriteEvent(5, baseName, mainAssemblyName, cultureName, loadedAssemblyName, resourceFileName);
+        }
+
+        // manifest resource stream lookup failed
+        [Event(6, Level = EventLevel.Warning, Keywords = Keywords.Loader)]
+        public void ResourceManagerStreamNotFound(String baseName, String mainAssemblyName, String cultureName, String loadedAssemblyName, String resourceFileName) {
+            if (IsEnabled())
+                WriteEvent(6, baseName, mainAssemblyName, cultureName, loadedAssemblyName, resourceFileName);
+        }
+
+        [Event(7, Level = EventLevel.Informational, Keywords = Keywords.Loader)]
+        public void ResourceManagerGetSatelliteAssemblySucceeded(String baseName, String mainAssemblyName, String cultureName, String assemblyName) {
+            if (IsEnabled())
+                WriteEvent(7, baseName, mainAssemblyName, cultureName, assemblyName);
+        }
+
+        [Event(8, Level = EventLevel.Warning, Keywords = Keywords.Loader)]
+        public void ResourceManagerGetSatelliteAssemblyFailed(String baseName, String mainAssemblyName, String cultureName, String assemblyName) {
+            if (IsEnabled())
+                WriteEvent(8, baseName, mainAssemblyName, cultureName, assemblyName);
+        }
+
+        [Event(9, Level = EventLevel.Informational, Keywords = Keywords.Loader)]
+        public void ResourceManagerCaseInsensitiveResourceStreamLookupSucceeded(String baseName, String mainAssemblyName, String assemblyName, String resourceFileName) {
+            if (IsEnabled())
+                WriteEvent(9, baseName, mainAssemblyName, assemblyName, resourceFileName);
+        }
+
+        [Event(10, Level = EventLevel.Warning, Keywords = Keywords.Loader)]
+        public void ResourceManagerCaseInsensitiveResourceStreamLookupFailed(String baseName, String mainAssemblyName, String assemblyName, String resourceFileName) {
+            if (IsEnabled())
+                WriteEvent(10, baseName, mainAssemblyName, assemblyName, resourceFileName);
+        }
+
+        // Could not access the manifest resource the assembly
+        [Event(11, Level = EventLevel.Error, Keywords = Keywords.Loader)]
+        public void ResourceManagerManifestResourceAccessDenied(String baseName, String mainAssemblyName, String assemblyName, String canonicalName) {
+            if (IsEnabled())
+                WriteEvent(11, baseName, mainAssemblyName, assemblyName, canonicalName);
+        }
+
+        // Neutral resources are sufficient for this culture. Skipping satellites
+        [Event(12, Level = EventLevel.Informational, Keywords = Keywords.Loader)]
+        public void ResourceManagerNeutralResourcesSufficient(String baseName, String mainAssemblyName, String cultureName) {
+            if (IsEnabled())
+                WriteEvent(12, baseName, mainAssemblyName, cultureName);
+        }
+
+        [Event(13, Level = EventLevel.Warning, Keywords = Keywords.Loader)]
+        public void ResourceManagerNeutralResourceAttributeMissing(String mainAssemblyName) {
+            if (IsEnabled())
+                WriteEvent(13, mainAssemblyName);
+        }
+
+        [Event(14, Level = EventLevel.Informational, Keywords = Keywords.Loader)]
+        public void ResourceManagerCreatingResourceSet(String baseName, String mainAssemblyName, String cultureName, String fileName) {
+            if (IsEnabled())
+                WriteEvent(14, baseName, mainAssemblyName, cultureName, fileName);
+        }
+
+        [Event(15, Level = EventLevel.Informational, Keywords = Keywords.Loader)]
+        public void ResourceManagerNotCreatingResourceSet(String baseName, String mainAssemblyName, String cultureName) {
+            if (IsEnabled())
+                WriteEvent(15, baseName, mainAssemblyName, cultureName);
+        }
+
+        [Event(16, Level = EventLevel.Warning, Keywords = Keywords.Loader)]
+        public void ResourceManagerLookupFailed(String baseName, String mainAssemblyName, String cultureName) {
+            if (IsEnabled())
+                WriteEvent(16, baseName, mainAssemblyName, cultureName);
+        }
+
+        [Event(17, Level = EventLevel.Informational, Keywords = Keywords.Loader)]
+        public void ResourceManagerReleasingResources(String baseName, String mainAssemblyName) {
+            if (IsEnabled())
+                WriteEvent(17, baseName, mainAssemblyName);
+        }
+
+        [Event(18, Level = EventLevel.Warning, Keywords = Keywords.Loader)]
+        public void ResourceManagerNeutralResourcesNotFound(String baseName, String mainAssemblyName, String resName) {
+            if (IsEnabled())
+                WriteEvent(18, baseName, mainAssemblyName, resName);
+        }
+
+        [Event(19, Level = EventLevel.Informational, Keywords = Keywords.Loader)]
+        public void ResourceManagerNeutralResourcesFound(String baseName, String mainAssemblyName, String resName) {
+            if (IsEnabled())
+                WriteEvent(19, baseName, mainAssemblyName, resName);
+        }
+
+        [Event(20, Level = EventLevel.Informational, Keywords = Keywords.Loader)]
+        public void ResourceManagerAddingCultureFromConfigFile(String baseName, String mainAssemblyName, String cultureName) {
+            if (IsEnabled())
+                WriteEvent(20, baseName, mainAssemblyName, cultureName);
+        }
+
+        [Event(21, Level = EventLevel.Informational, Keywords = Keywords.Loader)]
+        public void ResourceManagerCultureNotFoundInConfigFile(String baseName, String mainAssemblyName, String cultureName) {
+            if (IsEnabled())
+                WriteEvent(21, baseName, mainAssemblyName, cultureName);
+        }
+
+        [Event(22, Level = EventLevel.Informational, Keywords = Keywords.Loader)]
+        public void ResourceManagerCultureFoundInConfigFile(String baseName, String mainAssemblyName, String cultureName) {
+            if (IsEnabled())
+                WriteEvent(22, baseName, mainAssemblyName, cultureName);
+        }
+
+
+        // ResourceManager Event Wrappers
+
+        [NonEvent]
+        public void ResourceManagerLookupStarted(String baseName, Assembly mainAssembly, String cultureName) {
+            if (IsEnabled())
+                ResourceManagerLookupStarted(baseName, GetName(mainAssembly), cultureName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerLookingForResourceSet(String baseName, Assembly mainAssembly, String cultureName) {
+            if (IsEnabled())
+                ResourceManagerLookingForResourceSet(baseName, GetName(mainAssembly), cultureName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerFoundResourceSetInCache(String baseName, Assembly mainAssembly, String cultureName) {
+            if (IsEnabled())
+                ResourceManagerFoundResourceSetInCache(baseName, GetName(mainAssembly), cultureName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerFoundResourceSetInCacheUnexpected(String baseName, Assembly mainAssembly, String cultureName) {
+            if (IsEnabled())
+                ResourceManagerFoundResourceSetInCacheUnexpected(baseName, GetName(mainAssembly), cultureName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerStreamFound(String baseName, Assembly mainAssembly, String cultureName, Assembly loadedAssembly, String resourceFileName) {
+            if (IsEnabled())
+                ResourceManagerStreamFound(baseName, GetName(mainAssembly), cultureName, GetName(loadedAssembly), resourceFileName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerStreamNotFound(String baseName, Assembly mainAssembly, String cultureName, Assembly loadedAssembly, String resourceFileName) {
+            if (IsEnabled())
+                ResourceManagerStreamNotFound(baseName, GetName(mainAssembly), cultureName, GetName(loadedAssembly), resourceFileName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerGetSatelliteAssemblySucceeded(String baseName, Assembly mainAssembly, String cultureName, String assemblyName) {
+            if (IsEnabled())
+                ResourceManagerGetSatelliteAssemblySucceeded(baseName, GetName(mainAssembly), cultureName, assemblyName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerGetSatelliteAssemblyFailed(String baseName, Assembly mainAssembly, String cultureName, String assemblyName) {
+            if (IsEnabled())
+                ResourceManagerGetSatelliteAssemblyFailed(baseName, GetName(mainAssembly), cultureName, assemblyName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerCaseInsensitiveResourceStreamLookupSucceeded(String baseName, Assembly mainAssembly, String assemblyName, String resourceFileName) {
+            if (IsEnabled())
+                ResourceManagerCaseInsensitiveResourceStreamLookupSucceeded(baseName, GetName(mainAssembly), assemblyName, resourceFileName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerCaseInsensitiveResourceStreamLookupFailed(String baseName, Assembly mainAssembly, String assemblyName, String resourceFileName) {
+            if (IsEnabled())
+                ResourceManagerCaseInsensitiveResourceStreamLookupFailed(baseName, GetName(mainAssembly), assemblyName, resourceFileName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerManifestResourceAccessDenied(String baseName, Assembly mainAssembly, String assemblyName, String canonicalName) {
+            if (IsEnabled())
+                ResourceManagerManifestResourceAccessDenied(baseName, GetName(mainAssembly), assemblyName, canonicalName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerNeutralResourcesSufficient(String baseName, Assembly mainAssembly, String cultureName) {
+            if (IsEnabled()) 
+                ResourceManagerNeutralResourcesSufficient(baseName, GetName(mainAssembly), cultureName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerNeutralResourceAttributeMissing(Assembly mainAssembly) {
+            if (IsEnabled())
+                ResourceManagerNeutralResourceAttributeMissing(GetName(mainAssembly));
+        }
+
+        [NonEvent]
+        public void ResourceManagerCreatingResourceSet(String baseName, Assembly mainAssembly, String cultureName, String fileName) {
+            if (IsEnabled())
+                ResourceManagerCreatingResourceSet(baseName, GetName(mainAssembly), cultureName, fileName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerNotCreatingResourceSet(String baseName, Assembly mainAssembly, String cultureName) {
+            if (IsEnabled())
+                ResourceManagerNotCreatingResourceSet(baseName, GetName(mainAssembly), cultureName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerLookupFailed(String baseName, Assembly mainAssembly, String cultureName) {
+            if (IsEnabled())
+                ResourceManagerLookupFailed(baseName, GetName(mainAssembly), cultureName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerReleasingResources(String baseName, Assembly mainAssembly) {
+            if (IsEnabled())
+                ResourceManagerReleasingResources(baseName, GetName(mainAssembly));
+        }
+
+        [NonEvent]
+        public void ResourceManagerNeutralResourcesNotFound(String baseName, Assembly mainAssembly, String resName) {
+            if (IsEnabled())
+                ResourceManagerNeutralResourcesNotFound(baseName, GetName(mainAssembly), resName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerNeutralResourcesFound(String baseName, Assembly mainAssembly, String resName) {
+            if (IsEnabled())
+                ResourceManagerNeutralResourcesFound(baseName, GetName(mainAssembly), resName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerAddingCultureFromConfigFile(String baseName, Assembly mainAssembly, String cultureName) {
+            if (IsEnabled())
+                ResourceManagerAddingCultureFromConfigFile(baseName, GetName(mainAssembly), cultureName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerCultureNotFoundInConfigFile(String baseName, Assembly mainAssembly, String cultureName) {
+            if (IsEnabled())
+                ResourceManagerCultureNotFoundInConfigFile(baseName, GetName(mainAssembly), cultureName);
+        }
+
+        [NonEvent]
+        public void ResourceManagerCultureFoundInConfigFile(String baseName, Assembly mainAssembly, String cultureName) {
+            if (IsEnabled())
+                ResourceManagerCultureFoundInConfigFile(baseName, GetName(mainAssembly), cultureName);
+        }
+
+        private static string GetName(Assembly assembly) {
+            if (assembly == null)
+                return "<<NULL>>";
+            else
+                return assembly.FullName;
+        }
+
+        [Event(30, Level = EventLevel.Verbose, Keywords = Keywords.ThreadPool|Keywords.ThreadTransfer)]
+        public void ThreadPoolEnqueueWork(long workID) {
+            WriteEvent(30, workID);
+        }
+        [NonEvent]
+#if !CORECLR
+        [System.Security.SecuritySafeCritical]
+#endif // !CORECLR
+        public unsafe void ThreadPoolEnqueueWorkObject(object workID) {
+            // convert the Object Id to a long
+            ThreadPoolEnqueueWork((long) *((void**) JitHelpers.UnsafeCastToStackPointer(ref workID)));
+        }
+
+        [Event(31, Level = EventLevel.Verbose, Keywords = Keywords.ThreadPool|Keywords.ThreadTransfer)]
+        public void ThreadPoolDequeueWork(long workID) {
+            WriteEvent(31, workID);
+        }
+
+        [NonEvent]
+#if !CORECLR
+        [System.Security.SecuritySafeCritical]
+#endif // !CORECLR
+        public unsafe void ThreadPoolDequeueWorkObject(object workID) {
+            // convert the Object Id to a long
+            ThreadPoolDequeueWork((long) *((void**) JitHelpers.UnsafeCastToStackPointer(ref workID)));
+        }
+
+        // In the desktop runtime they don't use Tasks for the point at which the response happens, which means that the
+        // Activity ID created by start using implicit activity IDs does not match.   Thus disable implicit activities (until we fix that)
+        [Event(140, Level = EventLevel.Informational, Keywords = Keywords.NetClient, ActivityOptions=EventActivityOptions.Disable,
+         Task = Tasks.GetResponse, Opcode = EventOpcode.Start, Version = 1)]
+        private void GetResponseStart(long id, string uri, bool success, bool synchronous) {
+            WriteEvent(140, id, uri, success, synchronous);
+        }
+
+        [Event(141, Level = EventLevel.Informational, Keywords = Keywords.NetClient, ActivityOptions=EventActivityOptions.Disable, 
+         Task = Tasks.GetResponse, Opcode = EventOpcode.Stop, Version = 1)]
+        private void GetResponseStop(long id, bool success, bool synchronous, int statusCode) {
+            WriteEvent(141, id, success, synchronous, statusCode);
+        }
+
+        // In the desktop runtime they don't use Tasks for the point at which the response happens, which means that the
+        // Activity ID created by start using implicit activity IDs does not match.   Thus disable implicit activities (until we fix that)
+        [Event(142, Level = EventLevel.Informational, Keywords = Keywords.NetClient, ActivityOptions=EventActivityOptions.Disable,
+         Task = Tasks.GetRequestStream, Opcode = EventOpcode.Start, Version = 1)]
+        private void GetRequestStreamStart(long id, string uri, bool success, bool synchronous) {
+            WriteEvent(142, id, uri, success, synchronous);
+        }
+
+        [Event(143, Level = EventLevel.Informational, Keywords = Keywords.NetClient, ActivityOptions=EventActivityOptions.Disable,
+         Task = Tasks.GetRequestStream, Opcode = EventOpcode.Stop, Version = 1)]
+        private void GetRequestStreamStop(long id, bool success, bool synchronous) {
+            WriteEvent(143, id, success, synchronous);
+        }
+
+        [NonEvent]
+#if !CORECLR
+        [System.Security.SecuritySafeCritical]
+#endif // !CORECLR
+        public unsafe void BeginGetResponse(object id, string uri, bool success, bool synchronous) {
+            if (IsEnabled())
+                GetResponseStart(IdForObject(id), uri, success, synchronous);
+        }
+            
+        [NonEvent]
+#if !CORECLR
+        [System.Security.SecuritySafeCritical]
+#endif // !CORECLR
+        public unsafe void EndGetResponse(object id, bool success, bool synchronous, int statusCode) {
+            if (IsEnabled())
+                GetResponseStop(IdForObject(id), success, synchronous, statusCode);
+        }
+
+        [NonEvent]
+#if !CORECLR
+        [System.Security.SecuritySafeCritical]
+#endif // !CORECLR
+        public unsafe void BeginGetRequestStream(object id, string uri, bool success, bool synchronous) {
+            if (IsEnabled())
+                GetRequestStreamStart(IdForObject(id), uri, success, synchronous);
+        }
+
+        [NonEvent]
+#if !CORECLR
+        [System.Security.SecuritySafeCritical]
+#endif // !CORECLR
+        public unsafe void EndGetRequestStream(object id, bool success, bool synchronous) {
+            if (IsEnabled())
+                GetRequestStreamStop(IdForObject(id), success, synchronous);
+        }
+
+        // id -   represents a correlation ID that allows correlation of two activities, one stamped by 
+        //        ThreadTransferSend, the other by ThreadTransferReceive
+        // kind - identifies the transfer: values below 64 are reserved for the runtime. Currently used values:
+        //        1 - managed Timers ("roaming" ID)
+        //        2 - managed async IO operations (FileStream, PipeStream, a.o.)
+        //        3 - WinRT dispatch operations
+        // info - any additional information user code might consider interesting
+        [Event(150, Level = EventLevel.Informational, Keywords = Keywords.ThreadTransfer, Task = Tasks.ThreadTransfer, Opcode = EventOpcode.Send)]
+        public void ThreadTransferSend(long id, int kind, string info, bool multiDequeues) {
+            if (IsEnabled())
+                WriteEvent(150, id, kind, info, multiDequeues);
+        }
+        // id - is a managed object. it gets translated to the object's address. ETW listeners must
+        //      keep track of GC movements in order to correlate the value passed to XyzSend with the
+        //      (possibly changed) value passed to XyzReceive
+        [NonEvent]
+#if !CORECLR
+        [System.Security.SecuritySafeCritical]
+#endif // !CORECLR
+        public unsafe void ThreadTransferSendObj(object id, int kind, string info, bool multiDequeues) {
+            ThreadTransferSend((long) *((void**) JitHelpers.UnsafeCastToStackPointer(ref id)), kind, info, multiDequeues);
+        }
+
+        // id -   represents a correlation ID that allows correlation of two activities, one stamped by 
+        //        ThreadTransferSend, the other by ThreadTransferReceive
+        // kind - identifies the transfer: values below 64 are reserved for the runtime. Currently used values:
+        //        1 - managed Timers ("roaming" ID)
+        //        2 - managed async IO operations (FileStream, PipeStream, a.o.)
+        //        3 - WinRT dispatch operations
+        // info - any additional information user code might consider interesting
+        [Event(151, Level = EventLevel.Informational, Keywords = Keywords.ThreadTransfer, Task = Tasks.ThreadTransfer, Opcode = EventOpcode.Receive)]
+        public void ThreadTransferReceive(long id, int kind, string info) {
+            if (IsEnabled())
+                WriteEvent(151, id, kind, info);
+        }
+        // id - is a managed object. it gets translated to the object's address. ETW listeners must
+        //      keep track of GC movements in order to correlate the value passed to XyzSend with the
+        //      (possibly changed) value passed to XyzReceive
+        [NonEvent]
+#if !CORECLR
+        [System.Security.SecuritySafeCritical]
+#endif // !CORECLR
+        public unsafe void ThreadTransferReceiveObj(object id, int kind, string info) {
+            ThreadTransferReceive((long) *((void**) JitHelpers.UnsafeCastToStackPointer(ref id)), kind, info);
+        }
+
+        // id -   represents a correlation ID that allows correlation of two activities, one stamped by 
+        //        ThreadTransferSend, the other by ThreadTransferReceive
+        // kind - identifies the transfer: values below 64 are reserved for the runtime. Currently used values:
+        //        1 - managed Timers ("roaming" ID)
+        //        2 - managed async IO operations (FileStream, PipeStream, a.o.)
+        //        3 - WinRT dispatch operations
+        // info - any additional information user code might consider interesting
+        [Event(152, Level = EventLevel.Informational, Keywords = Keywords.ThreadTransfer, Task = Tasks.ThreadTransfer, Opcode = Opcodes.ReceiveHandled)]
+        public void ThreadTransferReceiveHandled(long id, int kind, string info) {
+            if (IsEnabled())
+                WriteEvent(152, id, kind, info);
+        }
+        // id - is a managed object. it gets translated to the object's address. ETW listeners must
+        //      keep track of GC movements in order to correlate the value passed to XyzSend with the
+        //      (possibly changed) value passed to XyzReceive
+        [NonEvent]
+#if !CORECLR
+        [System.Security.SecuritySafeCritical]
+#endif // !CORECLR
+        public unsafe void ThreadTransferReceiveHandledObj(object id, int kind, string info) {
+            ThreadTransferReceive((long) *((void**) JitHelpers.UnsafeCastToStackPointer(ref id)), kind, info);
+        }
+
+        // return a stable ID for a an object.  We use the hash code which is not truely unique but is 
+        // close enough for now at least. we add to it 0x7FFFFFFF00000000 to make it distinguishable
+        // from the style of ID that simply casts the object reference to a long (since old versions of the 
+        // runtime will emit IDs of that form).  
+        private static long IdForObject(object obj) {
+            return obj.GetHashCode() + 0x7FFFFFFF00000000;
+        }
+    }
+}
+
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/StubEnvironment.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/StubEnvironment.cs
new file mode 100644 (file)
index 0000000..add2812
--- /dev/null
@@ -0,0 +1,381 @@
+// 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.Generic;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing.Internal
+#else
+namespace System.Diagnostics.Tracing.Internal
+#endif
+{
+#if ES_BUILD_AGAINST_DOTNET_V35
+    using Microsoft.Internal;
+#endif
+    using Microsoft.Reflection;
+    using System.Reflection;
+
+    internal static class Environment
+    {
+        public static readonly string NewLine = System.Environment.NewLine;
+
+        public static int TickCount
+        { get { return System.Environment.TickCount; } }
+
+        public static string GetResourceString(string key, params object[] args)
+        {
+            string fmt = rm.GetString(key);
+            if (fmt != null)
+                return string.Format(fmt, args);
+
+            string sargs = String.Empty;
+            foreach(var arg in args)
+            {
+                if (sargs != String.Empty)
+                    sargs += ", ";
+                sargs += arg.ToString();
+            }
+
+            return key + " (" + sargs + ")";
+        }
+
+        public static string GetRuntimeResourceString(string key, params object[] args)
+        {
+            return GetResourceString(key, args);
+        }
+
+        private static System.Resources.ResourceManager rm = new System.Resources.ResourceManager("Microsoft.Diagnostics.Tracing.Messages", typeof(Environment).Assembly());
+    }
+}
+
+#if ES_BUILD_AGAINST_DOTNET_V35
+
+namespace Microsoft.Diagnostics.Contracts.Internal
+{
+    internal class Contract
+    {
+        public static void Assert(bool invariant)
+        {
+            Assert(invariant, string.Empty);
+        }
+        public static void Assert(bool invariant, string message)
+        {
+            if (!invariant)
+            {
+                if (System.Diagnostics.Debugger.IsAttached)
+                    System.Diagnostics.Debugger.Break();
+                throw new Exception("Assertion failed: " + message);
+            }
+        }
+        public static void EndContractBlock()
+        { }
+    }
+}
+
+
+namespace Microsoft.Internal
+{
+    using System.Text;
+
+    internal static class Tuple
+    {
+        public static Tuple<T1> Create<T1>(T1 item1)
+        {
+            return new Tuple<T1>(item1);
+        }
+
+        public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2)
+        {
+            return new Tuple<T1, T2>(item1, item2);
+        }
+    }
+
+    [Serializable]
+    internal class Tuple<T1>
+    {
+        private readonly T1 m_Item1;
+
+        public T1 Item1 { get { return m_Item1; } }
+
+        public Tuple(T1 item1)
+        {
+            m_Item1 = item1;
+        }
+
+        public override string ToString()
+        {
+            StringBuilder sb = new StringBuilder();
+            sb.Append("(");
+            sb.Append(m_Item1);
+            sb.Append(")");
+            return sb.ToString();
+        }
+
+        int Size
+        {
+            get
+            {
+                return 1;
+            }
+        }
+    }
+
+    [Serializable]
+    public class Tuple<T1, T2>
+    {
+        private readonly T1 m_Item1;
+        private readonly T2 m_Item2;
+
+        public T1 Item1 { get { return m_Item1; } }
+        public T2 Item2 { get { return m_Item2; } }
+
+        public Tuple(T1 item1, T2 item2)
+        {
+            m_Item1 = item1;
+            m_Item2 = item2;
+        }
+
+        public override string ToString()
+        {
+            StringBuilder sb = new StringBuilder();
+            sb.Append("(");
+            sb.Append(m_Item1);
+            sb.Append(", ");
+            sb.Append(m_Item2);
+            sb.Append(")");
+            return sb.ToString();
+        }
+
+        int Size
+        {
+            get
+            {
+                return 2;
+            }
+        }
+    }
+}
+
+#endif
+
+namespace Microsoft.Reflection
+{
+    using System.Reflection;
+
+#if ES_BUILD_PCL
+    [Flags]
+    public enum BindingFlags
+    {
+        DeclaredOnly = 0x02,        // Only look at the members declared on the Type
+        Instance     = 0x04,        // Include Instance members in search
+        Static       = 0x08,        // Include Static members in search
+        Public       = 0x10,        // Include Public members in search
+        NonPublic    = 0x20,        // Include Non-Public members in search
+    }
+    
+    public enum TypeCode {
+        Empty = 0,                  // Null reference
+        Object = 1,                 // Instance that isn't a value
+        DBNull = 2,                 // Database null value
+        Boolean = 3,                // Boolean
+        Char = 4,                   // Unicode character
+        SByte = 5,                  // Signed 8-bit integer
+        Byte = 6,                   // Unsigned 8-bit integer
+        Int16 = 7,                  // Signed 16-bit integer
+        UInt16 = 8,                 // Unsigned 16-bit integer
+        Int32 = 9,                  // Signed 32-bit integer
+        UInt32 = 10,                // Unsigned 32-bit integer
+        Int64 = 11,                 // Signed 64-bit integer
+        UInt64 = 12,                // Unsigned 64-bit integer
+        Single = 13,                // IEEE 32-bit float
+        Double = 14,                // IEEE 64-bit double
+        Decimal = 15,               // Decimal
+        DateTime = 16,              // DateTime
+        String = 18,                // Unicode character string
+    }
+#endif
+    static class ReflectionExtensions
+    {
+#if (!ES_BUILD_PCL && !ES_BUILD_PN)
+
+        //
+        // Type extension methods
+        //
+        public static bool IsEnum(this Type type) { return type.IsEnum; }
+        public static bool IsAbstract(this Type type) { return type.IsAbstract; }
+        public static bool IsSealed(this Type type) { return type.IsSealed; }
+        public static bool IsValueType(this Type type) { return type.IsValueType; }
+        public static bool IsGenericType(this Type type) { return type.IsGenericType; }
+        public static Type BaseType(this Type type) { return type.BaseType; }
+        public static Assembly Assembly(this Type type) { return type.Assembly; }
+        public static TypeCode GetTypeCode(this Type type) { return Type.GetTypeCode(type); }
+
+        public static bool ReflectionOnly(this Assembly assm) { return assm.ReflectionOnly; }
+
+#else // ES_BUILD_PCL
+
+        //
+        // Type extension methods
+        //
+        public static bool IsEnum(this Type type) { return type.GetTypeInfo().IsEnum; }
+        public static bool IsAbstract(this Type type) { return type.GetTypeInfo().IsAbstract; }
+        public static bool IsSealed(this Type type) { return type.GetTypeInfo().IsSealed; }
+        public static bool IsValueType(this Type type) { return type.GetTypeInfo().IsValueType; }
+        public static bool IsGenericType(this Type type) { return type.IsConstructedGenericType; }
+        public static Type BaseType(this Type type) { return type.GetTypeInfo().BaseType; }
+        public static Assembly Assembly(this Type type) { return type.GetTypeInfo().Assembly; }
+        public static IEnumerable<PropertyInfo> GetProperties(this Type type)
+        {
+#if ES_BUILD_PN
+            return type.GetProperties();
+#else
+            return type.GetRuntimeProperties();
+#endif
+        }
+        public static MethodInfo GetGetMethod(this PropertyInfo propInfo) { return propInfo.GetMethod; }
+        public static Type[] GetGenericArguments(this Type type) { return type.GenericTypeArguments; }
+        
+        public static MethodInfo[] GetMethods(this Type type, BindingFlags flags)
+        {
+            // Minimal implementation to cover only the cases we need
+            System.Diagnostics.Debug.Assert((flags & BindingFlags.DeclaredOnly) != 0);
+            System.Diagnostics.Debug.Assert((flags & ~(BindingFlags.DeclaredOnly|BindingFlags.Instance|BindingFlags.Static|BindingFlags.Public|BindingFlags.NonPublic)) == 0);
+            Func<MethodInfo, bool> visFilter;
+            Func<MethodInfo, bool> instFilter;
+            switch (flags & (BindingFlags.Public | BindingFlags.NonPublic))
+            {
+                case 0: visFilter = mi => false; break;
+                case BindingFlags.Public: visFilter = mi => mi.IsPublic; break;
+                case BindingFlags.NonPublic: visFilter = mi => !mi.IsPublic; break;
+                default: visFilter = mi => true; break;
+            }
+            switch (flags & (BindingFlags.Instance | BindingFlags.Static))
+            {
+                case 0: instFilter = mi => false; break;
+                case BindingFlags.Instance: instFilter = mi => !mi.IsStatic; break;
+                case BindingFlags.Static: instFilter = mi => mi.IsStatic; break;
+                default: instFilter = mi => true; break;
+            }
+            List<MethodInfo> methodInfos = new List<MethodInfo>();
+            foreach (var declaredMethod in type.GetTypeInfo().DeclaredMethods)
+            {
+                if (visFilter(declaredMethod) && instFilter(declaredMethod))
+                    methodInfos.Add(declaredMethod);
+            }
+            return methodInfos.ToArray();
+        }
+        public static FieldInfo[] GetFields(this Type type, BindingFlags flags)
+        {
+            // Minimal implementation to cover only the cases we need
+            System.Diagnostics.Debug.Assert((flags & BindingFlags.DeclaredOnly) != 0);
+            System.Diagnostics.Debug.Assert((flags & ~(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) == 0);
+            Func<FieldInfo, bool> visFilter;
+            Func<FieldInfo, bool> instFilter;
+            switch (flags & (BindingFlags.Public | BindingFlags.NonPublic))
+            {
+                case 0: visFilter = fi => false; break;
+                case BindingFlags.Public: visFilter = fi => fi.IsPublic; break;
+                case BindingFlags.NonPublic: visFilter = fi => !fi.IsPublic; break;
+                default: visFilter = fi => true; break;
+            }
+            switch (flags & (BindingFlags.Instance | BindingFlags.Static))
+            {
+                case 0: instFilter = fi => false; break;
+                case BindingFlags.Instance: instFilter = fi => !fi.IsStatic; break;
+                case BindingFlags.Static: instFilter = fi => fi.IsStatic; break;
+                default: instFilter = fi => true; break;
+            }
+            List<FieldInfo> fieldInfos = new List<FieldInfo>();
+            foreach (var declaredField in type.GetTypeInfo().DeclaredFields)
+            {
+                if (visFilter(declaredField) && instFilter(declaredField))
+                    fieldInfos.Add(declaredField);
+            }
+            return fieldInfos.ToArray();
+        }
+        public static Type GetNestedType(this Type type, string nestedTypeName)
+        {
+            TypeInfo ti = null;
+            foreach(var nt in type.GetTypeInfo().DeclaredNestedTypes)
+            {
+                if (nt.Name == nestedTypeName)
+                {
+                    ti = nt;
+                    break;
+                }
+            }
+            return ti == null ? null : ti.AsType();
+        }
+        public static TypeCode GetTypeCode(this Type type) 
+        {
+            if (type == typeof(bool)) return TypeCode.Boolean;
+            else if (type == typeof(byte)) return TypeCode.Byte;
+            else if (type == typeof(char)) return TypeCode.Char;
+            else if (type == typeof(ushort)) return TypeCode.UInt16;
+            else if (type == typeof(uint)) return TypeCode.UInt32;
+            else if (type == typeof(ulong)) return TypeCode.UInt64;
+            else if (type == typeof(sbyte)) return TypeCode.SByte;
+            else if (type == typeof(short)) return TypeCode.Int16;
+            else if (type == typeof(int)) return TypeCode.Int32;
+            else if (type == typeof(long)) return TypeCode.Int64;
+            else if (type == typeof(string)) return TypeCode.String;
+            else if (type == typeof(float)) return TypeCode.Single;
+            else if (type == typeof(double)) return TypeCode.Double;
+            else if (type == typeof(DateTime)) return TypeCode.DateTime;
+            else if (type == (typeof(Decimal))) return TypeCode.Decimal;
+            else return TypeCode.Object;
+        }
+
+        //
+        // FieldInfo extension methods
+        //
+        public static object GetRawConstantValue(this FieldInfo fi)
+        { return fi.GetValue(null); }
+
+        //
+        // Assembly extension methods
+        //
+        public static bool ReflectionOnly(this Assembly assm)
+        {
+            // In PCL we can't load in reflection-only context
+            return false;
+        }
+
+#endif
+    }
+}
+
+// Defining some no-ops in PCL builds
+#if ES_BUILD_PCL
+namespace System.Security
+{
+    class SuppressUnmanagedCodeSecurityAttribute : Attribute { }
+
+    enum SecurityAction { Demand }
+}
+
+namespace System.Security.Permissions
+{
+    class HostProtectionAttribute : Attribute { public bool MayLeakOnAbort { get; set; } }
+    class PermissionSetAttribute : Attribute
+    { 
+        public PermissionSetAttribute(System.Security.SecurityAction action) { }
+        public bool Unrestricted { get; set; }
+    }
+}
+#endif
+
+#if ES_BUILD_PN
+namespace System
+{
+    public static class AppDomain
+    {
+        public static int GetCurrentThreadId()
+        {
+            return Internal.Runtime.Augments.RuntimeThread.CurrentThread.ManagedThreadId;
+        }
+    }    
+}
+#endif
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/ArrayTypeInfo.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/ArrayTypeInfo.cs
new file mode 100644 (file)
index 0000000..5771354
--- /dev/null
@@ -0,0 +1,63 @@
+// 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.Generic;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    internal sealed class ArrayTypeInfo : TraceLoggingTypeInfo
+    {
+        private readonly TraceLoggingTypeInfo elementInfo;
+
+        public ArrayTypeInfo(Type type, TraceLoggingTypeInfo elementInfo)
+            : base(type)
+        {
+            this.elementInfo = elementInfo;
+        }
+
+        public override void WriteMetadata(
+            TraceLoggingMetadataCollector collector,
+            string name,
+            EventFieldFormat format)
+        {
+            collector.BeginBufferedArray();
+            this.elementInfo.WriteMetadata(collector, name, format);
+            collector.EndBufferedArray();
+        }
+
+        public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
+        {
+            var bookmark = collector.BeginBufferedArray();
+
+            var count = 0;
+            Array array = (Array)value.ReferenceValue;
+            if (array != null)
+            {
+                count = array.Length;
+                for (int i = 0; i < array.Length; i++)
+                {
+                    this.elementInfo.WriteData(collector, elementInfo.PropertyValueFactory(array.GetValue(i)));
+                }
+            }
+
+            collector.EndBufferedArray(bookmark, count);
+        }
+
+        public override object GetData(object value)
+        {
+            var array = (Array)value;
+            var serializedArray = new object[array.Length];
+            for (int i = 0; i < array.Length; i++)
+            {
+                serializedArray[i] = this.elementInfo.GetData(array.GetValue(i));
+            }
+            return serializedArray;
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSet.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSet.cs
new file mode 100644 (file)
index 0000000..76c01c6
--- /dev/null
@@ -0,0 +1,127 @@
+// 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 Interlocked = System.Threading.Interlocked;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: A very simple lock-free add-only dictionary.
+    /// Warning: this is a copy-by-value type. Copying performs a snapshot.
+    /// Accessing a readonly field always makes a copy of the field, so the
+    /// GetOrAdd method will not work as expected if called on a readonly field.
+    /// </summary>
+    /// <typeparam name="KeyType">
+    /// The type of the key, used for TryGet.
+    /// </typeparam>
+    /// <typeparam name="ItemType">
+    /// The type of the item, used for GetOrAdd.
+    /// </typeparam>
+    internal struct ConcurrentSet<KeyType, ItemType>
+        where ItemType : ConcurrentSetItem<KeyType, ItemType>
+    {
+        private ItemType[] items;
+
+        public ItemType TryGet(KeyType key)
+        {
+            ItemType item;
+            var oldItems = this.items;
+
+            if (oldItems != null)
+            {
+                var lo = 0;
+                var hi = oldItems.Length;
+                do
+                {
+                    int i = (lo + hi) / 2;
+                    item = oldItems[i];
+
+                    int cmp = item.Compare(key);
+                    if (cmp == 0)
+                    {
+                        goto Done;
+                    }
+                    else if (cmp < 0)
+                    {
+                        lo = i + 1;
+                    }
+                    else
+                    {
+                        hi = i;
+                    }
+                }
+                while (lo != hi);
+            }
+
+            item = null;
+
+        Done:
+
+            return item;
+        }
+
+        public ItemType GetOrAdd(ItemType newItem)
+        {
+            ItemType item;
+            var oldItems = this.items;
+            ItemType[] newItems;
+
+        Retry:
+
+            if (oldItems == null)
+            {
+                newItems = new ItemType[] { newItem };
+            }
+            else
+            {
+                var lo = 0;
+                var hi = oldItems.Length;
+                do
+                {
+                    int i = (lo + hi) / 2;
+                    item = oldItems[i];
+
+                    int cmp = item.Compare(newItem);
+                    if (cmp == 0)
+                    {
+                        goto Done;
+                    }
+                    else if (cmp < 0)
+                    {
+                        lo = i + 1;
+                    }
+                    else
+                    {
+                        hi = i;
+                    }
+                }
+                while (lo != hi);
+
+                int oldLength = oldItems.Length;
+                newItems = new ItemType[oldLength + 1];
+                Array.Copy(oldItems, 0, newItems, 0, lo);
+                newItems[lo] = newItem;
+                Array.Copy(oldItems, lo, newItems, lo + 1, oldLength - lo);
+            }
+
+            newItems = Interlocked.CompareExchange(ref this.items, newItems, oldItems);
+            if (oldItems != newItems)
+            {
+                oldItems = newItems;
+                goto Retry;
+            }
+
+            item = newItem;
+
+        Done:
+
+            return item;
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSetItem.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSetItem.cs
new file mode 100644 (file)
index 0000000..558dbf6
--- /dev/null
@@ -0,0 +1,25 @@
+// 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;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: Abstract base class that must be inherited by items in a
+    /// ConcurrentSet.
+    /// </summary>
+    /// <typeparam name="KeyType">Type of the set's key.</typeparam>
+    /// <typeparam name="ItemType">Type of the derived class.</typeparam>
+    internal abstract class ConcurrentSetItem<KeyType, ItemType>
+        where ItemType : ConcurrentSetItem<KeyType, ItemType>
+    {
+        public abstract int Compare(ItemType other);
+        public abstract int Compare(KeyType key);
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs
new file mode 100644 (file)
index 0000000..27aae82
--- /dev/null
@@ -0,0 +1,318 @@
+// 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;
+using System.Security;
+
+#if ES_BUILD_STANDALONE
+using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: This is the implementation of the DataCollector
+    /// functionality. To enable safe access to the DataCollector from
+    /// untrusted code, there is one thread-local instance of this structure
+    /// per thread. The instance must be Enabled before any data is written to
+    /// it. The instance must be Finished before the data is passed to
+    /// EventWrite. The instance must be Disabled before the arrays referenced
+    /// by the pointers are freed or unpinned.
+    /// </summary>
+    internal unsafe struct DataCollector
+    {
+        [ThreadStatic]
+        internal static DataCollector ThreadInstance;
+
+        private byte* scratchEnd;
+        private EventSource.EventData* datasEnd;
+        private GCHandle* pinsEnd;
+        private EventSource.EventData* datasStart;
+        private byte* scratch;
+        private EventSource.EventData* datas;
+        private GCHandle* pins;
+        private byte[] buffer;
+        private int bufferPos;
+        private int bufferNesting;          // We may merge many fields int a single blob.   If we are doing this we increment this. 
+        private bool writingScalars;
+
+        internal void Enable(
+            byte* scratch,
+            int scratchSize,
+            EventSource.EventData* datas,
+            int dataCount,
+            GCHandle* pins,
+            int pinCount)
+        {
+            this.datasStart = datas;
+            this.scratchEnd = scratch + scratchSize;
+            this.datasEnd = datas + dataCount;
+            this.pinsEnd = pins + pinCount;
+            this.scratch = scratch;
+            this.datas = datas;
+            this.pins = pins;
+            this.writingScalars = false;
+        }
+
+        internal void Disable()
+        {
+            this = new DataCollector();
+        }
+
+        /// <summary>
+        /// Completes the list of scalars. Finish must be called before the data
+        /// descriptor array is passed to EventWrite.
+        /// </summary>
+        /// <returns>
+        /// A pointer to the next unused data descriptor, or datasEnd if they were
+        /// all used. (Descriptors may be unused if a string or array was null.)
+        /// </returns>
+        internal EventSource.EventData* Finish()
+        {
+            this.ScalarsEnd();
+            return this.datas;
+        }
+
+        internal void AddScalar(void* value, int size)
+        {
+            var pb = (byte*)value;
+            if (this.bufferNesting == 0)
+            {
+                var scratchOld = this.scratch;
+                var scratchNew = scratchOld + size;
+                if (this.scratchEnd < scratchNew)
+                {
+                    throw new IndexOutOfRangeException(Resources.GetResourceString("EventSource_AddScalarOutOfRange"));
+                }
+
+                this.ScalarsBegin();
+                this.scratch = scratchNew;
+
+                for (int i = 0; i != size; i++)
+                {
+                    scratchOld[i] = pb[i];
+                }
+            }
+            else
+            {
+                var oldPos = this.bufferPos;
+                this.bufferPos = checked(this.bufferPos + size);
+                this.EnsureBuffer();
+                for (int i = 0; i != size; i++, oldPos++)
+                {
+                    this.buffer[oldPos] = pb[i];
+                }
+            }
+        }
+
+        internal void AddBinary(string value, int size)
+        {
+            if (size > ushort.MaxValue)
+            {
+                size = ushort.MaxValue - 1;
+            }
+
+            if (this.bufferNesting != 0)
+            {
+                this.EnsureBuffer(size + 2);
+            }
+
+            this.AddScalar(&size, 2);
+
+            if (size != 0)
+            {
+                if (this.bufferNesting == 0)
+                {
+                    this.ScalarsEnd();
+                    this.PinArray(value, size);
+                }
+                else
+                {
+                    var oldPos = this.bufferPos;
+                    this.bufferPos = checked(this.bufferPos + size);
+                    this.EnsureBuffer();
+                    fixed (void* p = value)
+                    {
+                        Marshal.Copy((IntPtr)p, buffer, oldPos, size);
+                    }
+                }
+            }
+        }
+
+        internal void AddBinary(Array value, int size)
+        {
+            this.AddArray(value, size, 1);
+        }
+
+        internal void AddArray(Array value, int length, int itemSize)
+        {
+            if (length > ushort.MaxValue)
+            {
+                length = ushort.MaxValue;
+            }
+
+            var size = length * itemSize;
+            if (this.bufferNesting != 0)
+            {
+                this.EnsureBuffer(size + 2);
+            }
+
+            this.AddScalar(&length, 2);
+
+            if (length != 0)
+            {
+                if (this.bufferNesting == 0)
+                {
+                    this.ScalarsEnd();
+                    this.PinArray(value, size);
+                }
+                else
+                {
+                    var oldPos = this.bufferPos;
+                    this.bufferPos = checked(this.bufferPos + size);
+                    this.EnsureBuffer();
+                    Buffer.BlockCopy(value, 0, this.buffer, oldPos, size);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Marks the start of a non-blittable array or enumerable.
+        /// </summary>
+        /// <returns>Bookmark to be passed to EndBufferedArray.</returns>
+        internal int BeginBufferedArray()
+        {
+            this.BeginBuffered();
+            this.bufferPos += 2; // Reserve space for the array length (filled in by EndEnumerable)
+            return this.bufferPos;
+        }
+
+        /// <summary>
+        /// Marks the end of a non-blittable array or enumerable.
+        /// </summary>
+        /// <param name="bookmark">The value returned by BeginBufferedArray.</param>
+        /// <param name="count">The number of items in the array.</param>
+        internal void EndBufferedArray(int bookmark, int count)
+        {
+            this.EnsureBuffer();
+            this.buffer[bookmark - 2] = unchecked((byte)count);
+            this.buffer[bookmark - 1] = unchecked((byte)(count >> 8));
+            this.EndBuffered();
+        }
+
+        /// <summary>
+        /// Marks the start of dynamically-buffered data.
+        /// </summary>
+        internal void BeginBuffered()
+        {
+            this.ScalarsEnd();
+            this.bufferNesting += 1;
+        }
+
+        /// <summary>
+        /// Marks the end of dynamically-buffered data.
+        /// </summary>
+        internal void EndBuffered()
+        {
+            this.bufferNesting -= 1;
+
+            if (this.bufferNesting == 0)
+            {
+                /*
+                TODO (perf): consider coalescing adjacent buffered regions into a
+                single buffer, similar to what we're already doing for adjacent
+                scalars. In addition, if a type contains a buffered region adjacent
+                to a blittable array, and the blittable array is small, it would be
+                more efficient to buffer the array instead of pinning it.
+                */
+
+                this.EnsureBuffer();
+                this.PinArray(this.buffer, this.bufferPos);
+                this.buffer = null;
+                this.bufferPos = 0;
+            }
+        }
+
+        private void EnsureBuffer()
+        {
+            var required = this.bufferPos;
+            if (this.buffer == null || this.buffer.Length < required)
+            {
+                this.GrowBuffer(required);
+            }
+        }
+
+        private void EnsureBuffer(int additionalSize)
+        {
+            var required = this.bufferPos + additionalSize;
+            if (this.buffer == null || this.buffer.Length < required)
+            {
+                this.GrowBuffer(required);
+            }
+        }
+
+        private void GrowBuffer(int required)
+        {
+            var newSize = this.buffer == null ? 64 : this.buffer.Length;
+
+            do
+            {
+                newSize *= 2;
+            }
+            while (newSize < required);
+
+            Array.Resize(ref this.buffer, newSize);
+        }
+
+        private void PinArray(object value, int size)
+        {
+            var pinsTemp = this.pins;
+            if (this.pinsEnd <= pinsTemp)
+            {
+                throw new IndexOutOfRangeException(Resources.GetResourceString("EventSource_PinArrayOutOfRange"));
+            }
+
+            var datasTemp = this.datas;
+            if (this.datasEnd <= datasTemp)
+            {
+                throw new IndexOutOfRangeException(Resources.GetResourceString("EventSource_DataDescriptorsOutOfRange"));
+            }
+
+            this.pins = pinsTemp + 1;
+            this.datas = datasTemp + 1;
+
+            *pinsTemp = GCHandle.Alloc(value, GCHandleType.Pinned);
+            datasTemp->m_Ptr = (long)(ulong)(UIntPtr)(void*)pinsTemp->AddrOfPinnedObject();
+            datasTemp->m_Size = size;
+        }
+
+        private void ScalarsBegin()
+        {
+            if (!this.writingScalars)
+            {
+                var datasTemp = this.datas;
+                if (this.datasEnd <= datasTemp)
+                {
+                    throw new IndexOutOfRangeException(Resources.GetResourceString("EventSource_DataDescriptorsOutOfRange"));
+                }
+
+                datasTemp->m_Ptr = (long)(ulong)(UIntPtr)this.scratch;
+                this.writingScalars = true;
+            }
+        }
+
+        private void ScalarsEnd()
+        {
+            if (this.writingScalars)
+            {
+                var datasTemp = this.datas;
+                datasTemp->m_Size = checked((int)(this.scratch - (byte*)datasTemp->m_Ptr));
+                this.datas = datasTemp + 1;
+                this.writingScalars = false;
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EmptyStruct.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EmptyStruct.cs
new file mode 100644 (file)
index 0000000..bc7fb8c
--- /dev/null
@@ -0,0 +1,17 @@
+// 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.
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: Empty struct indicating no payload data.
+    /// </summary>
+    internal struct EmptyStruct
+    {
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EnumHelper.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EnumHelper.cs
new file mode 100644 (file)
index 0000000..7a23378
--- /dev/null
@@ -0,0 +1,30 @@
+// 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.
+#if EVENTSOURCE_GENERICS
+?using System;
+using System.Reflection;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// Provides support for casting enums to their underlying type
+    /// from within generic context.
+    /// </summary>
+    /// <typeparam name="UnderlyingType">
+    /// The underlying type of the enum.
+    /// </typeparam>
+    internal static class EnumHelper<UnderlyingType>
+    {
+        public static UnderlyingType Cast<ValueType>(ValueType value)
+        {
+            return (UnderlyingType)(object)value;
+        }
+    }
+
+}
+#endif
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EnumerableTypeInfo.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EnumerableTypeInfo.cs
new file mode 100644 (file)
index 0000000..74a3fa2
--- /dev/null
@@ -0,0 +1,64 @@
+// 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;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    internal sealed class EnumerableTypeInfo : TraceLoggingTypeInfo
+    {
+        private readonly TraceLoggingTypeInfo elementInfo;
+
+        public EnumerableTypeInfo(Type type, TraceLoggingTypeInfo elementInfo)
+            : base(type)
+        {
+            this.elementInfo = elementInfo;
+        }
+
+        public override void WriteMetadata(
+            TraceLoggingMetadataCollector collector,
+            string name,
+            EventFieldFormat format)
+        {
+            collector.BeginBufferedArray();
+            this.elementInfo.WriteMetadata(collector, name, format);
+            collector.EndBufferedArray();
+        }
+
+        public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
+        {
+            var bookmark = collector.BeginBufferedArray();
+
+            var count = 0;
+            IEnumerable enumerable = (IEnumerable)value.ReferenceValue;
+            if (enumerable != null)
+            {
+                foreach (var element in enumerable)
+                {
+                    this.elementInfo.WriteData(collector, elementInfo.PropertyValueFactory(element));
+                    count++;
+                }
+            }
+
+            collector.EndBufferedArray(bookmark, count);
+        }
+
+        public override object GetData(object value)
+        {
+            var iterType = (IEnumerable)value;
+            List<object> serializedEnumerable = new List<object>();
+            foreach (var element in iterType)
+            {
+                serializedEnumerable.Add(elementInfo.GetData(element));
+            }
+            return serializedEnumerable.ToArray();
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventDataAttribute.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventDataAttribute.cs
new file mode 100644 (file)
index 0000000..cdedf13
--- /dev/null
@@ -0,0 +1,146 @@
+// 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;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// Used when authoring types that will be passed to EventSource.Write.
+    /// EventSource.Write&lt;T> only works when T is either an anonymous type
+    /// or a type with an [EventData] attribute. In addition, the properties
+    /// of T must be supported property types. Supported property types include
+    /// simple built-in types (int, string, Guid, DateTime, DateTimeOffset,
+    /// KeyValuePair, etc.), anonymous types that only contain supported types,
+    /// types with an [EventData] attribute, arrays of the above, and IEnumerable
+    /// of the above.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)]
+    public class EventDataAttribute
+        : Attribute
+    {
+        private EventLevel level = (EventLevel)(-1);
+        private EventOpcode opcode = (EventOpcode)(-1);
+
+        /// <summary>
+        /// Gets or sets the name to use if this type is used for an
+        /// implicitly-named event or an implicitly-named property.
+        /// 
+        /// Example 1:
+        /// 
+        ///     EventSource.Write(null, new T()); // implicitly-named event
+        ///     
+        /// The name of the event will be determined as follows:
+        /// 
+        /// if (T has an EventData attribute and attribute.Name != null)
+        ///     eventName = attribute.Name;
+        /// else
+        ///     eventName = typeof(T).Name;
+        ///     
+        /// Example 2:
+        /// 
+        ///     EventSource.Write(name, new { _1 = new T() }); // implicitly-named field
+        ///     
+        /// The name of the field will be determined as follows:
+        /// 
+        /// if (T has an EventData attribute and attribute.Name != null)
+        ///     fieldName = attribute.Name;
+        /// else
+        ///     fieldName = typeof(T).Name;
+        /// </summary>
+        public string Name
+        {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// Gets or sets the level to use for the event.
+        /// Invalid levels (outside the range 0..255) are treated as unset.
+        /// Note that the Level attribute can bubble-up, i.e. if a type contains
+        /// a sub-object (a field or property), and the sub-object's type has a
+        /// TraceLoggingEvent attribute, the Level from the sub-object's attribute
+        /// can affect the event's level.
+        /// 
+        /// Example: for EventSource.Write(name, options, data), the level of the
+        /// event will be determined as follows:
+        /// 
+        /// if (options.Level has been set)
+        ///     eventLevel = options.Level;
+        /// else if (data.GetType() has a TraceLoggingEvent attribute and attribute.Level has been set)
+        ///     eventLevel = attribute.Level;
+        /// else if (a field/property contained in data has a TraceLoggingEvent attribute and attribute.Level has been set)
+        ///     eventLevel = attribute.Level;
+        /// else
+        ///     eventLevel = EventLevel.LogAlways;
+        /// </summary>
+        internal EventLevel Level
+        {
+            get { return this.level; }
+            set { this.level = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the opcode to use for the event.
+        /// Invalid opcodes (outside the range 0..255) are treated as unset.
+        /// Note that the Opcode attribute can bubble-up, i.e. if a type contains
+        /// a sub-object (a field or property), and the sub-object's type has a
+        /// TraceLoggingEvent attribute, the Opcode from the sub-object's attribute
+        /// can affect the event's opcode.
+        /// 
+        /// Example: for EventSource.Write(name, options, data), the opcode of the
+        /// event will be determined as follows:
+        /// 
+        /// if (options.Opcode has been set)
+        ///     eventOpcode = options.Opcode;
+        /// else if (data.GetType() has a TraceLoggingEvent attribute and attribute.Opcode has been set)
+        ///     eventOpcode = attribute.Opcode;
+        /// else if (a field/property contained in data has a TraceLoggingEvent attribute and attribute.Opcode has been set)
+        ///     eventOpcode = attribute.Opcode;
+        /// else
+        ///     eventOpcode = EventOpcode.Info;
+        /// </summary>
+        internal EventOpcode Opcode
+        {
+            get { return this.opcode; }
+            set { this.opcode = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the keywords to use for the event.
+        /// Note that the Keywords attribute can bubble-up, i.e. if a type contains
+        /// a sub-object (a field or property), and the sub-object's type has a
+        /// TraceLoggingEvent attribute, the Keywords from the sub-object's attribute
+        /// can affect the event's keywords.
+        /// 
+        /// Example: for EventSource.Write(name, options, data), the keywords of the
+        /// event will be determined as follows:
+        /// 
+        /// eventKeywords = options.Keywords;
+        /// if (data.GetType() has a TraceLoggingEvent attribute)
+        ///     eventKeywords |= attribute.Keywords;
+        /// if (a field/property contained in data has a TraceLoggingEvent attribute)
+        ///     eventKeywords |= attribute.Keywords;
+        /// </summary>
+        internal EventKeywords Keywords
+        {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// Gets or sets the flags for an event. These flags are ignored by ETW,
+        /// but can have meaning to the event consumer.
+        /// </summary>
+        internal EventTags Tags
+        {
+            get;
+            set;
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventFieldAttribute.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventFieldAttribute.cs
new file mode 100644 (file)
index 0000000..1a298c2
--- /dev/null
@@ -0,0 +1,76 @@
+// 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;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// Tags are flags that are not interpreted by EventSource but are passed along
+    /// to the EventListener. The EventListener determines the semantics of the flags.
+    /// </summary>
+    [Flags]
+    public enum EventFieldTags
+    {
+        /// <summary>
+        /// No special traits are added to the field.
+        /// </summary>
+        None = 0,
+
+        /* Bits below 0x10000 are available for any use by the provider. */
+        /* Bits at or above 0x10000 are reserved for definition by Microsoft. */
+    }
+
+    /// <summary>
+    /// TraceLogging: used when authoring types that will be passed to EventSource.Write.
+    /// Controls how a field or property is handled when it is written as a
+    /// field in a TraceLogging event. Apply this attribute to a field or
+    /// property if the default handling is not correct. (Apply the
+    /// TraceLoggingIgnore attribute if the property should not be
+    /// included as a field in the event.)
+    /// The default for Name is null, which means that the name of the
+    /// underlying field or property will be used as the event field's name.
+    /// The default for PiiTag is 0, which means that the event field does not
+    /// contain personally-identifiable information.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Property)]
+    public class EventFieldAttribute
+        : Attribute
+    {
+        /// <summary>
+        /// User defined options for the field. These are not interpreted by the EventSource
+        /// but are available to the Listener. See EventFieldSettings for details
+        /// </summary>
+        public EventFieldTags Tags
+        {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// Gets or sets the name to use for the field. This defaults to null.
+        /// If null, the name of the corresponding property will be used
+        /// as the event field's name.
+        /// TODO REMOVE
+        /// </summary>
+        internal string Name
+        {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// Gets or sets a field formatting hint.
+        /// </summary>
+        public EventFieldFormat Format
+        {
+            get;
+            set;
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventFieldFormat.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventFieldFormat.cs
new file mode 100644 (file)
index 0000000..fd77b07
--- /dev/null
@@ -0,0 +1,130 @@
+// 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.
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// Provides a hint that may be used by an event listener when formatting
+    /// an event field for display. Note that the event listener may ignore the
+    /// hint if it does not recognize a particular combination of type and format.
+    /// Similar to TDH_OUTTYPE.
+    /// </summary>
+    public enum EventFieldFormat
+    {
+        /// <summary>
+        /// Field receives default formatting based on the field's underlying type.
+        /// </summary>
+        Default = 0,
+#if false 
+        /// <summary>
+        /// Field should not be displayed.
+        /// </summary>
+        NoPrint = 1,
+#endif
+        /// <summary>
+        /// Field should be formatted as character or string data.
+        /// Typically applied to 8-bit or 16-bit integers.
+        /// This is the default format for String and Char types.
+        /// </summary>
+        String = 2,
+
+        /// <summary>
+        /// Field should be formatted as boolean data. Typically applied to 8-bit
+        /// or 32-bit integers. This is the default format for the Boolean type.
+        /// </summary>
+        Boolean = 3,
+
+        /// <summary>
+        /// Field should be formatted as hexadecimal data. Typically applied to
+        /// integer types.
+        /// </summary>
+        Hexadecimal = 4,
+
+#if false 
+        /// <summary>
+        /// Field should be formatted as a process identifier. Typically applied to
+        /// 32-bit integer types.
+        /// </summary>
+        ProcessId = 5,
+
+        /// <summary>
+        /// Field should be formatted as a thread identifier. Typically applied to
+        /// 32-bit integer types.
+        /// </summary>
+        ThreadId = 6,
+
+        /// <summary>
+        /// Field should be formatted as an Internet port. Typically applied to 16-bit integer
+        /// types.
+        /// </summary>
+        Port = 7,
+        /// <summary>
+        /// Field should be formatted as an Internet Protocol v4 address. Typically applied to
+        /// 32-bit integer types.
+        /// </summary>
+        Ipv4Address = 8,
+
+        /// <summary>
+        /// Field should be formatted as an Internet Protocol v6 address. Typically applied to
+        /// byte[] types.
+        /// </summary>
+        Ipv6Address = 9,
+        /// <summary>
+        /// Field should be formatted as a SOCKADDR. Typically applied to byte[] types.
+        /// </summary>
+        SocketAddress = 10,
+#endif
+        /// <summary>
+        /// Field should be formatted as XML string data. Typically applied to
+        /// strings or arrays of 8-bit or 16-bit integers.
+        /// </summary>
+        Xml = 11,
+
+        /// <summary>
+        /// Field should be formatted as JSON string data. Typically applied to
+        /// strings or arrays of 8-bit or 16-bit integers.
+        /// </summary>
+        Json = 12,
+#if false 
+        /// <summary>
+        /// Field should be formatted as a Win32 error code. Typically applied to
+        /// 32-bit integer types.
+        /// </summary>
+        Win32Error = 13,
+
+        /// <summary>
+        /// Field should be formatted as an NTSTATUS code. Typically applied to
+        /// 32-bit integer types.
+        /// </summary>
+        NTStatus = 14,
+#endif
+        /// <summary>
+        /// Field should be formatted as an HRESULT code. Typically applied to
+        /// 32-bit integer types.
+        /// </summary>
+        HResult = 15,
+#if false 
+        /// <summary>
+        /// Field should be formatted as a FILETIME. Typically applied to 64-bit
+        /// integer types. This is the default format for DateTime types.
+        /// </summary>
+        FileTime = 16,
+        /// <summary>
+        /// When applied to a numeric type, indicates that the type should be formatted
+        /// as a signed integer. This is the default format for signed integer types.
+        /// </summary>
+        Signed = 17,
+
+        /// <summary>
+        /// When applied to a numeric type, indicates that the type should be formatted
+        /// as an unsigned integer. This is the default format for unsigned integer types.
+        /// </summary>
+        Unsigned = 18,
+#endif
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventIgnoreAttribute.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventIgnoreAttribute.cs
new file mode 100644 (file)
index 0000000..769345f
--- /dev/null
@@ -0,0 +1,25 @@
+// 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;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// Used when authoring types that will be passed to EventSource.Write.
+    /// By default, EventSource.Write will write all of an object's public
+    /// properties to the event payload. Apply [EventIgnore] to a public
+    /// property to prevent EventSource.Write from including the property in
+    /// the event.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Property)]
+    public class EventIgnoreAttribute
+        : Attribute
+    {
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs
new file mode 100644 (file)
index 0000000..5967ad6
--- /dev/null
@@ -0,0 +1,155 @@
+// 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.Collections.Generic;
+using System.Collections;
+using System.Diagnostics;
+
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// EventPayload class holds the list of parameters and their corresponding values for user defined types passed to 
+    /// EventSource APIs.
+    /// Preserving the order of the elements as they were found inside user defined types is the most important characteristic of this class.
+    /// </summary>
+    internal class EventPayload : IDictionary<string, object>
+    {
+        internal EventPayload(List<string> payloadNames, List<object> payloadValues) 
+        {
+            Debug.Assert(payloadNames.Count == payloadValues.Count);
+
+            m_names = payloadNames;
+            m_values = payloadValues;
+        }
+
+        public ICollection<string> Keys { get { return m_names; } }
+        public ICollection<object> Values { get { return m_values; } }
+
+        public object this[string key]
+        {
+            get
+            {
+                if (key == null)
+                    throw new System.ArgumentNullException(nameof(key));
+
+                int position = 0;
+                foreach(var name in m_names)
+                { 
+                    if (name == key)
+                    {
+                        return m_values[position];
+                    }
+                    position++;
+                }
+
+                throw new System.Collections.Generic.KeyNotFoundException();
+            }
+            set
+            {
+                throw new System.NotSupportedException();
+            }
+        }
+
+        public void Add(string key, object value)
+        {
+            throw new System.NotSupportedException();
+        }
+
+        public void Add(KeyValuePair<string, object> payloadEntry)
+        {
+            throw new System.NotSupportedException();
+        }
+
+        public void Clear()
+        {
+            throw new System.NotSupportedException();
+        }
+
+        public bool Contains(KeyValuePair<string, object> entry)
+        {
+            return ContainsKey(entry.Key);
+        }
+
+        public bool ContainsKey(string key)
+        {
+            if (key == null)
+                throw new System.ArgumentNullException(nameof(key));
+
+            foreach (var item in m_names)
+            {
+                if (item == key)
+                    return true;
+            }
+            return false;
+        }
+
+        public int Count { get { return m_names.Count; } }
+
+        public bool IsReadOnly { get { return true; } }
+
+        public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
+        {
+            for (int i = 0; i < Keys.Count; i++)
+            {
+                yield return new KeyValuePair<string, object>(this.m_names[i], this.m_values[i]);
+            }
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            var instance = this as IEnumerable<KeyValuePair<string, object>>;
+            return instance.GetEnumerator();
+        }
+
+        public void CopyTo(KeyValuePair<string, object>[] payloadEntries, int count)
+        {
+            throw new System.NotSupportedException();
+        }
+       
+        public bool Remove(string key)
+        {
+            throw new System.NotSupportedException();
+        }
+
+        public bool Remove(KeyValuePair<string, object> entry)
+        {
+            throw new System.NotSupportedException();
+        }
+       
+        public bool TryGetValue(string key, out object value)
+        {
+            if (key == null)
+                throw new System.ArgumentNullException(nameof(key));
+
+            int position = 0;
+            foreach (var name in m_names)
+            {
+                if (name == key)
+                {
+                    value =  m_values[position];
+                    return true;
+                }
+                position++;
+            }
+
+            value = default(object);
+            return false;
+        }
+
+        #region private
+        private List<string> m_names;
+        private List<object> m_values;
+        #endregion
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs
new file mode 100644 (file)
index 0000000..38c1767
--- /dev/null
@@ -0,0 +1,321 @@
+// 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;
+
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// Provides support for EventSource activities by marking the start and
+    /// end of a particular operation.
+    /// </summary>
+    internal sealed class EventSourceActivity
+        : IDisposable
+    {
+        /// <summary>
+        /// Initializes a new instance of the EventSourceActivity class that
+        /// is attached to the specified event source. The new activity will
+        /// not be attached to any related (parent) activity.
+        /// The activity is created in the Initialized state.
+        /// </summary>
+        /// <param name="eventSource">
+        /// The event source to which the activity information is written.
+        /// </param>
+        public EventSourceActivity(EventSource eventSource)
+        {
+            if (eventSource == null)
+                throw new ArgumentNullException(nameof(eventSource));
+            Contract.EndContractBlock();
+
+            this.eventSource = eventSource;
+        }
+
+        /// <summary>
+        /// You can make an activity out of just an EventSource.  
+        /// </summary>
+        public static implicit operator EventSourceActivity(EventSource eventSource) { return new EventSourceActivity(eventSource); }
+
+        /* Properties */
+        /// <summary>
+        /// Gets the event source to which this activity writes events.
+        /// </summary>
+        public EventSource EventSource
+        {
+            get { return this.eventSource; }
+        }
+
+        /// <summary>
+        /// Gets this activity's unique identifier, or the default Guid if the
+        /// event source was disabled when the activity was initialized.
+        /// </summary>
+        public Guid Id
+        {
+            get { return this.activityId; }
+        }
+
+#if false // don't expose RelatedActivityId unless there is a need.   
+        /// <summary>
+        /// Gets the unique identifier of this activity's related (parent)
+        /// activity.
+        /// </summary>
+        public Guid RelatedId
+        {
+            get { return this.relatedActivityId; }
+        }
+#endif
+
+        /// <summary>
+        /// Writes a Start event with the specified name and data.   If the start event is not active (because the provider 
+        /// is not on or keyword-level indiates the event is off, then the returned activity is simply the 'this' poitner 
+        /// and it is effectively like the Start d
+        /// 
+        /// A new activityID GUID is generated and the returned
+        /// EventSourceActivity remembers this activity and will mark every event (including the start stop and any writes)
+        /// with this activityID.   In addition the Start activity will log a 'relatedActivityID' that was the activity
+        /// ID before the start event.   This way event processors can form a linked list of all the activities that
+        /// caused this one (directly or indirectly).  
+        /// </summary>
+        /// <param name="eventName">
+        /// The name to use for the event.   It is strongly suggested that this name end in 'Start' (e.g. DownloadStart).  
+        /// If you do this, then the Stop() method will automatically replace the 'Start' suffix with a 'Stop' suffix.  
+        /// </param>
+        /// <param name="options">Allow options (keywords, level) to be set for the write associated with this start 
+        /// These will also be used for the stop event.</param>
+        /// <param name="data">The data to include in the event.</param>
+        public EventSourceActivity Start<T>(string eventName, EventSourceOptions options, T data)
+        {
+            return this.Start(eventName, ref options, ref data);
+        }
+        /// <summary>
+        /// Shortcut version see Start(string eventName, EventSourceOptions options, T data) Options is empty (no keywords 
+        /// and level==Info) Data payload is empty.  
+        /// </summary>
+        public EventSourceActivity Start(string eventName)
+        {
+            var options = new EventSourceOptions();
+            var data = new EmptyStruct();
+            return this.Start(eventName, ref options, ref data);
+        }
+        /// <summary>
+        /// Shortcut version see Start(string eventName, EventSourceOptions options, T data).  Data payload is empty. 
+        /// </summary>
+        public EventSourceActivity Start(string eventName, EventSourceOptions options)
+        {
+            var data = new EmptyStruct();
+            return this.Start(eventName, ref options, ref data);
+        }
+        /// <summary>
+        /// Shortcut version see Start(string eventName, EventSourceOptions options, T data) Options is empty (no keywords 
+        /// and level==Info) 
+        /// </summary>
+        public EventSourceActivity Start<T>(string eventName, T data)
+        {
+            var options = new EventSourceOptions();
+            return this.Start(eventName, ref options, ref data);
+        }
+
+        /// <summary>
+        /// Writes a Stop event with the specified data, and sets the activity
+        /// to the Stopped state.  The name is determined by the eventName used in Start.
+        /// If that Start event name is suffixed with 'Start' that is removed, and regardless
+        /// 'Stop' is appended to the result to form the Stop event name.  
+        /// May only be called when the activity is in the Started state.
+        /// </summary>
+        /// <param name="data">The data to include in the event.</param>
+        public void Stop<T>(T data)
+        {
+            this.Stop(null, ref data);
+        }
+        /// <summary>
+        /// Used if you wish to use the non-default stop name (which is the start name with Start replace with 'Stop')
+        /// This can be useful to indicate unusual ways of stoping (but it is still STRONGLY recommeded that
+        /// you start with the same prefix used for the start event and you end with the 'Stop' suffix.   
+        /// </summary>
+        public void Stop<T>(string eventName)
+        {
+            var data = new EmptyStruct();
+            this.Stop(eventName, ref data);
+        }
+        /// <summary>
+        /// Used if you wish to use the non-default stop name (which is the start name with Start replace with 'Stop')
+        /// This can be useful to indicate unusual ways of stoping (but it is still STRONGLY recommeded that
+        /// you start with the same prefix used for the start event and you end with the 'Stop' suffix.   
+        /// </summary>
+        public void Stop<T>(string eventName, T data)
+        {
+            this.Stop(eventName, ref data);
+        }
+
+        /// <summary>
+        /// Writes an event associated with this activity to the eventSource associted with this activity.  
+        /// May only be called when the activity is in the Started state.
+        /// </summary>
+        /// <param name="eventName">
+        /// The name to use for the event. If null, the name is determined from
+        /// data's type.
+        /// </param>
+        /// <param name="options">
+        /// The options to use for the event.
+        /// </param>
+        /// <param name="data">The data to include in the event.</param>
+        public void Write<T>(string eventName, EventSourceOptions options, T data)
+        {
+            this.Write(this.eventSource, eventName, ref options, ref data);
+        }
+        /// <summary>
+        /// Writes an event associated with this activity.
+        /// May only be called when the activity is in the Started state.
+        /// </summary>
+        /// <param name="eventName">
+        /// The name to use for the event. If null, the name is determined from
+        /// data's type.
+        /// </param>
+        /// <param name="data">The data to include in the event.</param>
+        public void Write<T>(string eventName, T data)
+        {
+            var options = new EventSourceOptions();
+            this.Write(this.eventSource, eventName, ref options, ref data);
+        }
+        /// <summary>
+        /// Writes a trivial event associated with this activity.
+        /// May only be called when the activity is in the Started state.
+        /// </summary>
+        /// <param name="eventName">
+        /// The name to use for the event. Must not be null.
+        /// </param>
+        /// <param name="options">
+        /// The options to use for the event.
+        /// </param>
+        public void Write(string eventName, EventSourceOptions options)
+        {
+            var data = new EmptyStruct();
+            this.Write(this.eventSource, eventName, ref options, ref data);
+        }
+        /// <summary>
+        /// Writes a trivial event associated with this activity.
+        /// May only be called when the activity is in the Started state.
+        /// </summary>
+        /// <param name="eventName">
+        /// The name to use for the event. Must not be null.
+        /// </param>
+        public void Write(string eventName)
+        {
+            var options = new EventSourceOptions();
+            var data = new EmptyStruct();
+            this.Write(this.eventSource, eventName, ref options, ref data);
+        }
+        /// <summary>
+        /// Writes an event to a arbitrary eventSource stamped with the activity ID of this activity.   
+        /// </summary>
+        public void Write<T>(EventSource source, string eventName, EventSourceOptions options, T data)
+        {
+            this.Write(source, eventName, ref options, ref data);
+        }
+
+        /// <summary>
+        /// Releases any unmanaged resources associated with this object.
+        /// If the activity is in the Started state, calls Stop().
+        /// </summary>
+        public void Dispose()
+        {
+            if (this.state == State.Started)
+            {
+                var data = new EmptyStruct();
+                this.Stop(null, ref data);
+            }
+        }
+
+        #region private
+        private EventSourceActivity Start<T>(string eventName, ref EventSourceOptions options, ref T data)
+        {
+            if (this.state != State.Started)
+                throw new InvalidOperationException();
+
+            // If the source is not on at all, then we don't need to do anything and we can simply return ourselves.  
+            if (!this.eventSource.IsEnabled())
+                return this;
+
+            var newActivity = new EventSourceActivity(eventSource);
+            if (!this.eventSource.IsEnabled(options.Level, options.Keywords))
+            {
+                // newActivity.relatedActivityId = this.Id;
+                Guid relatedActivityId = this.Id;
+                newActivity.activityId = Guid.NewGuid();
+                newActivity.startStopOptions = options;
+                newActivity.eventName = eventName;
+                newActivity.startStopOptions.Opcode = EventOpcode.Start;
+                this.eventSource.Write(eventName, ref newActivity.startStopOptions, ref newActivity.activityId, ref relatedActivityId, ref data);
+            }
+            else
+            {
+                // If we are not active, we don't set the eventName, which basically also turns off the Stop event as well.  
+                newActivity.activityId = this.Id;
+            }
+
+            return newActivity;
+        }
+
+        private void Write<T>(EventSource eventSource, string eventName, ref EventSourceOptions options, ref T data)
+        {
+            if (this.state != State.Started)
+                throw new InvalidOperationException();      // Write after stop. 
+            if (eventName == null)
+                throw new ArgumentNullException();
+
+            eventSource.Write(eventName, ref options, ref this.activityId, ref s_empty, ref data);
+        }
+
+        private void Stop<T>(string eventName, ref T data)
+        {
+            if (this.state != State.Started)
+                throw new InvalidOperationException();
+
+            // If start was not fired, then stop isn't as well.  
+            if (!StartEventWasFired)
+                return;
+
+            this.state = State.Stopped;
+            if (eventName == null)
+            {
+                eventName = this.eventName;
+                if (eventName.EndsWith("Start"))
+                    eventName = eventName.Substring(0, eventName.Length - 5);
+                eventName = eventName + "Stop";
+            }
+            this.startStopOptions.Opcode = EventOpcode.Stop;
+            this.eventSource.Write(eventName, ref this.startStopOptions, ref this.activityId, ref s_empty, ref data);
+        }
+
+        private enum State
+        {
+            Started,
+            Stopped
+        }
+
+        /// <summary>
+        /// If eventName is non-null then we logged a start event 
+        /// </summary>
+        private bool StartEventWasFired { get { return eventName != null; } }
+
+        private readonly EventSource eventSource;
+        private EventSourceOptions startStopOptions;
+        internal Guid activityId;
+        // internal Guid relatedActivityId;
+        private State state;
+        private string eventName;
+
+        static internal Guid s_empty;
+        #endregion
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceOptions.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceOptions.cs
new file mode 100644 (file)
index 0000000..26305a5
--- /dev/null
@@ -0,0 +1,130 @@
+// 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;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// Used when calling EventSource.Write.
+    /// Optional overrides for event settings such as Level, Keywords, or Opcode.
+    /// If overrides are not provided for a setting, default values will be used.
+    /// </summary>
+    public struct EventSourceOptions
+    {
+        internal EventKeywords keywords;
+        internal EventTags tags;
+        internal EventActivityOptions activityOptions;
+        internal byte level;
+        internal byte opcode;
+        internal byte valuesSet;
+
+        internal const byte keywordsSet = 0x1;
+        internal const byte tagsSet = 0x2;
+        internal const byte levelSet = 0x4;
+        internal const byte opcodeSet = 0x8;
+        internal const byte activityOptionsSet = 0x10;
+
+        /// <summary>
+        /// Gets or sets the level to use for the specified event. If this property
+        /// is unset, the event's level will be 5 (Verbose).
+        /// </summary>
+        public EventLevel Level
+        {
+            get
+            {
+                return (EventLevel)this.level;
+            }
+
+            set
+            {
+                this.level = checked((byte)value);
+                this.valuesSet |= levelSet;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the opcode to use for the specified event. If this property
+        /// is unset, the event's opcode will 0 (Info).
+        /// </summary>
+        public EventOpcode Opcode
+        {
+            get
+            {
+                return (EventOpcode)this.opcode;
+            }
+
+            set
+            {
+                this.opcode = checked((byte)value);
+                this.valuesSet |= opcodeSet;
+            }
+        }
+
+        internal bool IsOpcodeSet
+        {
+            get
+            {
+                return (this.valuesSet & opcodeSet) != 0;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the keywords to use for the specified event. If this
+        /// property is unset, the event's keywords will be 0.
+        /// </summary>
+        public EventKeywords Keywords
+        {
+            get
+            {
+                return this.keywords;
+            }
+
+            set
+            {
+                this.keywords = value;
+                this.valuesSet |= keywordsSet;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the tags to use for the specified event. If this property is
+        /// unset, the event's tags will be 0.
+        /// </summary>
+        public EventTags Tags
+        {
+            get
+            {
+                return this.tags;
+            }
+
+            set
+            {
+                this.tags = value;
+                this.valuesSet |= tagsSet;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the activity options for this specified events. If this property is
+        /// unset, the event's activity options will be 0.
+        /// </summary>
+        public EventActivityOptions ActivityOptions
+        {
+            get
+            {
+                return this.activityOptions;
+            }
+            set
+            {
+                this.activityOptions = value;
+                this.valuesSet |= activityOptionsSet;
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs
new file mode 100644 (file)
index 0000000..309226b
--- /dev/null
@@ -0,0 +1,231 @@
+// 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 Encoding = System.Text.Encoding;
+
+#if ES_BUILD_STANDALONE
+using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: Contains the information needed to generate tracelogging
+    /// metadata for an event field.
+    /// </summary>
+    internal class FieldMetadata
+    {
+        /// <summary>
+        /// Name of the field
+        /// </summary>
+        private readonly string name;
+
+        /// <summary>
+        /// The number of bytes in the UTF8 Encoding of 'name' INCLUDING a null terminator.  
+        /// </summary>
+        private readonly int nameSize;
+        private readonly EventFieldTags tags;
+        private readonly byte[] custom;
+
+        /// <summary>
+        /// ETW supports fixed sized arrays. If inType has the InTypeFixedCountFlag then this is the
+        /// statically known count for the array. It is also used to encode the number of bytes of
+        /// custom meta-data if InTypeCustomCountFlag set.
+        /// </summary>
+        private readonly ushort fixedCount;
+
+        private byte inType;
+        private byte outType;
+
+        /// <summary>
+        /// Scalar or variable-length array.
+        /// </summary>
+        public FieldMetadata(
+            string name,
+            TraceLoggingDataType type,
+            EventFieldTags tags,
+            bool variableCount)
+            : this(
+                name,
+                type,
+                tags,
+                variableCount ? Statics.InTypeVariableCountFlag : (byte)0,
+                0,
+                null)
+        {
+            return;
+        }
+
+        /// <summary>
+        /// Fixed-length array.
+        /// </summary>
+        public FieldMetadata(
+            string name,
+            TraceLoggingDataType type,
+            EventFieldTags tags,
+            ushort fixedCount)
+            : this(
+                name,
+                type,
+                tags,
+                Statics.InTypeFixedCountFlag,
+                fixedCount,
+                null)
+        {
+            return;
+        }
+
+        /// <summary>
+        /// Custom serializer
+        /// </summary>
+        public FieldMetadata(
+            string name,
+            TraceLoggingDataType type,
+            EventFieldTags tags,
+            byte[] custom)
+            : this(
+                name,
+                type,
+                tags,
+                Statics.InTypeCustomCountFlag,
+                checked((ushort)(custom == null ? 0 : custom.Length)),
+                custom)
+        {
+            return;
+        }
+
+        private FieldMetadata(
+            string name,
+            TraceLoggingDataType dataType,
+            EventFieldTags tags,
+            byte countFlags,
+            ushort fixedCount = 0,
+            byte[] custom = null)
+        {
+            if (name == null)
+            {
+                throw new ArgumentNullException(
+                    nameof(name),
+                    "This usually means that the object passed to Write is of a type that"
+                    + " does not support being used as the top-level object in an event,"
+                    + " e.g. a primitive or built-in type.");
+            }
+
+            Statics.CheckName(name);
+            var coreType = (int)dataType & Statics.InTypeMask;
+            this.name = name;
+            this.nameSize = Encoding.UTF8.GetByteCount(this.name) + 1;
+            this.inType = (byte)(coreType | countFlags);
+            this.outType = (byte)(((int)dataType >> 8) & Statics.OutTypeMask);
+            this.tags = tags;
+            this.fixedCount = fixedCount;
+            this.custom = custom;
+
+            if (countFlags != 0)
+            {
+                if (coreType == (int)TraceLoggingDataType.Nil)
+                {
+                    throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedArrayOfNil"));
+                }
+                if (coreType == (int)TraceLoggingDataType.Binary)
+                {
+                    throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedArrayOfBinary"));
+                }
+#if !BROKEN_UNTIL_M3
+                if (coreType == (int)TraceLoggingDataType.Utf16String ||
+                    coreType == (int)TraceLoggingDataType.MbcsString)
+                {
+                    throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedArrayOfNullTerminatedString"));
+                }
+#endif
+            }
+
+            if (((int)this.tags & 0xfffffff) != 0)
+            {
+                this.outType |= Statics.OutTypeChainFlag;
+            }
+
+            if (this.outType != 0)
+            {
+                this.inType |= Statics.InTypeChainFlag;
+            }
+        }
+
+        public void IncrementStructFieldCount()
+        {
+            this.inType |= Statics.InTypeChainFlag;
+            this.outType++;
+            if ((this.outType & Statics.OutTypeMask) == 0)
+            {
+                throw new NotSupportedException(Resources.GetResourceString("EventSource_TooManyFields"));
+            }
+        }
+
+        /// <summary>
+        /// This is the main routine for FieldMetaData.  Basically it will serialize the data in
+        /// this structure as TraceLogging style meta-data into the array 'metaArray' starting at
+        /// 'pos' (pos is updated to reflect the bytes written).  
+        /// 
+        /// Note that 'metaData' can be null, in which case it only updates 'pos'.  This is useful
+        /// for a 'two pass' approach where you figure out how big to make the array, and then you
+        /// fill it in.   
+        /// </summary>
+        public void Encode(ref int pos, byte[] metadata)
+        {
+            // Write out the null terminated UTF8 encoded name
+            if (metadata != null)
+            {
+                Encoding.UTF8.GetBytes(this.name, 0, this.name.Length, metadata, pos);
+            }
+            pos += this.nameSize;
+
+            // Write 1 byte for inType
+            if (metadata != null)
+            {
+                metadata[pos] = this.inType;
+            }
+            pos += 1;
+
+            // If InTypeChainFlag set, then write out the outType
+            if (0 != (this.inType & Statics.InTypeChainFlag))
+            {
+                if (metadata != null)
+                {
+                    metadata[pos] = this.outType;
+                }
+                pos += 1;
+
+                // If OutTypeChainFlag set, then write out tags
+                if (0 != (this.outType & Statics.OutTypeChainFlag))
+                {
+                    Statics.EncodeTags((int)this.tags, ref pos, metadata);
+                }
+            }
+
+            // If InTypeFixedCountFlag set, write out the fixedCount (2 bytes little endian)
+            if (0 != (this.inType & Statics.InTypeFixedCountFlag))
+            {
+                if (metadata != null)
+                {
+                    metadata[pos + 0] = unchecked((byte)this.fixedCount);
+                    metadata[pos + 1] = (byte)(this.fixedCount >> 8);
+                }
+                pos += 2;
+
+                // If InTypeCustomCountFlag set, write out the blob of custom meta-data.  
+                if (Statics.InTypeCustomCountFlag == (this.inType & Statics.InTypeCountMask) &&
+                    this.fixedCount != 0)
+                {
+                    if (metadata != null)
+                    {
+                        Buffer.BlockCopy(this.custom, 0, metadata, pos, this.fixedCount);
+                    }
+                    pos += this.fixedCount;
+                }
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs
new file mode 100644 (file)
index 0000000..3e5997b
--- /dev/null
@@ -0,0 +1,96 @@
+// 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.Generic;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: An implementation of TraceLoggingTypeInfo that works
+    /// for arbitrary types. It writes all public instance properties of
+    /// the type.
+    /// </summary>
+    /// <typeparam name="ContainerType">
+    /// Type from which to read values.
+    /// </typeparam>
+    internal sealed class InvokeTypeInfo : TraceLoggingTypeInfo
+    {
+        private readonly PropertyAnalysis[] properties;
+
+        public InvokeTypeInfo(
+            Type type,
+            TypeAnalysis typeAnalysis)
+            : base(
+                type,
+                typeAnalysis.name,
+                typeAnalysis.level,
+                typeAnalysis.opcode,
+                typeAnalysis.keywords,
+                typeAnalysis.tags)
+        {
+            if (typeAnalysis.properties.Length != 0)
+                this.properties = typeAnalysis.properties;
+        }
+
+        public override void WriteMetadata(
+            TraceLoggingMetadataCollector collector,
+            string name,
+            EventFieldFormat format)
+        {
+            var groupCollector = collector.AddGroup(name);
+            if (this.properties != null)
+            {
+                foreach (var property in this.properties)
+                {
+                    var propertyFormat = EventFieldFormat.Default;
+                    var propertyAttribute = property.fieldAttribute;
+                    if (propertyAttribute != null)
+                    {
+                        groupCollector.Tags = propertyAttribute.Tags;
+                        propertyFormat = propertyAttribute.Format;
+                    }
+
+                    property.typeInfo.WriteMetadata(
+                        groupCollector,
+                        property.name,
+                        propertyFormat);
+                }
+            }
+        }
+
+        public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
+        {
+            if (this.properties != null)
+            {
+                foreach (var property in this.properties)
+                {
+                    property.typeInfo.WriteData(collector, property.getter(value));
+                }
+            }
+        }
+
+        public override object GetData(object value)
+        {
+            if (this.properties != null)
+            {
+                var membersNames = new List<string>();
+                var memebersValues = new List<object>();
+                for (int i = 0; i < this.properties.Length; i++)
+                {
+                    var propertyValue = properties[i].propertyInfo.GetValue(value);
+                    membersNames.Add(properties[i].name);
+                    memebersValues.Add(properties[i].typeInfo.GetData(propertyValue));
+                }
+                return new EventPayload(membersNames, memebersValues);
+            }
+
+            return null;
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs
new file mode 100644 (file)
index 0000000..668043a
--- /dev/null
@@ -0,0 +1,79 @@
+// 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.Generic;
+using Interlocked = System.Threading.Interlocked;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: Stores the metadata and event identifier corresponding
+    /// to a tracelogging event type+name+tags combination.
+    /// </summary>
+    internal sealed class NameInfo
+        : ConcurrentSetItem<KeyValuePair<string, EventTags>, NameInfo>
+    {
+        /// <summary>
+        /// Insure that eventIds strictly less than 'eventId' will not be
+        /// used by the SelfDescribing events.   
+        /// </summary>
+        internal static void ReserveEventIDsBelow(int eventId)
+        {
+            for(;;)
+            {
+                int snapshot = lastIdentity;
+                int newIdentity = (lastIdentity & ~0xFFFFFF) + eventId;
+                newIdentity = Math.Max(newIdentity, snapshot);      // Should be redundant.  as we only create descriptors once.  
+                if (Interlocked.CompareExchange(ref lastIdentity, newIdentity, snapshot) == snapshot)
+                    break;
+            }
+        }
+
+        private static int lastIdentity = Statics.TraceLoggingChannel << 24;
+        internal readonly string name;
+        internal readonly EventTags tags;
+        internal readonly int identity;
+        internal readonly byte[] nameMetadata;
+
+        public NameInfo(string name, EventTags tags, int typeMetadataSize)
+        {
+            this.name = name;
+            this.tags = tags & Statics.EventTagsMask;
+            this.identity = Interlocked.Increment(ref lastIdentity);
+
+            int tagsPos = 0;
+            Statics.EncodeTags((int)this.tags, ref tagsPos, null);
+
+            this.nameMetadata = Statics.MetadataForString(name, tagsPos, 0, typeMetadataSize);
+
+            tagsPos = 2;
+            Statics.EncodeTags((int)this.tags, ref tagsPos, this.nameMetadata);
+        }
+
+        public override int Compare(NameInfo other)
+        {
+            return this.Compare(other.name, other.tags);
+        }
+
+        public override int Compare(KeyValuePair<string, EventTags> key)
+        {
+            return this.Compare(key.Key, key.Value & Statics.EventTagsMask);
+        }
+
+        private int Compare(string otherName, EventTags otherTags)
+        {
+            int result = StringComparer.Ordinal.Compare(this.name, otherName);
+            if (result == 0 && this.tags != otherTags)
+            {
+                result = this.tags < otherTags ? -1 : 1;
+            }
+            return result;
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyAnalysis.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyAnalysis.cs
new file mode 100644 (file)
index 0000000..1f07539
--- /dev/null
@@ -0,0 +1,39 @@
+// 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.Reflection;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: stores the per-property information obtained by
+    /// reflecting over a type.
+    /// </summary>
+    internal sealed class PropertyAnalysis
+    {
+        internal readonly string name;
+        internal readonly PropertyInfo propertyInfo;
+        internal readonly Func<PropertyValue, PropertyValue> getter;
+        internal readonly TraceLoggingTypeInfo typeInfo;
+        internal readonly EventFieldAttribute fieldAttribute;
+
+        public PropertyAnalysis(
+            string name,
+            PropertyInfo propertyInfo,
+            TraceLoggingTypeInfo typeInfo,
+            EventFieldAttribute fieldAttribute)
+        {
+            this.name = name;
+            this.propertyInfo = propertyInfo;
+            this.getter = PropertyValue.GetPropertyGetter(propertyInfo);
+            this.typeInfo = typeInfo;
+            this.fieldAttribute = fieldAttribute;
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs
new file mode 100644 (file)
index 0000000..3ea7812
--- /dev/null
@@ -0,0 +1,252 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
+namespace System.Diagnostics.Tracing
+{
+    /// <summary>
+    /// Holds property values of any type.  For common value types, we have inline storage so that we don't need
+    /// to box the values.  For all other types, we store the value in a single object reference field.
+    /// 
+    /// To get the value of a property quickly, use a delegate produced by <see cref="PropertyValue.GetPropertyGetter(PropertyInfo)"/>.
+    /// </summary>
+    internal unsafe struct PropertyValue
+    {
+        /// <summary>
+        /// Union of well-known value types, to avoid boxing those types.
+        /// </summary>
+        [StructLayout(LayoutKind.Explicit)]
+        public struct Scalar
+        {
+            [FieldOffset(0)]
+            public Boolean AsBoolean;
+            [FieldOffset(0)]
+            public Byte AsByte;
+            [FieldOffset(0)]
+            public SByte AsSByte;
+            [FieldOffset(0)]
+            public Char AsChar;
+            [FieldOffset(0)]
+            public Int16 AsInt16;
+            [FieldOffset(0)]
+            public UInt16 AsUInt16;
+            [FieldOffset(0)]
+            public Int32 AsInt32;
+            [FieldOffset(0)]
+            public UInt32 AsUInt32;
+            [FieldOffset(0)]
+            public Int64 AsInt64;
+            [FieldOffset(0)]
+            public UInt64 AsUInt64;
+            [FieldOffset(0)]
+            public IntPtr AsIntPtr;
+            [FieldOffset(0)]
+            public UIntPtr AsUIntPtr;
+            [FieldOffset(0)]
+            public Single AsSingle;
+            [FieldOffset(0)]
+            public Double AsDouble;
+            [FieldOffset(0)]
+            public Guid AsGuid;
+            [FieldOffset(0)]
+            public DateTime AsDateTime;
+            [FieldOffset(0)]
+            public DateTimeOffset AsDateTimeOffset;
+            [FieldOffset(0)]
+            public TimeSpan AsTimeSpan;
+            [FieldOffset(0)]
+            public Decimal AsDecimal;
+        }
+
+        // Anything not covered by the Scalar union gets stored in this reference.
+        readonly object _reference;
+        readonly Scalar _scalar;
+        readonly int _scalarLength;
+
+        private PropertyValue(object value)
+        {
+            _reference = value;
+            _scalar = default(Scalar);
+            _scalarLength = 0;
+        }
+
+        private PropertyValue(Scalar scalar, int scalarLength)
+        {
+            _reference = null;
+            _scalar = scalar;
+            _scalarLength = scalarLength;
+        }
+
+        private PropertyValue(Boolean value) : this(new Scalar() { AsBoolean = value }, sizeof(Boolean)) { }
+        private PropertyValue(Byte value) : this(new Scalar() { AsByte = value }, sizeof(Byte)) { }
+        private PropertyValue(SByte value) : this(new Scalar() { AsSByte = value }, sizeof(SByte)) { }
+        private PropertyValue(Char value) : this(new Scalar() { AsChar = value }, sizeof(Char)) { }
+        private PropertyValue(Int16 value) : this(new Scalar() { AsInt16 = value }, sizeof(Int16)) { }
+        private PropertyValue(UInt16 value) : this(new Scalar() { AsUInt16 = value }, sizeof(UInt16)) { }
+        private PropertyValue(Int32 value) : this(new Scalar() { AsInt32 = value }, sizeof(Int32)) { }
+        private PropertyValue(UInt32 value) : this(new Scalar() { AsUInt32 = value }, sizeof(UInt32)) { }
+        private PropertyValue(Int64 value) : this(new Scalar() { AsInt64 = value }, sizeof(Int64)) { }
+        private PropertyValue(UInt64 value) : this(new Scalar() { AsUInt64 = value }, sizeof(UInt64)) { }
+        private PropertyValue(IntPtr value) : this(new Scalar() { AsIntPtr = value }, sizeof(IntPtr)) { }
+        private PropertyValue(UIntPtr value) : this(new Scalar() { AsUIntPtr = value }, sizeof(UIntPtr)) { }
+        private PropertyValue(Single value) : this(new Scalar() { AsSingle = value }, sizeof(Single)) { }
+        private PropertyValue(Double value) : this(new Scalar() { AsDouble = value }, sizeof(Double)) { }
+        private PropertyValue(Guid value) : this(new Scalar() { AsGuid = value }, sizeof(Guid)) { }
+        private PropertyValue(DateTime value) : this(new Scalar() { AsDateTime = value }, sizeof(DateTime)) { }
+        private PropertyValue(DateTimeOffset value) : this(new Scalar() { AsDateTimeOffset = value }, sizeof(DateTimeOffset)) { }
+        private PropertyValue(TimeSpan value) : this(new Scalar() { AsTimeSpan = value }, sizeof(TimeSpan)) { }
+        private PropertyValue(Decimal value) : this(new Scalar() { AsDecimal = value }, sizeof(Decimal)) { }
+
+        public static Func<object, PropertyValue> GetFactory(Type type)
+        {
+            if (type == typeof(Boolean)) return value => new PropertyValue((Boolean)value);
+            if (type == typeof(Byte)) return value => new PropertyValue((Byte)value);
+            if (type == typeof(SByte)) return value => new PropertyValue((SByte)value);
+            if (type == typeof(Char)) return value => new PropertyValue((Char)value);
+            if (type == typeof(Int16)) return value => new PropertyValue((Int16)value);
+            if (type == typeof(UInt16)) return value => new PropertyValue((UInt16)value);
+            if (type == typeof(Int32)) return value => new PropertyValue((Int32)value);
+            if (type == typeof(UInt32)) return value => new PropertyValue((UInt32)value);
+            if (type == typeof(Int64)) return value => new PropertyValue((Int64)value);
+            if (type == typeof(UInt64)) return value => new PropertyValue((UInt64)value);
+            if (type == typeof(IntPtr)) return value => new PropertyValue((IntPtr)value);
+            if (type == typeof(UIntPtr)) return value => new PropertyValue((UIntPtr)value);
+            if (type == typeof(Single)) return value => new PropertyValue((Single)value);
+            if (type == typeof(Double)) return value => new PropertyValue((Double)value);
+            if (type == typeof(Guid)) return value => new PropertyValue((Guid)value);
+            if (type == typeof(DateTime)) return value => new PropertyValue((DateTime)value);
+            if (type == typeof(DateTimeOffset)) return value => new PropertyValue((DateTimeOffset)value);
+            if (type == typeof(TimeSpan)) return value => new PropertyValue((TimeSpan)value);
+            if (type == typeof(Decimal)) return value => new PropertyValue((Decimal)value);
+
+            return value => new PropertyValue(value);
+        }
+
+
+        public object ReferenceValue
+        {
+            get
+            {
+                Debug.Assert(_scalarLength == 0, "This ReflectedValue refers to an unboxed value type, not a reference type or boxed value type.");
+                return _reference;
+            }
+        }
+
+        public Scalar ScalarValue
+        {
+            get
+            {
+                Debug.Assert(_scalarLength > 0, "This ReflectedValue refers to a reference type or boxed value type, not an unboxed value type");
+                return _scalar;
+            }
+        }
+
+        public int ScalarLength
+        {
+            get
+            {
+                Debug.Assert(_scalarLength > 0, "This ReflectedValue refers to a reference type or boxed value type, not an unboxed value type");
+                return _scalarLength;
+            }
+        }
+
+        /// <summary>
+        /// Gets a delegate that gets the value of a given property.
+        /// </summary>
+        public static Func<PropertyValue, PropertyValue> GetPropertyGetter(PropertyInfo property)
+        {
+            if (property.DeclaringType.GetTypeInfo().IsValueType)
+                return GetBoxedValueTypePropertyGetter(property);
+            else
+                return GetReferenceTypePropertyGetter(property);
+        }
+
+        /// <summary>
+        /// Gets a delegate that gets the value of a property of a value type.  We unfortunately cannot avoid boxing the value type,
+        /// without making this generic over the value type.  That would result in a large number of generic instantiations, and furthermore
+        /// does not work correctly on .Net Native (we cannot express the needed instantiations in an rd.xml file).  We expect that user-defined
+        /// value types will be rare, and in any case the boxing only happens for events that are actually enabled.
+        /// </summary>
+        private static Func<PropertyValue, PropertyValue> GetBoxedValueTypePropertyGetter(PropertyInfo property)
+        {
+            var type = property.PropertyType;
+
+            if (type.GetTypeInfo().IsEnum)
+                type = Enum.GetUnderlyingType(type);
+
+            var factory = GetFactory(type);
+
+            return container => factory(property.GetValue(container.ReferenceValue));
+        }
+
+        /// <summary>
+        /// For properties of reference types, we use a generic helper class to get the value.  This enables us to use MethodInfo.CreateDelegate
+        /// to build a fast getter.  We can get away with this on .Net Native, because we really only need one runtime instantiation of the
+        /// generic type, since it's only instantiated over reference types (and thus all instances are shared).
+        /// </summary>
+        /// <param name="property"></param>
+        /// <returns></returns>
+        private static Func<PropertyValue, PropertyValue> GetReferenceTypePropertyGetter(PropertyInfo property)
+        {
+            var helper = (TypeHelper)Activator.CreateInstance(typeof(ReferenceTypeHelper<>).MakeGenericType(property.DeclaringType));
+            return helper.GetPropertyGetter(property);
+        }
+
+        private abstract class TypeHelper
+        {
+            public abstract Func<PropertyValue, PropertyValue> GetPropertyGetter(PropertyInfo property);
+
+            protected Delegate GetGetMethod(PropertyInfo property, Type propertyType)
+            {
+                return property.GetMethod.CreateDelegate(typeof(Func<,>).MakeGenericType(property.DeclaringType, propertyType));
+            }
+        }
+
+        private sealed class ReferenceTypeHelper<TContainer> : TypeHelper where TContainer : class
+        {
+            public override Func<PropertyValue, PropertyValue> GetPropertyGetter(PropertyInfo property)
+            {
+                var type = property.PropertyType;
+
+                if (!Statics.IsValueType(type))
+                {
+                    var getter = (Func<TContainer, object>)GetGetMethod(property, type);
+                    return container => new PropertyValue(getter((TContainer)container.ReferenceValue));
+                }
+                else
+                {
+                    if (type.GetTypeInfo().IsEnum)
+                        type = Enum.GetUnderlyingType(type);
+
+                    if (type == typeof(Boolean)) { var f = (Func<TContainer, Boolean>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(Byte)) { var f = (Func<TContainer, Byte>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(SByte)) { var f = (Func<TContainer, SByte>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(Char)) { var f = (Func<TContainer, Char>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(Int16)) { var f = (Func<TContainer, Int16>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(UInt16)) { var f = (Func<TContainer, UInt16>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(Int32)) { var f = (Func<TContainer, Int32>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(UInt32)) { var f = (Func<TContainer, UInt32>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(Int64)) { var f = (Func<TContainer, Int64>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(UInt64)) { var f = (Func<TContainer, UInt64>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(IntPtr)) { var f = (Func<TContainer, IntPtr>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(UIntPtr)) { var f = (Func<TContainer, UIntPtr>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(Single)) { var f = (Func<TContainer, Single>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(Double)) { var f = (Func<TContainer, Double>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(Guid)) { var f = (Func<TContainer, Guid>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(DateTime)) { var f = (Func<TContainer, DateTime>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(DateTimeOffset)) { var f = (Func<TContainer, DateTimeOffset>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(TimeSpan)) { var f = (Func<TContainer, TimeSpan>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+                    if (type == typeof(Decimal)) { var f = (Func<TContainer, Decimal>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); }
+
+                    return container => new PropertyValue(property.GetValue(container.ReferenceValue));
+                }
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleEventTypes.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleEventTypes.cs
new file mode 100644 (file)
index 0000000..cdced96
--- /dev/null
@@ -0,0 +1,39 @@
+// 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 Interlocked = System.Threading.Interlocked;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: Contains the metadata needed to emit an event, optimized
+    /// for events with one top-level compile-time-typed payload object.
+    /// </summary>
+    /// <typeparam name="T">
+    /// Type of the top-level payload object. Should be EmptyStruct if the
+    /// event has no payload.
+    /// </typeparam>
+    internal static class SimpleEventTypes<T>
+    {
+        private static TraceLoggingEventTypes instance;
+
+        public static TraceLoggingEventTypes Instance
+        {
+            get { return instance ?? InitInstance(); }
+        }
+
+        private static TraceLoggingEventTypes InitInstance()
+        {
+            var info = TraceLoggingTypeInfo.GetInstance(typeof(T), null);
+            var newInstance = new TraceLoggingEventTypes(info.Name, info.Tags, new TraceLoggingTypeInfo[] { info });
+            Interlocked.CompareExchange(ref instance, newInstance, null);
+            return instance;
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs
new file mode 100644 (file)
index 0000000..901a0ed
--- /dev/null
@@ -0,0 +1,297 @@
+// 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.Generic;
+using System.Reflection;
+using System.Diagnostics;
+
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: Type handler for empty or unsupported types.
+    /// </summary>
+    internal sealed class NullTypeInfo : TraceLoggingTypeInfo
+    {
+        public NullTypeInfo() : base(typeof(EmptyStruct)) { }
+
+        public override void WriteMetadata(
+            TraceLoggingMetadataCollector collector,
+            string name,
+            EventFieldFormat format)
+        {
+            collector.AddGroup(name);
+        }
+
+        public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
+        {
+            return;
+        }
+
+        public override object GetData(object value)
+        {
+            return null;
+        }
+    }
+
+    /// <summary>
+    /// Type handler for simple scalar types.
+    /// </summary>
+    sealed class ScalarTypeInfo : TraceLoggingTypeInfo
+    {
+        Func<EventFieldFormat, TraceLoggingDataType, TraceLoggingDataType> formatFunc;
+        TraceLoggingDataType nativeFormat;
+
+        private ScalarTypeInfo(
+            Type type,
+            Func<EventFieldFormat, TraceLoggingDataType, TraceLoggingDataType> formatFunc,
+            TraceLoggingDataType nativeFormat) 
+            : base(type)
+        {
+            this.formatFunc = formatFunc;
+            this.nativeFormat = nativeFormat;
+        }
+
+        public override void WriteMetadata(TraceLoggingMetadataCollector collector, string name, EventFieldFormat format)
+        {
+            collector.AddScalar(name, formatFunc(format, nativeFormat));
+        }
+
+        public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
+        {
+            collector.AddScalar(value);
+        }
+
+        public static TraceLoggingTypeInfo Boolean() { return new ScalarTypeInfo(typeof(Boolean), Statics.Format8, TraceLoggingDataType.Boolean8); }
+        public static TraceLoggingTypeInfo Byte() { return new ScalarTypeInfo(typeof(Byte), Statics.Format8, TraceLoggingDataType.UInt8); }
+        public static TraceLoggingTypeInfo SByte() { return new ScalarTypeInfo(typeof(SByte), Statics.Format8, TraceLoggingDataType.Int8); }
+        public static TraceLoggingTypeInfo Char() { return new ScalarTypeInfo(typeof(Char), Statics.Format16, TraceLoggingDataType.Char16); }
+        public static TraceLoggingTypeInfo Int16() { return new ScalarTypeInfo(typeof(Int16), Statics.Format16, TraceLoggingDataType.Int16); }
+        public static TraceLoggingTypeInfo UInt16() { return new ScalarTypeInfo(typeof(UInt16), Statics.Format16, TraceLoggingDataType.UInt16); }
+        public static TraceLoggingTypeInfo Int32() { return new ScalarTypeInfo(typeof(Int32), Statics.Format32, TraceLoggingDataType.Int32); }
+        public static TraceLoggingTypeInfo UInt32() { return new ScalarTypeInfo(typeof(UInt32), Statics.Format32, TraceLoggingDataType.UInt32); }
+        public static TraceLoggingTypeInfo Int64() { return new ScalarTypeInfo(typeof(Int64), Statics.Format64, TraceLoggingDataType.Int64); }
+        public static TraceLoggingTypeInfo UInt64() { return new ScalarTypeInfo(typeof(UInt64), Statics.Format64, TraceLoggingDataType.UInt64); }
+        public static TraceLoggingTypeInfo IntPtr() { return new ScalarTypeInfo(typeof(IntPtr), Statics.FormatPtr, Statics.IntPtrType); }
+        public static TraceLoggingTypeInfo UIntPtr() { return new ScalarTypeInfo(typeof(UIntPtr), Statics.FormatPtr, Statics.UIntPtrType); }
+        public static TraceLoggingTypeInfo Single() { return new ScalarTypeInfo(typeof(Single), Statics.Format32, TraceLoggingDataType.Float); }
+        public static TraceLoggingTypeInfo Double() { return new ScalarTypeInfo(typeof(Double), Statics.Format64, TraceLoggingDataType.Double); }
+        public static TraceLoggingTypeInfo Guid() { return new ScalarTypeInfo(typeof(Guid), (f, t) => Statics.MakeDataType(TraceLoggingDataType.Guid, f), TraceLoggingDataType.Guid); }
+    }
+
+
+    /// <summary>
+    /// Type handler for arrays of scalars
+    /// </summary>
+    internal sealed class ScalarArrayTypeInfo : TraceLoggingTypeInfo
+    {
+        Func<EventFieldFormat, TraceLoggingDataType, TraceLoggingDataType> formatFunc;
+        TraceLoggingDataType nativeFormat;
+        int elementSize;
+
+        private ScalarArrayTypeInfo(
+            Type type,
+            Func<EventFieldFormat, TraceLoggingDataType, TraceLoggingDataType> formatFunc,
+            TraceLoggingDataType nativeFormat,
+            int elementSize) 
+            : base(type)
+        {
+            this.formatFunc = formatFunc;
+            this.nativeFormat = nativeFormat;
+            this.elementSize = elementSize;
+        }
+
+        public override void WriteMetadata(TraceLoggingMetadataCollector collector, string name, EventFieldFormat format)
+        {
+            collector.AddArray(name, formatFunc(format, nativeFormat));
+        }
+
+        public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
+        {
+            collector.AddArray(value, elementSize);
+        }
+
+        public static TraceLoggingTypeInfo Boolean() { return new ScalarArrayTypeInfo(typeof(Boolean[]), Statics.Format8, TraceLoggingDataType.Boolean8, sizeof(Boolean)); }
+        public static TraceLoggingTypeInfo Byte() { return new ScalarArrayTypeInfo(typeof(Byte[]), Statics.Format8, TraceLoggingDataType.UInt8, sizeof(Byte)); }
+        public static TraceLoggingTypeInfo SByte() { return new ScalarArrayTypeInfo(typeof(SByte[]), Statics.Format8, TraceLoggingDataType.Int8, sizeof(SByte)); }
+        public static TraceLoggingTypeInfo Char() { return new ScalarArrayTypeInfo(typeof(Char[]), Statics.Format16, TraceLoggingDataType.Char16, sizeof(Char)); }
+        public static TraceLoggingTypeInfo Int16() { return new ScalarArrayTypeInfo(typeof(Int16[]), Statics.Format16, TraceLoggingDataType.Int16, sizeof(Int16)); }
+        public static TraceLoggingTypeInfo UInt16() { return new ScalarArrayTypeInfo(typeof(UInt16[]), Statics.Format16, TraceLoggingDataType.UInt16, sizeof(UInt16)); }
+        public static TraceLoggingTypeInfo Int32() { return new ScalarArrayTypeInfo(typeof(Int32[]), Statics.Format32, TraceLoggingDataType.Int32, sizeof(Int32)); }
+        public static TraceLoggingTypeInfo UInt32() { return new ScalarArrayTypeInfo(typeof(UInt32[]), Statics.Format32, TraceLoggingDataType.UInt32, sizeof(UInt32)); }
+        public static TraceLoggingTypeInfo Int64() { return new ScalarArrayTypeInfo(typeof(Int64[]), Statics.Format64, TraceLoggingDataType.Int64, sizeof(Int64)); }
+        public static TraceLoggingTypeInfo UInt64() { return new ScalarArrayTypeInfo(typeof(UInt64[]), Statics.Format64, TraceLoggingDataType.UInt64, sizeof(UInt64)); }
+        public static TraceLoggingTypeInfo IntPtr() { return new ScalarArrayTypeInfo(typeof(IntPtr[]), Statics.FormatPtr, Statics.IntPtrType, System.IntPtr.Size); }
+        public static TraceLoggingTypeInfo UIntPtr() { return new ScalarArrayTypeInfo(typeof(UIntPtr[]), Statics.FormatPtr, Statics.UIntPtrType, System.IntPtr.Size); }
+        public static TraceLoggingTypeInfo Single() { return new ScalarArrayTypeInfo(typeof(Single[]), Statics.Format32, TraceLoggingDataType.Float, sizeof(Single)); }
+        public static TraceLoggingTypeInfo Double() { return new ScalarArrayTypeInfo(typeof(Double[]), Statics.Format64, TraceLoggingDataType.Double, sizeof(Double)); }
+        public unsafe static TraceLoggingTypeInfo Guid() { return new ScalarArrayTypeInfo(typeof(Guid), (f, t) => Statics.MakeDataType(TraceLoggingDataType.Guid, f), TraceLoggingDataType.Guid, sizeof(Guid)); }
+    }
+
+    /// <summary>
+    /// TraceLogging: Type handler for String.
+    /// </summary>
+    internal sealed class StringTypeInfo : TraceLoggingTypeInfo
+    {
+        public StringTypeInfo() : base(typeof(string)) { }
+
+        public override void WriteMetadata(
+            TraceLoggingMetadataCollector collector,
+            string name,
+            EventFieldFormat format)
+        {
+            collector.AddBinary(name, Statics.MakeDataType(TraceLoggingDataType.CountedUtf16String, format));
+        }
+
+        public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
+        {
+            collector.AddBinary((string)value.ReferenceValue);
+        }
+        
+        public override object GetData(object value)
+        {
+            if(value == null)
+            {
+                return "";
+            }
+            
+            return value;
+        }
+    }
+
+    /// <summary>
+    /// TraceLogging: Type handler for DateTime.
+    /// </summary>
+    internal sealed class DateTimeTypeInfo : TraceLoggingTypeInfo
+    {
+        public DateTimeTypeInfo() : base(typeof(DateTime)) { }
+
+        public override void WriteMetadata(
+            TraceLoggingMetadataCollector collector,
+            string name,
+            EventFieldFormat format)
+        {
+            collector.AddScalar(name, Statics.MakeDataType(TraceLoggingDataType.FileTime, format));
+        }
+
+        public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
+        {
+            var ticks = value.ScalarValue.AsDateTime.Ticks;
+            collector.AddScalar(ticks < 504911232000000000 ? 0 : ticks - 504911232000000000);
+        }
+    }
+
+    /// <summary>
+    /// TraceLogging: Type handler for DateTimeOffset.
+    /// </summary>
+    internal sealed class DateTimeOffsetTypeInfo : TraceLoggingTypeInfo
+    {
+        public DateTimeOffsetTypeInfo() : base(typeof(DateTimeOffset)) { }
+
+        public override void WriteMetadata(TraceLoggingMetadataCollector collector, string name, EventFieldFormat format)
+        {
+            var group = collector.AddGroup(name);
+            group.AddScalar("Ticks", Statics.MakeDataType(TraceLoggingDataType.FileTime, format));
+            group.AddScalar("Offset", TraceLoggingDataType.Int64);
+        }
+
+        public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
+        {
+            var dateTimeOffset = value.ScalarValue.AsDateTimeOffset;
+            var ticks = dateTimeOffset.Ticks;
+            collector.AddScalar(ticks < 504911232000000000 ? 0 : ticks - 504911232000000000);
+            collector.AddScalar(dateTimeOffset.Offset.Ticks);
+        }
+    }
+
+    /// <summary>
+    /// TraceLogging: Type handler for TimeSpan.
+    /// </summary>
+    internal sealed class TimeSpanTypeInfo : TraceLoggingTypeInfo
+    {
+        public TimeSpanTypeInfo() : base(typeof(TimeSpan)) { }
+
+        public override void WriteMetadata(
+            TraceLoggingMetadataCollector collector,
+            string name,
+            EventFieldFormat format)
+        {
+            collector.AddScalar(name, Statics.MakeDataType(TraceLoggingDataType.Int64, format));
+        }
+
+        public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
+        {
+            collector.AddScalar(value.ScalarValue.AsTimeSpan.Ticks);
+        }
+    }
+
+    /// <summary>
+    /// TraceLogging: Type handler for Decimal. (Note: not full-fidelity, exposed as Double.)
+    /// </summary>
+    internal sealed class DecimalTypeInfo : TraceLoggingTypeInfo
+    {
+        public DecimalTypeInfo() : base(typeof(Decimal)) { }
+
+        public override void WriteMetadata(
+            TraceLoggingMetadataCollector collector,
+            string name,
+            EventFieldFormat format)
+        {
+            collector.AddScalar(name, Statics.MakeDataType(TraceLoggingDataType.Double, format));
+        }
+
+        public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
+        {
+            collector.AddScalar((double)value.ScalarValue.AsDecimal);
+        }
+    }
+
+    /// <summary>
+    /// TraceLogging: Type handler for Nullable.
+    /// </summary>
+    internal sealed class NullableTypeInfo : TraceLoggingTypeInfo
+    {
+        private readonly TraceLoggingTypeInfo valueInfo;
+        private readonly Func<PropertyValue, PropertyValue> hasValueGetter;
+        private readonly Func<PropertyValue, PropertyValue> valueGetter;
+
+        public NullableTypeInfo(Type type, List<Type> recursionCheck)
+            : base(type)
+        {
+            var typeArgs = type.GenericTypeArguments;
+            Debug.Assert(typeArgs.Length == 1);
+            this.valueInfo = TraceLoggingTypeInfo.GetInstance(typeArgs[0], recursionCheck);
+            this.hasValueGetter = PropertyValue.GetPropertyGetter(type.GetTypeInfo().GetDeclaredProperty("HasValue"));
+            this.valueGetter = PropertyValue.GetPropertyGetter(type.GetTypeInfo().GetDeclaredProperty("Value"));
+        }
+
+        public override void WriteMetadata(
+            TraceLoggingMetadataCollector collector,
+            string name,
+            EventFieldFormat format)
+        {
+            var group = collector.AddGroup(name);
+            group.AddScalar("HasValue", TraceLoggingDataType.Boolean8);
+            this.valueInfo.WriteMetadata(group, "Value", format);
+        }
+
+        public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
+        {
+            var hasValue = hasValueGetter(value);
+            collector.AddScalar(hasValue);
+            var val = hasValue.ScalarValue.AsBoolean ? valueGetter(value) : valueInfo.PropertyValueFactory(Activator.CreateInstance(valueInfo.DataType));
+            this.valueInfo.WriteData(collector, val);
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs
new file mode 100644 (file)
index 0000000..9fa7767
--- /dev/null
@@ -0,0 +1,727 @@
+// 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.Generic;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using Encoding = System.Text.Encoding;
+
+using Microsoft.Reflection;
+
+#if ES_BUILD_STANDALONE
+using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: Constants and utility functions.
+    /// </summary>
+    internal static class Statics
+    {
+        #region Constants
+
+        public const byte DefaultLevel = 5;
+        public const byte TraceLoggingChannel = 0xb;
+        public const byte InTypeMask = 31;
+        public const byte InTypeFixedCountFlag = 32;
+        public const byte InTypeVariableCountFlag = 64;
+        public const byte InTypeCustomCountFlag = 96;
+        public const byte InTypeCountMask = 96;
+        public const byte InTypeChainFlag = 128;
+        public const byte OutTypeMask = 127;
+        public const byte OutTypeChainFlag = 128;
+        public const EventTags EventTagsMask = (EventTags)0xfffffff;
+
+        public static readonly TraceLoggingDataType IntPtrType = IntPtr.Size == 8
+            ? TraceLoggingDataType.Int64
+            : TraceLoggingDataType.Int32;
+        public static readonly TraceLoggingDataType UIntPtrType = IntPtr.Size == 8
+            ? TraceLoggingDataType.UInt64
+            : TraceLoggingDataType.UInt32;
+        public static readonly TraceLoggingDataType HexIntPtrType = IntPtr.Size == 8
+            ? TraceLoggingDataType.HexInt64
+            : TraceLoggingDataType.HexInt32;
+
+        #endregion
+
+        #region Metadata helpers
+
+        /// <summary>
+        /// A complete metadata chunk can be expressed as:
+        /// length16 + prefix + null-terminated-utf8-name + suffix + additionalData.
+        /// We assume that excludedData will be provided by some other means,
+        /// but that its size is known. This function returns a blob containing
+        /// length16 + prefix + name + suffix, with prefix and suffix initialized
+        /// to 0's. The length16 value is initialized to the length of the returned
+        /// blob plus additionalSize, so that the concatenation of the returned blob
+        /// plus a blob of size additionalSize constitutes a valid metadata blob.
+        /// </summary>
+        /// <param name="name">
+        /// The name to include in the blob.
+        /// </param>
+        /// <param name="prefixSize">
+        /// Amount of space to reserve before name. For provider or field blobs, this
+        /// should be 0. For event blobs, this is used for the tags field and will vary
+        /// from 1 to 4, depending on how large the tags field needs to be.
+        /// </param>
+        /// <param name="suffixSize">
+        /// Amount of space to reserve after name. For example, a provider blob with no
+        /// traits would reserve 0 extra bytes, but a provider blob with a single GroupId
+        /// field would reserve 19 extra bytes.
+        /// </param>
+        /// <param name="additionalSize">
+        /// Amount of additional data in another blob. This value will be counted in the
+        /// blob's length field, but will not be included in the returned byte[] object.
+        /// The complete blob would then be the concatenation of the returned byte[] object
+        /// with another byte[] object of length additionalSize.
+        /// </param>
+        /// <returns>
+        /// A byte[] object with the length and name fields set, with room reserved for
+        /// prefix and suffix. If additionalSize was 0, the byte[] object is a complete
+        /// blob. Otherwise, another byte[] of size additionalSize must be concatenated
+        /// with this one to form a complete blob.
+        /// </returns>
+        public static byte[] MetadataForString(
+            string name,
+            int prefixSize,
+            int suffixSize,
+            int additionalSize)
+        {
+            Statics.CheckName(name);
+            int metadataSize = Encoding.UTF8.GetByteCount(name) + 3 + prefixSize + suffixSize;
+            var metadata = new byte[metadataSize];
+            ushort totalSize = checked((ushort)(metadataSize + additionalSize));
+            metadata[0] = unchecked((byte)totalSize);
+            metadata[1] = unchecked((byte)(totalSize >> 8));
+            Encoding.UTF8.GetBytes(name, 0, name.Length, metadata, 2 + prefixSize);
+            return metadata;
+        }
+
+        /// <summary>
+        /// Serialize the low 28 bits of the tags value into the metadata stream,
+        /// starting at the index given by pos. Updates pos. Writes 1 to 4 bytes,
+        /// depending on the value of the tags variable. Usable for event tags and
+        /// field tags.
+        /// 
+        /// Note that 'metadata' can be null, in which case it only updates 'pos'.
+        /// This is useful for a two pass approach where you figure out how big to
+        /// make the array, and then you fill it in.   
+        /// </summary>
+        public static void EncodeTags(int tags, ref int pos, byte[] metadata)
+        {
+            // We transmit the low 28 bits of tags, high bits first, 7 bits at a time.
+            var tagsLeft = tags & 0xfffffff;
+            bool more;
+            do
+            {
+                byte current = (byte)((tagsLeft >> 21) & 0x7f);
+                more = (tagsLeft & 0x1fffff) != 0;
+                current |= (byte)(more ? 0x80 : 0x00);
+                tagsLeft = tagsLeft << 7;
+
+                if (metadata != null)
+                {
+                    metadata[pos] = current;
+                }
+                pos += 1;
+            }
+            while (more);
+        }
+
+        public static byte Combine(
+            int settingValue,
+            byte defaultValue)
+        {
+            unchecked
+            {
+                return (byte)settingValue == settingValue
+                    ? (byte)settingValue
+                    : defaultValue;
+            }
+        }
+
+        public static byte Combine(
+            int settingValue1,
+            int settingValue2,
+            byte defaultValue)
+        {
+            unchecked
+            {
+                return (byte)settingValue1 == settingValue1
+                    ? (byte)settingValue1
+                    : (byte)settingValue2 == settingValue2
+                    ? (byte)settingValue2
+                    : defaultValue;
+            }
+        }
+
+        public static int Combine(
+            int settingValue1,
+            int settingValue2)
+        {
+            unchecked
+            {
+                return (byte)settingValue1 == settingValue1
+                    ? settingValue1
+                    : settingValue2;
+            }
+        }
+
+        public static void CheckName(string name)
+        {
+            if (name != null && 0 <= name.IndexOf('\0'))
+            {
+                throw new ArgumentOutOfRangeException(nameof(name));
+            }
+        }
+
+        public static bool ShouldOverrideFieldName(string fieldName)
+        {
+            return (fieldName.Length <= 2 && fieldName[0] == '_');
+        }
+
+        public static TraceLoggingDataType MakeDataType(
+            TraceLoggingDataType baseType,
+            EventFieldFormat format)
+        {
+            return (TraceLoggingDataType)(((int)baseType & 0x1f) | ((int)format << 8));
+        }
+
+        /// <summary>
+        /// Adjusts the native type based on format.
+        /// - If format is default, return native.
+        /// - If format is recognized, return the canonical type for that format.
+        /// - Otherwise remove existing format from native and apply the requested format.
+        /// </summary>
+        public static TraceLoggingDataType Format8(
+            EventFieldFormat format,
+            TraceLoggingDataType native)
+        {
+            switch (format)
+            {
+                case EventFieldFormat.Default:
+                    return native;
+                case EventFieldFormat.String:
+                    return TraceLoggingDataType.Char8;
+                case EventFieldFormat.Boolean:
+                    return TraceLoggingDataType.Boolean8;
+                case EventFieldFormat.Hexadecimal:
+                    return TraceLoggingDataType.HexInt8;
+#if false 
+                case EventSourceFieldFormat.Signed:
+                    return TraceLoggingDataType.Int8;
+                case EventSourceFieldFormat.Unsigned:
+                    return TraceLoggingDataType.UInt8;
+#endif
+                default:
+                    return MakeDataType(native, format);
+            }
+        }
+
+        /// <summary>
+        /// Adjusts the native type based on format.
+        /// - If format is default, return native.
+        /// - If format is recognized, return the canonical type for that format.
+        /// - Otherwise remove existing format from native and apply the requested format.
+        /// </summary>
+        public static TraceLoggingDataType Format16(
+            EventFieldFormat format,
+            TraceLoggingDataType native)
+        {
+            switch (format)
+            {
+                case EventFieldFormat.Default:
+                    return native;
+                case EventFieldFormat.String:
+                    return TraceLoggingDataType.Char16;
+                case EventFieldFormat.Hexadecimal:
+                    return TraceLoggingDataType.HexInt16;
+#if false
+                case EventSourceFieldFormat.Port:
+                    return TraceLoggingDataType.Port;
+                case EventSourceFieldFormat.Signed:
+                    return TraceLoggingDataType.Int16;
+                case EventSourceFieldFormat.Unsigned:
+                    return TraceLoggingDataType.UInt16;
+#endif
+                default:
+                    return MakeDataType(native, format);
+            }
+        }
+
+        /// <summary>
+        /// Adjusts the native type based on format.
+        /// - If format is default, return native.
+        /// - If format is recognized, return the canonical type for that format.
+        /// - Otherwise remove existing format from native and apply the requested format.
+        /// </summary>
+        public static TraceLoggingDataType Format32(
+            EventFieldFormat format,
+            TraceLoggingDataType native)
+        {
+            switch (format)
+            {
+                case EventFieldFormat.Default:
+                    return native;
+                case EventFieldFormat.Boolean:
+                    return TraceLoggingDataType.Boolean32;
+                case EventFieldFormat.Hexadecimal:
+                    return TraceLoggingDataType.HexInt32;
+#if false 
+                case EventSourceFieldFormat.Ipv4Address:
+                    return TraceLoggingDataType.Ipv4Address;
+                case EventSourceFieldFormat.ProcessId:
+                    return TraceLoggingDataType.ProcessId;
+                case EventSourceFieldFormat.ThreadId:
+                    return TraceLoggingDataType.ThreadId;
+                case EventSourceFieldFormat.Win32Error:
+                    return TraceLoggingDataType.Win32Error;
+                case EventSourceFieldFormat.NTStatus:
+                    return TraceLoggingDataType.NTStatus;
+#endif
+                case EventFieldFormat.HResult:
+                    return TraceLoggingDataType.HResult;
+#if false 
+                case EventSourceFieldFormat.Signed:
+                    return TraceLoggingDataType.Int32;
+                case EventSourceFieldFormat.Unsigned:
+                    return TraceLoggingDataType.UInt32;
+#endif
+                default:
+                    return MakeDataType(native, format);
+            }
+        }
+
+        /// <summary>
+        /// Adjusts the native type based on format.
+        /// - If format is default, return native.
+        /// - If format is recognized, return the canonical type for that format.
+        /// - Otherwise remove existing format from native and apply the requested format.
+        /// </summary>
+        public static TraceLoggingDataType Format64(
+            EventFieldFormat format,
+            TraceLoggingDataType native)
+        {
+            switch (format)
+            {
+                case EventFieldFormat.Default:
+                    return native;
+                case EventFieldFormat.Hexadecimal:
+                    return TraceLoggingDataType.HexInt64;
+#if false 
+                case EventSourceFieldFormat.FileTime:
+                    return TraceLoggingDataType.FileTime;
+                case EventSourceFieldFormat.Signed:
+                    return TraceLoggingDataType.Int64;
+                case EventSourceFieldFormat.Unsigned:
+                    return TraceLoggingDataType.UInt64;
+#endif
+                default:
+                    return MakeDataType(native, format);
+            }
+        }
+
+        /// <summary>
+        /// Adjusts the native type based on format.
+        /// - If format is default, return native.
+        /// - If format is recognized, return the canonical type for that format.
+        /// - Otherwise remove existing format from native and apply the requested format.
+        /// </summary>
+        public static TraceLoggingDataType FormatPtr(
+            EventFieldFormat format,
+            TraceLoggingDataType native)
+        {
+            switch (format)
+            {
+                case EventFieldFormat.Default:
+                    return native;
+                case EventFieldFormat.Hexadecimal:
+                    return HexIntPtrType;
+#if false 
+                case EventSourceFieldFormat.Signed:
+                    return IntPtrType;
+                case EventSourceFieldFormat.Unsigned:
+                    return UIntPtrType;
+#endif
+                default:
+                    return MakeDataType(native, format);
+            }
+        }
+
+        #endregion
+
+        #region Reflection helpers
+
+        /*
+        All TraceLogging use of reflection APIs should go through wrappers here.
+        This helps with portability, and it also makes it easier to audit what
+        kinds of reflection operations are being done.
+        */
+
+        public static object CreateInstance(Type type, params object[] parameters)
+        {
+            return Activator.CreateInstance(type, parameters);
+        }
+
+        public static bool IsValueType(Type type)
+        {
+            bool result = type.IsValueType();
+            return result;
+        }
+
+        public static bool IsEnum(Type type)
+        {
+            bool result = type.IsEnum();
+            return result;
+        }
+
+        public static IEnumerable<PropertyInfo> GetProperties(Type type)
+        {
+            IEnumerable<PropertyInfo> result = type.GetProperties();
+            return result;
+        }
+
+        public static MethodInfo GetGetMethod(PropertyInfo propInfo)
+        {
+            MethodInfo result = propInfo.GetGetMethod();
+            return result;
+        }
+
+        public static MethodInfo GetDeclaredStaticMethod(Type declaringType, string name)
+        {
+            MethodInfo result;
+#if (ES_BUILD_PCL || ES_BUILD_PN)
+            result = declaringType.GetTypeInfo().GetDeclaredMethod(name);
+#else
+            result = declaringType.GetMethod(
+                name,
+                BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.NonPublic);
+#endif
+            return result;
+        }
+
+        public static bool HasCustomAttribute(
+            PropertyInfo propInfo,
+            Type attributeType)
+        {
+            bool result;
+#if (ES_BUILD_PCL || ES_BUILD_PN)
+            result = propInfo.IsDefined(attributeType);
+#else
+            var attributes = propInfo.GetCustomAttributes(
+                attributeType,
+                false);
+            result = attributes.Length != 0;
+#endif
+            return result;
+        }
+
+        public static AttributeType GetCustomAttribute<AttributeType>(PropertyInfo propInfo)
+            where AttributeType : Attribute
+        {
+            AttributeType result = null;
+#if (ES_BUILD_PCL || ES_BUILD_PN)
+            foreach (var attrib in propInfo.GetCustomAttributes<AttributeType>(false))
+            {
+                result = attrib;
+                break;
+            }
+#else
+            var attributes = propInfo.GetCustomAttributes(typeof(AttributeType), false);
+            if (attributes.Length != 0)
+            {
+                result = (AttributeType)attributes[0];
+            }
+#endif
+            return result;
+        }
+
+        public static AttributeType GetCustomAttribute<AttributeType>(Type type)
+            where AttributeType : Attribute
+        {
+            AttributeType result = null;
+#if (ES_BUILD_PCL || ES_BUILD_PN)
+            foreach (var attrib in type.GetTypeInfo().GetCustomAttributes<AttributeType>(false))
+            {
+                result = attrib;
+                break;
+            }
+#else
+            var attributes = type.GetCustomAttributes(typeof(AttributeType), false);
+            if (attributes.Length != 0)
+            {
+                result = (AttributeType)attributes[0];
+            }
+#endif
+            return result;
+        }
+
+        public static Type[] GetGenericArguments(Type type)
+        {
+            return type.GetGenericArguments();
+        }
+
+        public static Type FindEnumerableElementType(Type type)
+        {
+            Type elementType = null;
+
+            if (IsGenericMatch(type, typeof(IEnumerable<>)))
+            {
+                elementType = GetGenericArguments(type)[0];
+            }
+            else
+            {
+#if (ES_BUILD_PCL || ES_BUILD_PN)
+                var ifaceTypes = type.GetTypeInfo().ImplementedInterfaces;
+#else
+                var ifaceTypes = type.FindInterfaces(IsGenericMatch, typeof(IEnumerable<>));
+#endif
+
+                foreach (var ifaceType in ifaceTypes)
+                {
+#if (ES_BUILD_PCL || ES_BUILD_PN)
+                    if (!IsGenericMatch(ifaceType, typeof(IEnumerable<>)))
+                    {
+                        continue;
+                    }
+#endif
+
+                    if (elementType != null)
+                    {
+                        // ambiguous match. report no match at all.
+                        elementType = null;
+                        break;
+                    }
+
+                    elementType = GetGenericArguments(ifaceType)[0];
+                }
+            }
+
+            return elementType;
+        }
+
+        public static bool IsGenericMatch(Type type, object openType)
+        {
+            return type.IsGenericType() && type.GetGenericTypeDefinition() == (Type)openType;
+        }
+
+        public static Delegate CreateDelegate(Type delegateType, MethodInfo methodInfo)
+        {
+            Delegate result;
+#if (ES_BUILD_PCL || ES_BUILD_PN)
+            result = methodInfo.CreateDelegate(
+                delegateType);
+#else
+            result = Delegate.CreateDelegate(
+                delegateType,
+                methodInfo);
+#endif
+            return result;
+        }
+
+        public static TraceLoggingTypeInfo CreateDefaultTypeInfo(
+            Type dataType,
+            List<Type> recursionCheck)
+        {
+            TraceLoggingTypeInfo result;
+
+            if (recursionCheck.Contains(dataType))
+            {
+                throw new NotSupportedException(Resources.GetResourceString("EventSource_RecursiveTypeDefinition"));
+            }
+
+            recursionCheck.Add(dataType);
+
+            var eventAttrib = Statics.GetCustomAttribute<EventDataAttribute>(dataType);
+            if (eventAttrib != null ||
+                Statics.GetCustomAttribute<CompilerGeneratedAttribute>(dataType) != null ||
+                IsGenericMatch(dataType, typeof(KeyValuePair<,>)))
+            {
+                var analysis = new TypeAnalysis(dataType, eventAttrib, recursionCheck);
+                result = new InvokeTypeInfo(dataType, analysis);
+            }
+            else if (dataType.IsArray)
+            {
+                var elementType = dataType.GetElementType();
+                if (elementType == typeof(Boolean))
+                {
+                    result = ScalarArrayTypeInfo.Boolean();
+                }
+                else if (elementType == typeof(Byte))
+                {
+                    result = ScalarArrayTypeInfo.Byte();
+                }
+                else if (elementType == typeof(SByte))
+                {
+                    result = ScalarArrayTypeInfo.SByte();
+                }
+                else if (elementType == typeof(Int16))
+                {
+                    result = ScalarArrayTypeInfo.Int16();
+                }
+                else if (elementType == typeof(UInt16))
+                {
+                    result = ScalarArrayTypeInfo.UInt16();
+                }
+                else if (elementType == typeof(Int32))
+                {
+                    result = ScalarArrayTypeInfo.Int32();
+                }
+                else if (elementType == typeof(UInt32))
+                {
+                    result = ScalarArrayTypeInfo.UInt32();
+                }
+                else if (elementType == typeof(Int64))
+                {
+                    result = ScalarArrayTypeInfo.Int64();
+                }
+                else if (elementType == typeof(UInt64))
+                {
+                    result = ScalarArrayTypeInfo.UInt64();
+                }
+                else if (elementType == typeof(Char))
+                {
+                    result = ScalarArrayTypeInfo.Char();
+                }
+                else if (elementType == typeof(Double))
+                {
+                    result = ScalarArrayTypeInfo.Double();
+                }
+                else if (elementType == typeof(Single))
+                {
+                    result = ScalarArrayTypeInfo.Single();
+                }
+                else if (elementType == typeof(IntPtr))
+                {
+                    result = ScalarArrayTypeInfo.IntPtr();
+                }
+                else if (elementType == typeof(UIntPtr))
+                {
+                    result = ScalarArrayTypeInfo.UIntPtr();
+                }
+                else if (elementType == typeof(Guid))
+                {
+                    result = ScalarArrayTypeInfo.Guid();
+                }
+                else
+                {
+                    result = new ArrayTypeInfo(dataType, TraceLoggingTypeInfo.GetInstance(elementType, recursionCheck));
+                }
+            }
+            else
+            {
+                if (Statics.IsEnum(dataType))
+                    dataType = Enum.GetUnderlyingType(dataType);
+
+                if (dataType == typeof(String))
+                {
+                    result = new StringTypeInfo();
+                }
+                else if (dataType == typeof(Boolean))
+                {
+                    result = ScalarTypeInfo.Boolean();
+                }
+                else if (dataType == typeof(Byte))
+                {
+                    result = ScalarTypeInfo.Byte();
+                }
+                else if (dataType == typeof(SByte))
+                {
+                    result = ScalarTypeInfo.SByte();
+                }
+                else if (dataType == typeof(Int16))
+                {
+                    result = ScalarTypeInfo.Int16();
+                }
+                else if (dataType == typeof(UInt16))
+                {
+                    result = ScalarTypeInfo.UInt16();
+                }
+                else if (dataType == typeof(Int32))
+                {
+                    result = ScalarTypeInfo.Int32();
+                }
+                else if (dataType == typeof(UInt32))
+                {
+                    result = ScalarTypeInfo.UInt32();
+                }
+                else if (dataType == typeof(Int64))
+                {
+                    result = ScalarTypeInfo.Int64();
+                }
+                else if (dataType == typeof(UInt64))
+                {
+                    result = ScalarTypeInfo.UInt64();
+                }
+                else if (dataType == typeof(Char))
+                {
+                    result = ScalarTypeInfo.Char();
+                }
+                else if (dataType == typeof(Double))
+                {
+                    result = ScalarTypeInfo.Double();
+                }
+                else if (dataType == typeof(Single))
+                {
+                    result = ScalarTypeInfo.Single();
+                }
+                else if (dataType == typeof(DateTime))
+                {
+                    result = new DateTimeTypeInfo();
+                }
+                else if (dataType == typeof(Decimal))
+                {
+                    result = new DecimalTypeInfo();
+                }
+                else if (dataType == typeof(IntPtr))
+                {
+                    result = ScalarTypeInfo.IntPtr();
+                }
+                else if (dataType == typeof(UIntPtr))
+                {
+                    result = ScalarTypeInfo.UIntPtr();
+                }
+                else if (dataType == typeof(Guid))
+                {
+                    result = ScalarTypeInfo.Guid();
+                }
+                else if (dataType == typeof(TimeSpan))
+                {
+                    result = new TimeSpanTypeInfo();
+                }
+                else if (dataType == typeof(DateTimeOffset))
+                {
+                    result = new DateTimeOffsetTypeInfo();
+                }
+                else if (dataType == typeof(EmptyStruct))
+                {
+                    result = new NullTypeInfo();
+                }
+                else if (IsGenericMatch(dataType, typeof(Nullable<>)))
+                {
+                    result = new NullableTypeInfo(dataType, recursionCheck);
+                }
+                else
+                {
+                    var elementType = FindEnumerableElementType(dataType);
+                    if (elementType != null)
+                    {
+                        result = new EnumerableTypeInfo(dataType, TraceLoggingTypeInfo.GetInstance(elementType, recursionCheck));
+                    }
+                    else
+                    {
+                        throw new ArgumentException(Resources.GetResourceString("EventSource_NonCompliantTypeError", dataType.Name));
+                    }
+                }
+            }
+
+            return result;
+        }
+
+        #endregion
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataCollector.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataCollector.cs
new file mode 100644 (file)
index 0000000..04a047f
--- /dev/null
@@ -0,0 +1,104 @@
+// 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.Security;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: Used when implementing a custom TraceLoggingTypeInfo.
+    /// The instance of this type is provided to the TypeInfo.WriteData method.
+    /// All operations are forwarded to the current thread's DataCollector.
+    /// Note that this abstraction would allow us to expose the custom
+    /// serialization system to partially-trusted code. If we end up not
+    /// making custom serialization public, or if we only expose it to
+    /// full-trust code, this abstraction is unnecessary (though it probably
+    /// doesn't hurt anything).
+    /// </summary>
+    internal unsafe class TraceLoggingDataCollector
+    {
+        internal static readonly TraceLoggingDataCollector Instance = new TraceLoggingDataCollector();
+
+        private TraceLoggingDataCollector()
+        {
+            return;
+        }
+
+        /// <summary>
+        /// Marks the start of a non-blittable array or enumerable.
+        /// </summary>
+        /// <returns>Bookmark to be passed to EndBufferedArray.</returns>
+        public int BeginBufferedArray()
+        {
+            return DataCollector.ThreadInstance.BeginBufferedArray();
+        }
+
+        /// <summary>
+        /// Marks the end of a non-blittable array or enumerable.
+        /// </summary>
+        /// <param name="bookmark">The value returned by BeginBufferedArray.</param>
+        /// <param name="count">The number of items in the array.</param>
+        public void EndBufferedArray(int bookmark, int count)
+        {
+            DataCollector.ThreadInstance.EndBufferedArray(bookmark, count);
+        }
+
+        /// <summary>
+        /// Adds the start of a group to the event.
+        /// This has no effect on the event payload, but is provided to allow
+        /// WriteMetadata and WriteData implementations to have similar
+        /// sequences of calls, allowing for easier verification of correctness.
+        /// </summary>
+        public TraceLoggingDataCollector AddGroup()
+        {
+            return this;
+        }
+
+        public void AddScalar(PropertyValue value)
+        {
+            var scalar = value.ScalarValue;
+            DataCollector.ThreadInstance.AddScalar(&scalar, value.ScalarLength);
+        }
+
+        /// <summary>
+        /// Adds an Int64 value to the event payload.
+        /// </summary>
+        /// <param name="value">Value to be added.</param>
+        public void AddScalar(long value)
+        {
+            DataCollector.ThreadInstance.AddScalar(&value, sizeof(long));
+        }
+
+        /// <summary>
+        /// Adds a Double value to the event payload.
+        /// </summary>
+        /// <param name="value">Value to be added.</param>
+        public void AddScalar(double value)
+        {
+            DataCollector.ThreadInstance.AddScalar(&value, sizeof(double));
+        }
+
+        /// <summary>
+        /// Adds a counted String value to the event payload.
+        /// </summary>
+        /// <param name="value">
+        /// Value to be added. A null value is treated as a zero-length string.
+        /// </param>
+        public void AddBinary(string value)
+        {
+            DataCollector.ThreadInstance.AddBinary(value, value == null ? 0 : value.Length * 2);
+        }
+
+        public void AddArray(PropertyValue value, int elementSize)
+        {
+            Array array = (Array)value.ReferenceValue;
+            DataCollector.ThreadInstance.AddArray(array, array == null ? 0 : array.Length, elementSize);
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataType.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataType.cs
new file mode 100644 (file)
index 0000000..529948d
--- /dev/null
@@ -0,0 +1,349 @@
+// 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;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: Used when implementing a custom TraceLoggingTypeInfo.
+    /// These are passed to metadataCollector.Add to specify the low-level
+    /// type of a field in the event payload. Note that a "formatted"
+    /// TraceLoggingDataType consists of a core TraceLoggingDataType value
+    /// (a TraceLoggingDataType with a value less than 32) plus an OutType.
+    /// Any combination of TraceLoggingDataType + OutType is valid, but not
+    /// all are useful. In particular, combinations not explicitly listed
+    /// below are unlikely to be recognized by decoders, and will typically
+    /// be decoded as the corresponding core type (i.e. the decoder will
+    /// mask off any unrecognized OutType value).
+    /// </summary>
+    internal enum TraceLoggingDataType
+    {
+        /// <summary>
+        /// Core type.
+        /// Data type with no value (0-length payload).
+        /// NOTE: arrays of Nil are illegal.
+        /// NOTE: a fixed-length array of Nil is interpreted by the decoder as
+        /// a struct (obsolete but retained for backwards-compatibility).
+        /// </summary>
+        Nil = 0,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes null-terminated Char16 string.
+        /// Decoding treats as UTF-16LE string.
+        /// </summary>
+        Utf16String = 1,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes null-terminated Char8 string.
+        /// Decoding treats as MBCS string.
+        /// </summary>
+        MbcsString = 2,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 8-bit value.
+        /// Decoding treats as signed integer.
+        /// </summary>
+        Int8 = 3,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 8-bit value.
+        /// Decoding treats as unsigned integer.
+        /// </summary>
+        UInt8 = 4,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 16-bit value.
+        /// Decoding treats as signed integer.
+        /// </summary>
+        Int16 = 5,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 16-bit value.
+        /// Decoding treats as unsigned integer.
+        /// </summary>
+        UInt16 = 6,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 32-bit value.
+        /// Decoding treats as signed integer.
+        /// </summary>
+        Int32 = 7,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 32-bit value.
+        /// Decoding treats as unsigned integer.
+        /// </summary>
+        UInt32 = 8,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 64-bit value.
+        /// Decoding treats as signed integer.
+        /// </summary>
+        Int64 = 9,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 64-bit value.
+        /// Decoding treats as unsigned integer.
+        /// </summary>
+        UInt64 = 10,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 32-bit value.
+        /// Decoding treats as Float.
+        /// </summary>
+        Float = 11,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 64-bit value.
+        /// Decoding treats as Double.
+        /// </summary>
+        Double = 12,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 32-bit value.
+        /// Decoding treats as Boolean.
+        /// </summary>
+        Boolean32 = 13,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 16-bit bytecount followed by binary data.
+        /// Decoding treats as binary data.
+        /// </summary>
+        Binary = 14,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 16-byte value.
+        /// Decoding treats as GUID.
+        /// </summary>
+        Guid = 15,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 64-bit value.
+        /// Decoding treats as FILETIME.
+        /// </summary>
+        FileTime = 17,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 16-byte value.
+        /// Decoding treats as SYSTEMTIME.
+        /// </summary>
+        SystemTime = 18,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 32-bit value.
+        /// Decoding treats as hexadecimal unsigned integer.
+        /// </summary>
+        HexInt32 = 20,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 64-bit value.
+        /// Decoding treats as hexadecimal unsigned integer.
+        /// </summary>
+        HexInt64 = 21,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 16-bit bytecount followed by Char16 data.
+        /// Decoding treats as UTF-16LE string.
+        /// </summary>
+        CountedUtf16String = 22,
+
+        /// <summary>
+        /// Core type.
+        /// Encoding assumes 16-bit bytecount followed by Char8 data.
+        /// Decoding treats as MBCS string.
+        /// </summary>
+        CountedMbcsString = 23,
+
+        /// <summary>
+        /// Core type.
+        /// Special case: Struct indicates that this field plus the the
+        /// subsequent N logical fields are to be considered as one logical
+        /// field (i.e. a nested structure). The OutType is used to encode N.
+        /// The maximum value for N is 127. This field has no payload by
+        /// itself, but logically contains the payload of the following N
+        /// fields. It is legal to have an array of Struct.
+        /// </summary>
+        Struct = 24,
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 16-bit value.
+        /// Decoding treats as UTF-16LE character.
+        /// </summary>
+        Char16 = UInt16 + (EventFieldFormat.String << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 8-bit value.
+        /// Decoding treats as character.
+        /// </summary>
+        Char8 = UInt8 + (EventFieldFormat.String << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 8-bit value.
+        /// Decoding treats as Boolean.
+        /// </summary>
+        Boolean8 = UInt8 + (EventFieldFormat.Boolean << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 8-bit value.
+        /// Decoding treats as hexadecimal unsigned integer.
+        /// </summary>
+        HexInt8 = UInt8 + (EventFieldFormat.Hexadecimal << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 16-bit value.
+        /// Decoding treats as hexadecimal unsigned integer.
+        /// </summary>
+        HexInt16 = UInt16 + (EventFieldFormat.Hexadecimal << 8),
+
+#if false 
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 32-bit value.
+        /// Decoding treats as process identifier.
+        /// </summary>
+        ProcessId = UInt32 + (EventSourceFieldFormat.ProcessId << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 32-bit value.
+        /// Decoding treats as thread identifier.
+        /// </summary>
+        ThreadId = UInt32 + (EventSourceFieldFormat.ThreadId << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 16-bit value.
+        /// Decoding treats as IP port.
+        /// </summary>
+        Port = UInt16 + (EventSourceFieldFormat.Port << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 32-bit value.
+        /// Decoding treats as IPv4 address.
+        /// </summary>
+        Ipv4Address = UInt32 + (EventSourceFieldFormat.Ipv4Address << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 16-bit bytecount followed by binary data.
+        /// Decoding treats as IPv6 address.
+        /// </summary>
+        Ipv6Address = Binary + (EventSourceFieldFormat.Ipv6Address << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 16-bit bytecount followed by binary data.
+        /// Decoding treats as SOCKADDR.
+        /// </summary>
+        SocketAddress = Binary + (EventSourceFieldFormat.SocketAddress << 8),
+#endif
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes null-terminated Char16 string.
+        /// Decoding treats as UTF-16LE XML string.
+        /// </summary>
+        Utf16Xml = Utf16String + (EventFieldFormat.Xml << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes null-terminated Char8 string.
+        /// Decoding treats as MBCS XML string.
+        /// </summary>
+        MbcsXml = MbcsString + (EventFieldFormat.Xml << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 16-bit bytecount followed by Char16 data.
+        /// Decoding treats as UTF-16LE XML.
+        /// </summary>
+        CountedUtf16Xml = CountedUtf16String + (EventFieldFormat.Xml << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 16-bit bytecount followed by Char8 data.
+        /// Decoding treats as MBCS XML.
+        /// </summary>
+        CountedMbcsXml = CountedMbcsString + (EventFieldFormat.Xml << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes null-terminated Char16 string.
+        /// Decoding treats as UTF-16LE JSON string.
+        /// </summary>
+        Utf16Json = Utf16String + (EventFieldFormat.Json << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes null-terminated Char8 string.
+        /// Decoding treats as MBCS JSON string.
+        /// </summary>
+        MbcsJson = MbcsString + (EventFieldFormat.Json << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 16-bit bytecount followed by Char16 data.
+        /// Decoding treats as UTF-16LE JSON.
+        /// </summary>
+        CountedUtf16Json = CountedUtf16String + (EventFieldFormat.Json << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 16-bit bytecount followed by Char8 data.
+        /// Decoding treats as MBCS JSON.
+        /// </summary>
+        CountedMbcsJson = CountedMbcsString + (EventFieldFormat.Json << 8),
+#if false 
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 32-bit value.
+        /// Decoding treats as Win32 error.
+        /// </summary>
+        Win32Error = UInt32 + (EventSourceFieldFormat.Win32Error << 8),
+
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 32-bit value.
+        /// Decoding treats as NTSTATUS.
+        /// </summary>
+        NTStatus = UInt32 + (EventSourceFieldFormat.NTStatus << 8),
+#endif
+        /// <summary>
+        /// Formatted type.
+        /// Encoding assumes 32-bit value.
+        /// Decoding treats as HRESULT.
+        /// </summary>
+        HResult = Int32 + (EventFieldFormat.HResult << 8)
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs
new file mode 100644 (file)
index 0000000..8c875fc
--- /dev/null
@@ -0,0 +1,890 @@
+// 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.
+
+// This program uses code hyperlinks available as part of the HyperAddin Visual Studio plug-in.
+// It is available from http://www.codeplex.com/hyperAddin 
+
+#if !PLATFORM_UNIX
+#define FEATURE_MANAGED_ETW
+
+#if !ES_BUILD_STANDALONE
+#define FEATURE_ACTIVITYSAMPLING
+#endif
+#endif // PLATFORM_UNIX
+
+#if ES_BUILD_STANDALONE
+#define FEATURE_MANAGED_ETW_CHANNELS
+// #define FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
+#endif
+
+#if ES_BUILD_STANDALONE
+using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
+using EventDescriptor = Microsoft.Diagnostics.Tracing.EventDescriptor;
+#endif
+
+using System;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Collections.ObjectModel;
+
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+using System.Collections.Generic;
+using System.Text;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+using System.Collections.Generic;
+using System.Text;
+#endif
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    public partial class EventSource
+    {
+#if FEATURE_MANAGED_ETW
+        private byte[] providerMetadata;
+#endif
+
+        /// <summary>
+        /// Construct an EventSource with a given name for non-contract based events (e.g. those using the Write() API).
+        /// </summary>
+        /// <param name="eventSourceName">
+        /// The name of the event source. Must not be null.
+        /// </param>
+        public EventSource(
+            string eventSourceName)
+            : this(eventSourceName, EventSourceSettings.EtwSelfDescribingEventFormat)
+        { }
+
+        /// <summary>
+        /// Construct an EventSource with a given name for non-contract based events (e.g. those using the Write() API).
+        /// </summary>
+        /// <param name="eventSourceName">
+        /// The name of the event source. Must not be null.
+        /// </param>
+        /// <param name="config">
+        /// Configuration options for the EventSource as a whole. 
+        /// </param>
+        public EventSource(
+            string eventSourceName,
+            EventSourceSettings config)
+            : this(eventSourceName, config, null) { }
+
+        /// <summary>
+        /// Construct an EventSource with a given name for non-contract based events (e.g. those using the Write() API).
+        /// 
+        /// Also specify a list of key-value pairs called traits (you must pass an even number of strings).   
+        /// The first string is the key and the second is the value.   These are not interpreted by EventSource
+        /// itself but may be interprated the listeners.  Can be fetched with GetTrait(string).   
+        /// </summary>
+        /// <param name="eventSourceName">
+        /// The name of the event source. Must not be null.
+        /// </param>
+        /// <param name="config">
+        /// Configuration options for the EventSource as a whole. 
+        /// </param>
+        /// <param name="traits">A collection of key-value strings (must be an even number).</param>
+        public EventSource(
+            string eventSourceName,
+            EventSourceSettings config,
+            params string[] traits)
+            : this(
+                eventSourceName == null ? new Guid() : GenerateGuidFromName(eventSourceName.ToUpperInvariant()),
+                eventSourceName,
+                config, traits)
+        {
+            if (eventSourceName == null)
+            {
+                throw new ArgumentNullException(nameof(eventSourceName));
+            }
+            Contract.EndContractBlock();
+        }
+
+        /// <summary>
+        /// Writes an event with no fields and default options.
+        /// (Native API: EventWriteTransfer)
+        /// </summary>
+        /// <param name="eventName">The name of the event. Must not be null.</param>
+        public unsafe void Write(string eventName)
+        {
+            if (eventName == null)
+            {
+                throw new ArgumentNullException(nameof(eventName));
+            }
+
+            Contract.EndContractBlock();
+
+            if (!this.IsEnabled())
+            {
+                return;
+            }
+
+            var options = new EventSourceOptions();
+            this.WriteImpl(eventName, ref options, null, null, null, SimpleEventTypes<EmptyStruct>.Instance);
+        }
+
+        /// <summary>
+        /// Writes an event with no fields.
+        /// (Native API: EventWriteTransfer)
+        /// </summary>
+        /// <param name="eventName">The name of the event. Must not be null.</param>
+        /// <param name="options">
+        /// Options for the event, such as the level, keywords, and opcode. Unset
+        /// options will be set to default values.
+        /// </param>
+        public unsafe void Write(string eventName, EventSourceOptions options)
+        {
+            if (eventName == null)
+            {
+                throw new ArgumentNullException(nameof(eventName));
+            }
+
+            Contract.EndContractBlock();
+
+            if (!this.IsEnabled())
+            {
+                return;
+            }
+
+            this.WriteImpl(eventName, ref options, null, null, null, SimpleEventTypes<EmptyStruct>.Instance);
+        }
+
+        /// <summary>
+        /// Writes an event.
+        /// (Native API: EventWriteTransfer)
+        /// </summary>
+        /// <typeparam name="T">
+        /// The type that defines the event and its payload. This must be an
+        /// anonymous type or a type with an [EventData] attribute.
+        /// </typeparam>
+        /// <param name="eventName">
+        /// The name for the event. If null, the event name is automatically
+        /// determined based on T, either from the Name property of T's EventData
+        /// attribute or from typeof(T).Name.
+        /// </param>
+        /// <param name="data">
+        /// The object containing the event payload data. The type T must be
+        /// an anonymous type or a type with an [EventData] attribute. The
+        /// public instance properties of data will be written recursively to
+        /// create the fields of the event.
+        /// </param>
+        public unsafe void Write<T>(
+            string eventName,
+            T data)
+        {
+            if (!this.IsEnabled())
+            {
+                return;
+            }
+
+            var options = new EventSourceOptions();
+            this.WriteImpl(eventName, ref options, data, null, null, SimpleEventTypes<T>.Instance);
+        }
+
+        /// <summary>
+        /// Writes an event.
+        /// (Native API: EventWriteTransfer)
+        /// </summary>
+        /// <typeparam name="T">
+        /// The type that defines the event and its payload. This must be an
+        /// anonymous type or a type with an [EventData] attribute.
+        /// </typeparam>
+        /// <param name="eventName">
+        /// The name for the event. If null, the event name is automatically
+        /// determined based on T, either from the Name property of T's EventData
+        /// attribute or from typeof(T).Name.
+        /// </param>
+        /// <param name="options">
+        /// Options for the event, such as the level, keywords, and opcode. Unset
+        /// options will be set to default values.
+        /// </param>
+        /// <param name="data">
+        /// The object containing the event payload data. The type T must be
+        /// an anonymous type or a type with an [EventData] attribute. The
+        /// public instance properties of data will be written recursively to
+        /// create the fields of the event.
+        /// </param>
+        public unsafe void Write<T>(
+            string eventName,
+            EventSourceOptions options,
+            T data)
+        {
+            if (!this.IsEnabled())
+            {
+                return;
+            }
+
+            this.WriteImpl(eventName, ref options, data, null, null, SimpleEventTypes<T>.Instance);
+        }
+
+        /// <summary>
+        /// Writes an event.
+        /// This overload is for use with extension methods that wish to efficiently
+        /// forward the options or data parameter without performing an extra copy.
+        /// (Native API: EventWriteTransfer)
+        /// </summary>
+        /// <typeparam name="T">
+        /// The type that defines the event and its payload. This must be an
+        /// anonymous type or a type with an [EventData] attribute.
+        /// </typeparam>
+        /// <param name="eventName">
+        /// The name for the event. If null, the event name is automatically
+        /// determined based on T, either from the Name property of T's EventData
+        /// attribute or from typeof(T).Name.
+        /// </param>
+        /// <param name="options">
+        /// Options for the event, such as the level, keywords, and opcode. Unset
+        /// options will be set to default values.
+        /// </param>
+        /// <param name="data">
+        /// The object containing the event payload data. The type T must be
+        /// an anonymous type or a type with an [EventData] attribute. The
+        /// public instance properties of data will be written recursively to
+        /// create the fields of the event.
+        /// </param>
+        public unsafe void Write<T>(
+            string eventName,
+            ref EventSourceOptions options,
+            ref T data)
+        {
+            if (!this.IsEnabled())
+            {
+                return;
+            }
+
+            this.WriteImpl(eventName, ref options, data, null, null, SimpleEventTypes<T>.Instance);
+        }
+
+        /// <summary>
+        /// Writes an event.
+        /// This overload is meant for clients that need to manipuate the activityId
+        /// and related ActivityId for the event.  
+        /// </summary>
+        /// <typeparam name="T">
+        /// The type that defines the event and its payload. This must be an
+        /// anonymous type or a type with an [EventData] attribute.
+        /// </typeparam>
+        /// <param name="eventName">
+        /// The name for the event. If null, the event name is automatically
+        /// determined based on T, either from the Name property of T's EventData
+        /// attribute or from typeof(T).Name.
+        /// </param>
+        /// <param name="options">
+        /// Options for the event, such as the level, keywords, and opcode. Unset
+        /// options will be set to default values.
+        /// </param>
+        /// <param name="activityId">
+        /// The GUID of the activity associated with this event.
+        /// </param>
+        /// <param name="relatedActivityId">
+        /// The GUID of another activity that is related to this activity, or Guid.Empty
+        /// if there is no related activity. Most commonly, the Start operation of a
+        /// new activity specifies a parent activity as its related activity.
+        /// </param>
+        /// <param name="data">
+        /// The object containing the event payload data. The type T must be
+        /// an anonymous type or a type with an [EventData] attribute. The
+        /// public instance properties of data will be written recursively to
+        /// create the fields of the event.
+        /// </param>
+        public unsafe void Write<T>(
+            string eventName,
+            ref EventSourceOptions options,
+            ref Guid activityId,
+            ref Guid relatedActivityId,
+            ref T data)
+        {
+            if (!this.IsEnabled())
+            {
+                return;
+            }
+
+            fixed (Guid* pActivity = &activityId, pRelated = &relatedActivityId)
+            {
+                this.WriteImpl(
+                    eventName,
+                    ref options,
+                    data,
+                    pActivity,
+                    relatedActivityId == Guid.Empty ? null : pRelated,
+                    SimpleEventTypes<T>.Instance);
+            }
+        }
+
+        /// <summary>
+        /// Writes an extended event, where the values of the event are the
+        /// combined properties of any number of values. This method is
+        /// intended for use in advanced logging scenarios that support a
+        /// dynamic set of event context providers.
+        /// This method does a quick check on whether this event is enabled.
+        /// </summary>
+        /// <param name="eventName">
+        /// The name for the event. If null, the name from eventTypes is used.
+        /// (Note that providing the event name via the name parameter is slightly
+        /// less efficient than using the name from eventTypes.)
+        /// </param>
+        /// <param name="options">
+        /// Optional overrides for the event, such as the level, keyword, opcode,
+        /// activityId, and relatedActivityId. Any settings not specified by options
+        /// are obtained from eventTypes.
+        /// </param>
+        /// <param name="eventTypes">
+        /// Information about the event and the types of the values in the event.
+        /// Must not be null. Note that the eventTypes object should be created once and
+        /// saved. It should not be recreated for each event.
+        /// </param>
+        /// <param name="activityID">
+        /// A pointer to the activity ID GUID to log 
+        /// </param>
+        /// <param name="childActivityID">
+        /// A pointer to the child activity ID to log (can be null) </param>
+        /// <param name="values">
+        /// The values to include in the event. Must not be null. The number and types of
+        /// the values must match the number and types of the fields described by the
+        /// eventTypes parameter.
+        /// </param>
+        private unsafe void WriteMultiMerge(
+            string eventName,
+            ref EventSourceOptions options,
+            TraceLoggingEventTypes eventTypes,
+             Guid* activityID,
+             Guid* childActivityID,
+            params object[] values)
+        {
+            if (!this.IsEnabled())
+            {
+                return;
+            }
+            byte level = (options.valuesSet & EventSourceOptions.levelSet) != 0
+                ? options.level
+                : eventTypes.level;
+            EventKeywords keywords = (options.valuesSet & EventSourceOptions.keywordsSet) != 0
+                ? options.keywords
+                : eventTypes.keywords;
+
+            if (this.IsEnabled((EventLevel)level, keywords))
+            {
+                WriteMultiMergeInner(eventName, ref options, eventTypes, activityID, childActivityID, values);
+            }
+        }
+
+        /// <summary>
+        /// Writes an extended event, where the values of the event are the
+        /// combined properties of any number of values. This method is
+        /// intended for use in advanced logging scenarios that support a
+        /// dynamic set of event context providers.
+        /// Attention: This API does not check whether the event is enabled or not. 
+        /// Please use WriteMultiMerge to avoid spending CPU cycles for events that are 
+        /// not enabled.
+        /// </summary>
+        /// <param name="eventName">
+        /// The name for the event. If null, the name from eventTypes is used.
+        /// (Note that providing the event name via the name parameter is slightly
+        /// less efficient than using the name from eventTypes.)
+        /// </param>
+        /// <param name="options">
+        /// Optional overrides for the event, such as the level, keyword, opcode,
+        /// activityId, and relatedActivityId. Any settings not specified by options
+        /// are obtained from eventTypes.
+        /// </param>
+        /// <param name="eventTypes">
+        /// Information about the event and the types of the values in the event.
+        /// Must not be null. Note that the eventTypes object should be created once and
+        /// saved. It should not be recreated for each event.
+        /// </param>
+        /// <param name="activityID">
+        /// A pointer to the activity ID GUID to log 
+        /// </param>
+        /// <param name="childActivityID">
+        /// A pointer to the child activity ID to log (can be null)
+        /// </param>
+        /// <param name="values">
+        /// The values to include in the event. Must not be null. The number and types of
+        /// the values must match the number and types of the fields described by the
+        /// eventTypes parameter.
+        /// </param>
+        private unsafe void WriteMultiMergeInner(
+            string eventName,
+            ref EventSourceOptions options,
+            TraceLoggingEventTypes eventTypes,
+            Guid* activityID,
+            Guid* childActivityID,
+            params object[] values)
+        {
+#if FEATURE_MANAGED_ETW
+            int identity = 0;
+            byte level = (options.valuesSet & EventSourceOptions.levelSet) != 0
+                ? options.level
+                : eventTypes.level;
+            byte opcode = (options.valuesSet & EventSourceOptions.opcodeSet) != 0
+                ? options.opcode
+                : eventTypes.opcode;
+            EventTags tags = (options.valuesSet & EventSourceOptions.tagsSet) != 0
+                ? options.tags
+                : eventTypes.Tags;
+            EventKeywords keywords = (options.valuesSet & EventSourceOptions.keywordsSet) != 0
+                ? options.keywords
+                : eventTypes.keywords;
+
+            var nameInfo = eventTypes.GetNameInfo(eventName ?? eventTypes.Name, tags);
+            if (nameInfo == null)
+            {
+                return;
+            }
+            identity = nameInfo.identity;
+            EventDescriptor descriptor = new EventDescriptor(identity, level, opcode, (long)keywords);
+
+            var pinCount = eventTypes.pinCount;
+            var scratch = stackalloc byte[eventTypes.scratchSize];
+            var descriptors = stackalloc EventData[eventTypes.dataCount + 3];
+            var pins = stackalloc GCHandle[pinCount];
+
+            fixed (byte*
+                pMetadata0 = this.providerMetadata,
+                pMetadata1 = nameInfo.nameMetadata,
+                pMetadata2 = eventTypes.typeMetadata)
+            {
+                descriptors[0].SetMetadata(pMetadata0, this.providerMetadata.Length, 2);
+                descriptors[1].SetMetadata(pMetadata1, nameInfo.nameMetadata.Length, 1);
+                descriptors[2].SetMetadata(pMetadata2, eventTypes.typeMetadata.Length, 1);
+
+#if (!ES_BUILD_PCL && !ES_BUILD_PN)
+                System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
+#endif
+                try
+                {
+                    DataCollector.ThreadInstance.Enable(
+                        scratch,
+                        eventTypes.scratchSize,
+                        descriptors + 3,
+                        eventTypes.dataCount,
+                        pins,
+                        pinCount);
+
+                    for (int i = 0; i < eventTypes.typeInfos.Length; i++)
+                    {
+                        var info = eventTypes.typeInfos[i];
+                        info.WriteData(TraceLoggingDataCollector.Instance, info.PropertyValueFactory(values[i]));
+                    }
+
+                    this.WriteEventRaw(
+                        eventName,
+                        ref descriptor,
+                        activityID,
+                        childActivityID,
+                        (int)(DataCollector.ThreadInstance.Finish() - descriptors),
+                        (IntPtr)descriptors);
+                }
+                finally
+                {
+                    this.WriteCleanup(pins, pinCount);
+                }
+            }
+#endif // FEATURE_MANAGED_ETW
+        }
+
+        /// <summary>
+        /// Writes an extended event, where the values of the event have already
+        /// been serialized in "data".
+        /// </summary>
+        /// <param name="eventName">
+        /// The name for the event. If null, the name from eventTypes is used.
+        /// (Note that providing the event name via the name parameter is slightly
+        /// less efficient than using the name from eventTypes.)
+        /// </param>
+        /// <param name="options">
+        /// Optional overrides for the event, such as the level, keyword, opcode,
+        /// activityId, and relatedActivityId. Any settings not specified by options
+        /// are obtained from eventTypes.
+        /// </param>
+        /// <param name="eventTypes">
+        /// Information about the event and the types of the values in the event.
+        /// Must not be null. Note that the eventTypes object should be created once and
+        /// saved. It should not be recreated for each event.
+        /// </param>
+        /// <param name="activityID">
+        /// A pointer to the activity ID GUID to log 
+        /// </param>
+        /// <param name="childActivityID">
+        /// A pointer to the child activity ID to log (can be null)
+        /// </param> 
+        /// <param name="data">
+        /// The previously serialized values to include in the event. Must not be null.
+        /// The number and types of the values must match the number and types of the 
+        /// fields described by the eventTypes parameter.
+        /// </param>
+        internal unsafe void WriteMultiMerge(
+            string eventName,
+            ref EventSourceOptions options,
+            TraceLoggingEventTypes eventTypes,
+            Guid* activityID,
+            Guid* childActivityID,
+            EventData* data)
+        {
+#if FEATURE_MANAGED_ETW
+            if (!this.IsEnabled())
+            {
+                return;
+            }
+
+            fixed (EventSourceOptions* pOptions = &options)
+            {
+                EventDescriptor descriptor;
+                var nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out descriptor);
+                if (nameInfo == null)
+                {
+                    return;
+                }
+
+                // We make a descriptor for each EventData, and because we morph strings to counted strings
+                // we may have 2 for each arg, so we allocate enough for this.  
+                var descriptors = stackalloc EventData[eventTypes.dataCount + eventTypes.typeInfos.Length * 2 + 3];
+
+                fixed (byte*
+                    pMetadata0 = this.providerMetadata,
+                    pMetadata1 = nameInfo.nameMetadata,
+                    pMetadata2 = eventTypes.typeMetadata)
+                {
+                    descriptors[0].SetMetadata(pMetadata0, this.providerMetadata.Length, 2);
+                    descriptors[1].SetMetadata(pMetadata1, nameInfo.nameMetadata.Length, 1);
+                    descriptors[2].SetMetadata(pMetadata2, eventTypes.typeMetadata.Length, 1);
+                    int numDescrs = 3;
+
+                    for (int i = 0; i < eventTypes.typeInfos.Length; i++)
+                    {
+                        // Until M3, we need to morph strings to a counted representation
+                        // When TDH supports null terminated strings, we can remove this.  
+                        if (eventTypes.typeInfos[i].DataType == typeof(string))
+                        {
+                            // Write out the size of the string 
+                            descriptors[numDescrs].m_Ptr = (long)&descriptors[numDescrs + 1].m_Size;
+                            descriptors[numDescrs].m_Size = 2;
+                            numDescrs++;
+
+                            descriptors[numDescrs].m_Ptr = data[i].m_Ptr;
+                            descriptors[numDescrs].m_Size = data[i].m_Size - 2;   // Remove the null terminator
+                            numDescrs++;
+                        }
+                        else
+                        {
+                            descriptors[numDescrs].m_Ptr = data[i].m_Ptr;
+                            descriptors[numDescrs].m_Size = data[i].m_Size;
+
+                            // old conventions for bool is 4 bytes, but meta-data assumes 1.  
+                            if (data[i].m_Size == 4 && eventTypes.typeInfos[i].DataType == typeof(bool))
+                                descriptors[numDescrs].m_Size = 1;
+
+                            numDescrs++;
+                        }
+                    }
+
+                    this.WriteEventRaw(
+                        eventName,
+                        ref descriptor,
+                        activityID,
+                        childActivityID,
+                        numDescrs,
+                        (IntPtr)descriptors);
+                }
+            }
+#endif // FEATURE_MANAGED_ETW
+        }
+
+        private unsafe void WriteImpl(
+            string eventName,
+            ref EventSourceOptions options,
+            object data,
+            Guid* pActivityId,
+            Guid* pRelatedActivityId,
+            TraceLoggingEventTypes eventTypes)
+        {
+            try
+            {
+                fixed (EventSourceOptions* pOptions = &options)
+                {
+                    EventDescriptor descriptor;
+                    options.Opcode = options.IsOpcodeSet ? options.Opcode : GetOpcodeWithDefault(options.Opcode, eventName);
+                    var nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out descriptor);
+                    if (nameInfo == null)
+                    {
+                        return;
+                    }
+
+#if FEATURE_MANAGED_ETW
+                    var pinCount = eventTypes.pinCount;
+                    var scratch = stackalloc byte[eventTypes.scratchSize];
+                    var descriptors = stackalloc EventData[eventTypes.dataCount + 3];
+                    var pins = stackalloc GCHandle[pinCount];
+
+                    fixed (byte*
+                        pMetadata0 = this.providerMetadata,
+                        pMetadata1 = nameInfo.nameMetadata,
+                        pMetadata2 = eventTypes.typeMetadata)
+                    {
+                        descriptors[0].SetMetadata(pMetadata0, this.providerMetadata.Length, 2);
+                        descriptors[1].SetMetadata(pMetadata1, nameInfo.nameMetadata.Length, 1);
+                        descriptors[2].SetMetadata(pMetadata2, eventTypes.typeMetadata.Length, 1);
+#endif // FEATURE_MANAGED_ETW
+
+#if (!ES_BUILD_PCL && !ES_BUILD_PN)
+                        System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
+#endif
+                        EventOpcode opcode = (EventOpcode)descriptor.Opcode;
+
+                        Guid activityId = Guid.Empty;
+                        Guid relatedActivityId = Guid.Empty;
+                        if (pActivityId == null && pRelatedActivityId == null &&
+                           ((options.ActivityOptions & EventActivityOptions.Disable) == 0))
+                        {
+                            if (opcode == EventOpcode.Start)
+                            {
+                                m_activityTracker.OnStart(m_name, eventName, 0, ref activityId, ref relatedActivityId, options.ActivityOptions);
+                            }
+                            else if (opcode == EventOpcode.Stop)
+                            {
+                                m_activityTracker.OnStop(m_name, eventName, 0, ref activityId);
+                            }
+                            if (activityId != Guid.Empty)
+                                pActivityId = &activityId;
+                            if (relatedActivityId != Guid.Empty)
+                                pRelatedActivityId = &relatedActivityId;
+                        }
+
+                        try
+                        {
+#if FEATURE_MANAGED_ETW
+                            DataCollector.ThreadInstance.Enable(
+                                scratch,
+                                eventTypes.scratchSize,
+                                descriptors + 3,
+                                eventTypes.dataCount,
+                                pins,
+                                pinCount);
+
+                            var info = eventTypes.typeInfos[0];
+                            info.WriteData(TraceLoggingDataCollector.Instance, info.PropertyValueFactory(data));
+
+                            this.WriteEventRaw(
+                                eventName,
+                                ref descriptor,
+                                pActivityId,
+                                pRelatedActivityId,
+                                (int)(DataCollector.ThreadInstance.Finish() - descriptors),
+                                (IntPtr)descriptors);
+#endif // FEATURE_MANAGED_ETW
+
+                            // TODO enable filtering for listeners.
+                            if (m_Dispatchers != null)
+                            {
+                                var eventData = (EventPayload)(eventTypes.typeInfos[0].GetData(data));
+                                WriteToAllListeners(eventName, ref descriptor, nameInfo.tags, pActivityId, eventData);
+                            }
+
+                        }
+                        catch (Exception ex)
+                        {
+                            if (ex is EventSourceException)
+                                throw;
+                            else
+                                ThrowEventSourceException(eventName, ex);
+                        }
+#if FEATURE_MANAGED_ETW
+                        finally
+                        {
+                            this.WriteCleanup(pins, pinCount);
+                        }
+                    }
+#endif // FEATURE_MANAGED_ETW
+                }
+            }
+            catch (Exception ex)
+            {
+                if (ex is EventSourceException)
+                    throw;
+                else
+                    ThrowEventSourceException(eventName, ex);
+            }
+        }
+
+        private unsafe void WriteToAllListeners(string eventName, ref EventDescriptor eventDescriptor, EventTags tags, Guid* pActivityId, EventPayload payload)
+        {
+            EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this);
+            eventCallbackArgs.EventName = eventName;
+            eventCallbackArgs.m_level = (EventLevel) eventDescriptor.Level;
+            eventCallbackArgs.m_keywords = (EventKeywords) eventDescriptor.Keywords;
+            eventCallbackArgs.m_opcode = (EventOpcode) eventDescriptor.Opcode;
+            eventCallbackArgs.m_tags = tags;
+
+            // Self described events do not have an id attached. We mark it internally with -1.
+            eventCallbackArgs.EventId = -1;
+            if (pActivityId != null)
+                eventCallbackArgs.RelatedActivityId = *pActivityId;
+
+            if (payload != null)
+            {
+                eventCallbackArgs.Payload = new ReadOnlyCollection<object>((IList<object>)payload.Values);
+                eventCallbackArgs.PayloadNames = new ReadOnlyCollection<string>((IList<string>)payload.Keys);
+            }
+
+            DispatchToAllListeners(-1, pActivityId, eventCallbackArgs);
+        }
+
+#if (!ES_BUILD_PCL && !ES_BUILD_PN)
+        [System.Runtime.ConstrainedExecution.ReliabilityContract(
+            System.Runtime.ConstrainedExecution.Consistency.WillNotCorruptState,
+            System.Runtime.ConstrainedExecution.Cer.Success)]
+#endif
+        [NonEvent]
+        private unsafe void WriteCleanup(GCHandle* pPins, int cPins)
+        {
+            DataCollector.ThreadInstance.Disable();
+
+            for (int i = 0; i != cPins; i++)
+            {
+                if (IntPtr.Zero != (IntPtr)pPins[i])
+                {
+                    pPins[i].Free();
+                }
+            }
+        }
+
+        private void InitializeProviderMetadata()
+        {
+#if FEATURE_MANAGED_ETW
+            if (m_traits != null)
+            {
+                List<byte> traitMetaData = new List<byte>(100);
+                for (int i = 0; i < m_traits.Length - 1; i += 2)
+                {
+                    if (m_traits[i].StartsWith("ETW_", StringComparison.Ordinal))
+                    {
+                        string etwTrait = m_traits[i].Substring(4);
+                        byte traitNum;
+                        if (!byte.TryParse(etwTrait, out traitNum))
+                        {
+                            if (etwTrait == "GROUP")
+                            {
+                                traitNum = 1;
+                            }
+                            else
+                            {
+                                throw new ArgumentException(Resources.GetResourceString("UnknownEtwTrait", etwTrait), "traits");
+                            }
+                        }
+                        string value = m_traits[i + 1];
+                        int lenPos = traitMetaData.Count;
+                        traitMetaData.Add(0);                                           // Emit size (to be filled in later) 
+                        traitMetaData.Add(0);
+                        traitMetaData.Add(traitNum);                                    // Emit Trait number
+                        var valueLen = AddValueToMetaData(traitMetaData, value) + 3;    // Emit the value bytes +3 accounts for 3 bytes we emited above.  
+                        traitMetaData[lenPos] = unchecked((byte)valueLen);              // Fill in size
+                        traitMetaData[lenPos + 1] = unchecked((byte)(valueLen >> 8));
+                    }
+                }
+                providerMetadata = Statics.MetadataForString(this.Name, 0, traitMetaData.Count, 0);
+                int startPos = providerMetadata.Length - traitMetaData.Count;
+                foreach (var b in traitMetaData)
+                    providerMetadata[startPos++] = b;
+            }
+            else
+                providerMetadata = Statics.MetadataForString(this.Name, 0, 0, 0);
+#endif //FEATURE_MANAGED_ETW
+        }
+
+        private static int AddValueToMetaData(List<byte> metaData, string value)
+        {
+            if (value.Length == 0)
+                return 0;
+
+            int startPos = metaData.Count;
+            char firstChar = value[0];
+
+            if (firstChar == '@')
+                metaData.AddRange(Encoding.UTF8.GetBytes(value.Substring(1)));
+            else if (firstChar == '{')
+                metaData.AddRange(new Guid(value).ToByteArray());
+            else if (firstChar == '#')
+            {
+                for (int i = 1; i < value.Length; i++)
+                {
+                    if (value[i] != ' ')        // Skip spaces between bytes.  
+                    {
+                        if (!(i + 1 < value.Length))
+                        {
+                            throw new ArgumentException(Resources.GetResourceString("EvenHexDigits"), "traits");
+                        }
+                        metaData.Add((byte)(HexDigit(value[i]) * 16 + HexDigit(value[i + 1])));
+                        i++;
+                    }
+                }
+            }
+            else if ('A' <= firstChar || ' ' == firstChar)  // Is it alphabetic or space (excludes digits and most punctuation). 
+            {
+                metaData.AddRange(Encoding.UTF8.GetBytes(value));
+            }
+            else
+            {
+                throw new ArgumentException(Resources.GetResourceString("IllegalValue", value), "traits");
+            }
+
+            return metaData.Count - startPos;
+        }
+
+        /// <summary>
+        /// Returns a value 0-15 if 'c' is a hexadecimal digit.   If  it throws an argument exception.  
+        /// </summary>
+        private static int HexDigit(char c)
+        {
+            if ('0' <= c && c <= '9')
+            {
+                return (c - '0');
+            }
+            if ('a' <= c)
+            {
+                c = unchecked((char)(c - ('a' - 'A')));        // Convert to lower case
+            }
+            if ('A' <= c && c <= 'F')
+            {
+                return (c - 'A' + 10);
+            }
+            
+            throw new ArgumentException(Resources.GetResourceString("BadHexDigit", c), "traits");
+        }
+
+        private NameInfo UpdateDescriptor(
+            string name,
+            TraceLoggingEventTypes eventInfo,
+            ref EventSourceOptions options,
+            out EventDescriptor descriptor)
+        {
+            NameInfo nameInfo = null;
+            int identity = 0;
+            byte level = (options.valuesSet & EventSourceOptions.levelSet) != 0
+                ? options.level
+                : eventInfo.level;
+            byte opcode = (options.valuesSet & EventSourceOptions.opcodeSet) != 0
+                ? options.opcode
+                : eventInfo.opcode;
+            EventTags tags = (options.valuesSet & EventSourceOptions.tagsSet) != 0
+                ? options.tags
+                : eventInfo.Tags;
+            EventKeywords keywords = (options.valuesSet & EventSourceOptions.keywordsSet) != 0
+                ? options.keywords
+                : eventInfo.keywords;
+
+            if (this.IsEnabled((EventLevel)level, keywords))
+            {
+                nameInfo = eventInfo.GetNameInfo(name ?? eventInfo.Name, tags);
+                identity = nameInfo.identity;
+            }
+
+            descriptor = new EventDescriptor(identity, level, opcode, (long)keywords);
+            return nameInfo;
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTraits.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTraits.cs
new file mode 100644 (file)
index 0000000..e808a88
--- /dev/null
@@ -0,0 +1,28 @@
+// 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;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// Tags are flags that are not interpreted by EventSource but are passed along
+    /// to the EventListener. The EventListener determines the semantics of the flags.
+    /// </summary>
+    [Flags]
+    public enum EventTags
+    {
+        /// <summary>
+        /// No special traits are added to the event.
+        /// </summary>
+        None = 0,
+
+        /* Bits below 0x10000 are available for any use by the provider. */
+        /* Bits at or above 0x10000 are reserved for definition by Microsoft. */
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs
new file mode 100644 (file)
index 0000000..c223967
--- /dev/null
@@ -0,0 +1,262 @@
+// 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.Generic;
+using Interlocked = System.Threading.Interlocked;
+
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: Used when calling EventSource.WriteMultiMerge.
+    /// Stores the type information to use when writing the event fields.
+    /// </summary>
+    public class TraceLoggingEventTypes
+    {
+        internal readonly TraceLoggingTypeInfo[] typeInfos;
+        internal readonly string name;
+        internal readonly EventTags tags;
+        internal readonly byte level;
+        internal readonly byte opcode;
+        internal readonly EventKeywords keywords;
+        internal readonly byte[] typeMetadata;
+        internal readonly int scratchSize;
+        internal readonly int dataCount;
+        internal readonly int pinCount;
+        private ConcurrentSet<KeyValuePair<string, EventTags>, NameInfo> nameInfos;
+
+        /// <summary>
+        /// Initializes a new instance of TraceLoggingEventTypes corresponding
+        /// to the name, flags, and types provided. Always uses the default
+        /// TypeInfo for each Type.
+        /// </summary>
+        /// <param name="name">
+        /// The name to use when the name parameter passed to
+        /// EventSource.Write is null. This value must not be null.
+        /// </param>
+        /// <param name="tags">
+        /// Tags to add to the event if the tags are not set via options.
+        /// </param>
+        /// <param name="types">
+        /// The types of the fields in the event. This value must not be null.
+        /// </param>
+        internal TraceLoggingEventTypes(
+            string name,
+            EventTags tags,
+            params Type[] types)
+            : this(tags, name, MakeArray(types))
+        {
+            return;
+        }
+
+        /// <summary>
+        /// Returns a new instance of TraceLoggingEventInfo corresponding to the name,
+        /// flags, and typeInfos provided.
+        /// </summary>
+        /// <param name="name">
+        /// The name to use when the name parameter passed to
+        /// EventSource.Write is null. This value must not be null.
+        /// </param>
+        /// <param name="tags">
+        /// Tags to add to the event if the tags are not set via options.
+        /// </param>
+        /// <param name="typeInfos">
+        /// The types of the fields in the event. This value must not be null.
+        /// </param>
+        /// <returns>
+        /// An instance of TraceLoggingEventInfo with DefaultName set to the specified name
+        /// and with the specified typeInfos.
+        /// </returns>
+        internal TraceLoggingEventTypes(
+            string name,
+            EventTags tags,
+            params TraceLoggingTypeInfo[] typeInfos)
+            : this(tags, name, MakeArray(typeInfos))
+        {
+            return;
+        }
+
+        internal TraceLoggingEventTypes(
+            string name,
+            EventTags tags,
+            System.Reflection.ParameterInfo[] paramInfos)
+        {
+            if (name == null)
+            {
+                throw new ArgumentNullException(nameof(name));
+            }
+
+            Contract.EndContractBlock();
+
+            this.typeInfos = MakeArray(paramInfos);
+            this.name = name;
+            this.tags = tags;
+            this.level = Statics.DefaultLevel;
+
+            var collector = new TraceLoggingMetadataCollector();
+            for (int i = 0; i < typeInfos.Length; ++i)
+            {
+                var typeInfo = typeInfos[i];
+                this.level = Statics.Combine((int)typeInfo.Level, this.level);
+                this.opcode = Statics.Combine((int)typeInfo.Opcode, this.opcode);
+                this.keywords |= typeInfo.Keywords;
+                var paramName = paramInfos[i].Name;
+                if (Statics.ShouldOverrideFieldName(paramName))
+                {
+                    paramName = typeInfo.Name;
+                }
+                typeInfo.WriteMetadata(collector, paramName, EventFieldFormat.Default);
+            }
+
+            this.typeMetadata = collector.GetMetadata();
+            this.scratchSize = collector.ScratchSize;
+            this.dataCount = collector.DataCount;
+            this.pinCount = collector.PinCount;
+        }
+
+        private TraceLoggingEventTypes(
+            EventTags tags,
+            string defaultName,
+            TraceLoggingTypeInfo[] typeInfos)
+        {
+            if (defaultName == null)
+            {
+                throw new ArgumentNullException(nameof(defaultName));
+            }
+
+            Contract.EndContractBlock();
+
+            this.typeInfos = typeInfos;
+            this.name = defaultName;
+            this.tags = tags;
+            this.level = Statics.DefaultLevel;
+
+            var collector = new TraceLoggingMetadataCollector();
+            foreach (var typeInfo in typeInfos)
+            {
+                this.level = Statics.Combine((int)typeInfo.Level, this.level);
+                this.opcode = Statics.Combine((int)typeInfo.Opcode, this.opcode);
+                this.keywords |= typeInfo.Keywords;
+                typeInfo.WriteMetadata(collector, null, EventFieldFormat.Default);
+            }
+
+            this.typeMetadata = collector.GetMetadata();
+            this.scratchSize = collector.ScratchSize;
+            this.dataCount = collector.DataCount;
+            this.pinCount = collector.PinCount;
+        }
+
+        /// <summary>
+        /// Gets the default name that will be used for events with this descriptor.
+        /// </summary>
+        internal string Name
+        {
+            get { return this.name; }
+        }
+
+        /// <summary>
+        /// Gets the default level that will be used for events with this descriptor.
+        /// </summary>
+        internal EventLevel Level
+        {
+            get { return (EventLevel)this.level; }
+        }
+
+        /// <summary>
+        /// Gets the default opcode that will be used for events with this descriptor.
+        /// </summary>
+        internal EventOpcode Opcode
+        {
+            get { return (EventOpcode)this.opcode; }
+        }
+
+        /// <summary>
+        /// Gets the default set of keywords that will added to events with this descriptor.
+        /// </summary>
+        internal EventKeywords Keywords
+        {
+            get { return (EventKeywords)this.keywords; }
+        }
+
+        /// <summary>
+        /// Gets the default tags that will be added events with this descriptor.
+        /// </summary>
+        internal EventTags Tags
+        {
+            get { return this.tags; }
+        }
+
+        internal NameInfo GetNameInfo(string name, EventTags tags)
+        {
+            var ret = this.nameInfos.TryGet(new KeyValuePair<string, EventTags>(name, tags));
+            if (ret == null)
+            {
+                ret = this.nameInfos.GetOrAdd(new NameInfo(name, tags, this.typeMetadata.Length));
+            }
+
+            return ret;
+        }
+
+        private TraceLoggingTypeInfo[] MakeArray(System.Reflection.ParameterInfo[] paramInfos)
+        {
+            if (paramInfos == null)
+            {
+                throw new ArgumentNullException(nameof(paramInfos));
+            }
+
+            Contract.EndContractBlock();
+
+            var recursionCheck = new List<Type>(paramInfos.Length);
+            var result = new TraceLoggingTypeInfo[paramInfos.Length];
+            for (int i = 0; i < paramInfos.Length; ++i)
+            {
+                result[i] = TraceLoggingTypeInfo.GetInstance(paramInfos[i].ParameterType, recursionCheck);
+            }
+
+            return result;
+        }
+
+        private static TraceLoggingTypeInfo[] MakeArray(Type[] types)
+        {
+            if (types == null)
+            {
+                throw new ArgumentNullException(nameof(types));
+            }
+
+            Contract.EndContractBlock();
+
+            var recursionCheck = new List<Type>(types.Length);
+            var result = new TraceLoggingTypeInfo[types.Length];
+            for (int i = 0; i < types.Length; i++)
+            {
+                result[i] = TraceLoggingTypeInfo.GetInstance(types[i], recursionCheck);
+            }
+
+            return result;
+        }
+
+        private static TraceLoggingTypeInfo[] MakeArray(
+            TraceLoggingTypeInfo[] typeInfos)
+        {
+            if (typeInfos == null)
+            {
+                throw new ArgumentNullException(nameof(typeInfos));
+            }
+
+            Contract.EndContractBlock();
+
+            return (TraceLoggingTypeInfo[])typeInfos.Clone(); ;
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs
new file mode 100644 (file)
index 0000000..41225c8
--- /dev/null
@@ -0,0 +1,370 @@
+// 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.Generic;
+
+#if ES_BUILD_STANDALONE
+using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: used when implementing a custom TraceLoggingTypeInfo.
+    /// An instance of this type is provided to the TypeInfo.WriteMetadata method.
+    /// </summary>
+    internal class TraceLoggingMetadataCollector
+    {
+        private readonly Impl impl;
+        private readonly FieldMetadata currentGroup;
+        private int bufferedArrayFieldCount = int.MinValue;
+
+        /// <summary>
+        /// Creates a root-level collector.
+        /// </summary>
+        internal TraceLoggingMetadataCollector()
+        {
+            this.impl = new Impl();
+        }
+
+        /// <summary>
+        /// Creates a collector for a group.
+        /// </summary>
+        /// <param name="other">Parent collector</param>
+        /// <param name="group">The field that starts the group</param>
+        private TraceLoggingMetadataCollector(
+            TraceLoggingMetadataCollector other,
+            FieldMetadata group)
+        {
+            this.impl = other.impl;
+            this.currentGroup = group;
+        }
+
+        /// <summary>
+        /// The field tags to be used for the next field.
+        /// This will be reset to None each time a field is written.
+        /// </summary>
+        internal EventFieldTags Tags
+        {
+            get;
+            set;
+        }
+
+        internal int ScratchSize
+        {
+            get { return this.impl.scratchSize; }
+        }
+
+        internal int DataCount
+        {
+            get { return this.impl.dataCount; }
+        }
+
+        internal int PinCount
+        {
+            get { return this.impl.pinCount; }
+        }
+
+        private bool BeginningBufferedArray
+        {
+            get { return this.bufferedArrayFieldCount == 0; }
+        }
+
+        /// <summary>
+        /// Call this method to add a group to the event and to return
+        /// a new metadata collector that can be used to add fields to the
+        /// group. After all of the fields in the group have been written,
+        /// switch back to the original metadata collector to add fields
+        /// outside of the group.
+        /// Special-case: if name is null, no group is created, and AddGroup
+        /// returns the original metadata collector. This is useful when
+        /// adding the top-level group for an event.
+        /// Note: do not use the original metadata collector while the group's
+        /// metadata collector is in use, and do not use the group's metadata
+        /// collector after switching back to the original.
+        /// </summary>
+        /// <param name="name">
+        /// The name of the group. If name is null, the call to AddGroup is a
+        /// no-op (collector.AddGroup(null) returns collector).
+        /// </param>
+        /// <returns>
+        /// A new metadata collector that can be used to add fields to the group.
+        /// </returns>
+        public TraceLoggingMetadataCollector AddGroup(string name)
+        {
+            TraceLoggingMetadataCollector result = this;
+
+            if (name != null || // Normal.
+                this.BeginningBufferedArray) // Error, FieldMetadata's constructor will throw the appropriate exception.
+            {
+                var newGroup = new FieldMetadata(
+                    name,
+                    TraceLoggingDataType.Struct,
+                    this.Tags,
+                    this.BeginningBufferedArray);
+                this.AddField(newGroup);
+                result = new TraceLoggingMetadataCollector(this, newGroup);
+            }
+
+            return result;
+        }
+
+        /// <summary>
+        /// Adds a scalar field to an event.
+        /// </summary>
+        /// <param name="name">
+        /// The name to use for the added field. This value must not be null.
+        /// </param>
+        /// <param name="type">
+        /// The type code for the added field. This must be a fixed-size type
+        /// (e.g. string types are not supported).
+        /// </param>
+        public void AddScalar(string name, TraceLoggingDataType type)
+        {
+            int size;
+            switch ((TraceLoggingDataType)((int)type & Statics.InTypeMask))
+            {
+                case TraceLoggingDataType.Int8:
+                case TraceLoggingDataType.UInt8:
+                case TraceLoggingDataType.Char8:
+                    size = 1;
+                    break;
+                case TraceLoggingDataType.Int16:
+                case TraceLoggingDataType.UInt16:
+                case TraceLoggingDataType.Char16:
+                    size = 2;
+                    break;
+                case TraceLoggingDataType.Int32:
+                case TraceLoggingDataType.UInt32:
+                case TraceLoggingDataType.HexInt32:
+                case TraceLoggingDataType.Float:
+                case TraceLoggingDataType.Boolean32:
+                    size = 4;
+                    break;
+                case TraceLoggingDataType.Int64:
+                case TraceLoggingDataType.UInt64:
+                case TraceLoggingDataType.HexInt64:
+                case TraceLoggingDataType.Double:
+                case TraceLoggingDataType.FileTime:
+                    size = 8;
+                    break;
+                case TraceLoggingDataType.Guid:
+                case TraceLoggingDataType.SystemTime:
+                    size = 16;
+                    break;
+                default:
+                    throw new ArgumentOutOfRangeException(nameof(type));
+            }
+
+            this.impl.AddScalar(size);
+            this.AddField(new FieldMetadata(name, type, this.Tags, this.BeginningBufferedArray));
+        }
+
+        /// <summary>
+        /// Adds a binary-format field to an event.
+        /// Compatible with core types: Binary, CountedUtf16String, CountedMbcsString.
+        /// Compatible with dataCollector methods: AddBinary(string), AddArray(Any8bitType[]).
+        /// </summary>
+        /// <param name="name">
+        /// The name to use for the added field. This value must not be null.
+        /// </param>
+        /// <param name="type">
+        /// The type code for the added field. This must be a Binary or CountedString type.
+        /// </param>
+        public void AddBinary(string name, TraceLoggingDataType type)
+        {
+            switch ((TraceLoggingDataType)((int)type & Statics.InTypeMask))
+            {
+                case TraceLoggingDataType.Binary:
+                case TraceLoggingDataType.CountedMbcsString:
+                case TraceLoggingDataType.CountedUtf16String:
+                    break;
+                default:
+                    throw new ArgumentOutOfRangeException(nameof(type));
+            }
+
+            this.impl.AddScalar(2);
+            this.impl.AddNonscalar();
+            this.AddField(new FieldMetadata(name, type, this.Tags, this.BeginningBufferedArray));
+        }
+
+        /// <summary>
+        /// Adds an array field to an event.
+        /// </summary>
+        /// <param name="name">
+        /// The name to use for the added field. This value must not be null.
+        /// </param>
+        /// <param name="type">
+        /// The type code for the added field. This must be a fixed-size type
+        /// or a string type. In the case of a string type, this adds an array
+        /// of characters, not an array of strings.
+        /// </param>
+        public void AddArray(string name, TraceLoggingDataType type)
+        {
+            switch ((TraceLoggingDataType)((int)type & Statics.InTypeMask))
+            {
+                case TraceLoggingDataType.Utf16String:
+                case TraceLoggingDataType.MbcsString:
+                case TraceLoggingDataType.Int8:
+                case TraceLoggingDataType.UInt8:
+                case TraceLoggingDataType.Int16:
+                case TraceLoggingDataType.UInt16:
+                case TraceLoggingDataType.Int32:
+                case TraceLoggingDataType.UInt32:
+                case TraceLoggingDataType.Int64:
+                case TraceLoggingDataType.UInt64:
+                case TraceLoggingDataType.Float:
+                case TraceLoggingDataType.Double:
+                case TraceLoggingDataType.Boolean32:
+                case TraceLoggingDataType.Guid:
+                case TraceLoggingDataType.FileTime:
+                case TraceLoggingDataType.HexInt32:
+                case TraceLoggingDataType.HexInt64:
+                case TraceLoggingDataType.Char16:
+                case TraceLoggingDataType.Char8:
+                    break;
+                default:
+                    throw new ArgumentOutOfRangeException(nameof(type));
+            }
+
+            if (this.BeginningBufferedArray)
+            {
+                throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedNestedArraysEnums"));
+            }
+
+            this.impl.AddScalar(2);
+            this.impl.AddNonscalar();
+            this.AddField(new FieldMetadata(name, type, this.Tags, true));
+        }
+
+        public void BeginBufferedArray()
+        {
+            if (this.bufferedArrayFieldCount >= 0)
+            {
+                throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedNestedArraysEnums"));
+            }
+
+            this.bufferedArrayFieldCount = 0;
+            this.impl.BeginBuffered();
+        }
+
+        public void EndBufferedArray()
+        {
+            if (this.bufferedArrayFieldCount != 1)
+            {
+                throw new InvalidOperationException(Resources.GetResourceString("EventSource_IncorrentlyAuthoredTypeInfo"));
+            }
+
+            this.bufferedArrayFieldCount = int.MinValue;
+            this.impl.EndBuffered();
+        }
+
+        /// <summary>
+        /// Adds a custom-serialized field to an event.
+        /// </summary>
+        /// <param name="name">
+        /// The name to use for the added field. This value must not be null.
+        /// </param>
+        /// <param name="type">The encoding type for the field.</param>
+        /// <param name="metadata">Additional information needed to decode the field, if any.</param>
+        public void AddCustom(string name, TraceLoggingDataType type, byte[] metadata)
+        {
+            if (this.BeginningBufferedArray)
+            {
+                throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedCustomSerializedData"));
+            }
+
+            this.impl.AddScalar(2);
+            this.impl.AddNonscalar();
+            this.AddField(new FieldMetadata(
+                name,
+                type,
+                this.Tags,
+                metadata));
+        }
+
+        internal byte[] GetMetadata()
+        {
+            var size = this.impl.Encode(null);
+            var metadata = new byte[size];
+            this.impl.Encode(metadata);
+            return metadata;
+        }
+
+        private void AddField(FieldMetadata fieldMetadata)
+        {
+            this.Tags = EventFieldTags.None;
+            this.bufferedArrayFieldCount++;
+            this.impl.fields.Add(fieldMetadata);
+
+            if (this.currentGroup != null)
+            {
+                this.currentGroup.IncrementStructFieldCount();
+            }
+        }
+
+        private class Impl
+        {
+            internal readonly List<FieldMetadata> fields = new List<FieldMetadata>();
+            internal short scratchSize;
+            internal sbyte dataCount;
+            internal sbyte pinCount;
+            private int bufferNesting;
+            private bool scalar;
+
+            public void AddScalar(int size)
+            {
+                if (this.bufferNesting == 0)
+                {
+                    if (!this.scalar)
+                    {
+                        this.dataCount = checked((sbyte)(this.dataCount + 1));
+                    }
+
+                    this.scalar = true;
+                    this.scratchSize = checked((short)(this.scratchSize + size));
+                }
+            }
+
+            public void AddNonscalar()
+            {
+                if (this.bufferNesting == 0)
+                {
+                    this.scalar = false;
+                    this.pinCount = checked((sbyte)(this.pinCount + 1));
+                    this.dataCount = checked((sbyte)(this.dataCount + 1));
+                }
+            }
+
+            public void BeginBuffered()
+            {
+                if (this.bufferNesting == 0)
+                {
+                    this.AddNonscalar();
+                }
+
+                this.bufferNesting++;
+            }
+
+            public void EndBuffered()
+            {
+                this.bufferNesting--;
+            }
+
+            public int Encode(byte[] metadata)
+            {
+                int size = 0;
+
+                foreach (var field in this.fields)
+                {
+                    field.Encode(ref size, metadata);
+                }
+
+                return size;
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs
new file mode 100644 (file)
index 0000000..d68e106
--- /dev/null
@@ -0,0 +1,209 @@
+// 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.Generic;
+
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: used when implementing a custom TraceLoggingTypeInfo.
+    /// Non-generic base class for TraceLoggingTypeInfo&lt;DataType>. Do not derive
+    /// from this class. Instead, derive from TraceLoggingTypeInfo&lt;DataType>.
+    /// </summary>
+    internal abstract class TraceLoggingTypeInfo
+    {
+        private readonly string name;
+        private readonly EventKeywords keywords;
+        private readonly EventLevel level = (EventLevel)(-1);
+        private readonly EventOpcode opcode = (EventOpcode)(-1);
+        private readonly EventTags tags;
+        private readonly Type dataType;
+        private readonly Func<object, PropertyValue> propertyValueFactory;
+
+        internal TraceLoggingTypeInfo(Type dataType)
+        {
+            if (dataType == null)
+            {
+                throw new ArgumentNullException(nameof(dataType));
+            }
+
+            Contract.EndContractBlock();
+
+            this.name = dataType.Name;
+            this.dataType = dataType;
+            this.propertyValueFactory = PropertyValue.GetFactory(dataType);
+        }
+
+        internal TraceLoggingTypeInfo(
+            Type dataType,
+            string name,
+            EventLevel level,
+            EventOpcode opcode,
+            EventKeywords keywords,
+            EventTags tags)
+        {
+            if (dataType == null)
+            {
+                throw new ArgumentNullException(nameof(dataType));
+            }
+
+            if (name == null)
+            {
+                throw new ArgumentNullException(nameof(name));
+            }
+
+            Contract.EndContractBlock();
+
+            Statics.CheckName(name);
+
+            this.name = name;
+            this.keywords = keywords;
+            this.level = level;
+            this.opcode = opcode;
+            this.tags = tags;
+            this.dataType = dataType;
+            this.propertyValueFactory = PropertyValue.GetFactory(dataType);
+        }
+
+        /// <summary>
+        /// Gets the name to use for the event if this type is the top-level type,
+        /// or the name to use for an implicitly-named field.
+        /// Never null.
+        /// </summary>
+        public string Name
+        {
+            get { return this.name; }
+        }
+
+        /// <summary>
+        /// Gets the event level associated with this type. Any value in the range 0..255
+        /// is an associated event level. Any value outside the range 0..255 is invalid and
+        /// indicates that this type has no associated event level.
+        /// </summary>
+        public EventLevel Level
+        {
+            get { return this.level; }
+        }
+
+        /// <summary>
+        /// Gets the event opcode associated with this type. Any value in the range 0..255
+        /// is an associated event opcode. Any value outside the range 0..255 is invalid and
+        /// indicates that this type has no associated event opcode.
+        /// </summary>
+        public EventOpcode Opcode
+        {
+            get { return this.opcode; }
+        }
+
+        /// <summary>
+        /// Gets the keyword(s) associated with this type.
+        /// </summary>
+        public EventKeywords Keywords
+        {
+            get { return this.keywords; }
+        }
+
+        /// <summary>
+        /// Gets the event tags associated with this type.
+        /// </summary>
+        public EventTags Tags
+        {
+            get { return this.tags; }
+        }
+
+        internal Type DataType
+        {
+            get { return this.dataType; }
+        }
+
+        internal Func<object, PropertyValue> PropertyValueFactory
+        {
+            get { return this.propertyValueFactory; }
+        }
+
+        /// <summary>
+        /// When overridden by a derived class, writes the metadata (schema) for
+        /// this type. Note that the sequence of operations in WriteMetadata should be
+        /// essentially identical to the sequence of operations in
+        /// WriteData/WriteObjectData. Otherwise, the metadata and data will not match,
+        /// which may cause trouble when decoding the event.
+        /// </summary>
+        /// <param name="collector">
+        /// The object that collects metadata for this object's type. Metadata is written
+        /// by calling methods on the collector object. Note that if the type contains
+        /// sub-objects, the implementation of this method may need to call the
+        /// WriteMetadata method for the type of the sub-object, e.g. by calling
+        /// TraceLoggingTypeInfo&lt;SubType&gt;.Instance.WriteMetadata(...).
+        /// </param>
+        /// <param name="name">
+        /// The name of the property that contains an object of this type, or null if this
+        /// object is being written as a top-level object of an event. Typical usage
+        /// is to pass this value to collector.AddGroup.
+        /// </param>
+        /// <param name="format">
+        /// The format attribute for the field that contains an object of this type.
+        /// </param>
+        public abstract void WriteMetadata(
+            TraceLoggingMetadataCollector collector,
+            string name,
+            EventFieldFormat format);
+
+        /// <summary>
+        /// Refer to TraceLoggingTypeInfo.WriteObjectData for information about this
+        /// method.
+        /// </summary>
+        /// <param name="collector">
+        /// Refer to TraceLoggingTypeInfo.WriteObjectData for information about this
+        /// method.
+        /// </param>
+        /// <param name="value">
+        /// Refer to TraceLoggingTypeInfo.WriteObjectData for information about this
+        /// method.
+        /// </param>
+        public abstract void WriteData(
+            TraceLoggingDataCollector collector,
+            PropertyValue value);
+
+        /// <summary>
+        /// Fetches the event parameter data for internal serialization. 
+        /// </summary>
+        /// <param name="value"></param>
+        /// <returns></returns>
+        public virtual object GetData(object value)
+        {
+            return value;
+        }
+
+        [ThreadStatic] // per-thread cache to avoid synchronization
+        private static Dictionary<Type, TraceLoggingTypeInfo> threadCache;
+
+        public static TraceLoggingTypeInfo GetInstance(Type type, List<Type> recursionCheck)
+        {
+            var cache = threadCache ?? (threadCache = new Dictionary<Type, TraceLoggingTypeInfo>());
+
+            TraceLoggingTypeInfo instance;
+            if (!cache.TryGetValue(type, out instance))
+            {
+                if (recursionCheck == null)
+                    recursionCheck = new List<Type>();
+                var recursionCheckCount = recursionCheck.Count;
+                instance = Statics.CreateDefaultTypeInfo(type, recursionCheck);
+                cache[type] = instance;
+                recursionCheck.RemoveRange(recursionCheckCount, recursionCheck.Count - recursionCheckCount);
+            }
+            return instance;
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TypeAnalysis.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TypeAnalysis.cs
new file mode 100644 (file)
index 0000000..42cdde5
--- /dev/null
@@ -0,0 +1,103 @@
+// 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.Generic;
+using System.Reflection;
+
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    /// <summary>
+    /// TraceLogging: stores the per-type information obtained by reflecting over a type.
+    /// </summary>
+    internal sealed class TypeAnalysis
+    {
+        internal readonly PropertyAnalysis[] properties;
+        internal readonly string name;
+        internal readonly EventKeywords keywords;
+        internal readonly EventLevel level = (EventLevel)(-1);
+        internal readonly EventOpcode opcode = (EventOpcode)(-1);
+        internal readonly EventTags tags;
+
+        public TypeAnalysis(
+            Type dataType,
+            EventDataAttribute eventAttrib,
+            List<Type> recursionCheck)
+        {
+            var propertyInfos = Statics.GetProperties(dataType);
+            var propertyList = new List<PropertyAnalysis>();
+
+            foreach (var propertyInfo in propertyInfos)
+            {
+                if (Statics.HasCustomAttribute(propertyInfo, typeof(EventIgnoreAttribute)))
+                {
+                    continue;
+                }
+
+                if (!propertyInfo.CanRead ||
+                    propertyInfo.GetIndexParameters().Length != 0)
+                {
+                    continue;
+                }
+
+                MethodInfo getterInfo = Statics.GetGetMethod(propertyInfo);
+                if (getterInfo == null)
+                {
+                    continue;
+                }
+
+                if (getterInfo.IsStatic || !getterInfo.IsPublic)
+                {
+                    continue;
+                }
+
+                var propertyType = propertyInfo.PropertyType;
+                var propertyTypeInfo = TraceLoggingTypeInfo.GetInstance(propertyType, recursionCheck);
+                var fieldAttribute = Statics.GetCustomAttribute<EventFieldAttribute>(propertyInfo);
+
+                string propertyName =
+                    fieldAttribute != null && fieldAttribute.Name != null
+                    ? fieldAttribute.Name
+                    : Statics.ShouldOverrideFieldName(propertyInfo.Name)
+                    ? propertyTypeInfo.Name
+                    : propertyInfo.Name;
+                propertyList.Add(new PropertyAnalysis(
+                    propertyName,
+                    propertyInfo,
+                    propertyTypeInfo,
+                    fieldAttribute));
+            }
+
+            this.properties = propertyList.ToArray();
+
+            foreach (var property in this.properties)
+            {
+                var typeInfo = property.typeInfo;
+                this.level = (EventLevel)Statics.Combine((int)typeInfo.Level, (int)this.level);
+                this.opcode = (EventOpcode)Statics.Combine((int)typeInfo.Opcode, (int)this.opcode);
+                this.keywords |= typeInfo.Keywords;
+                this.tags |= typeInfo.Tags;
+            }
+
+            if (eventAttrib != null)
+            {
+                this.level = (EventLevel)Statics.Combine((int)eventAttrib.Level, (int)this.level);
+                this.opcode = (EventOpcode)Statics.Combine((int)eventAttrib.Opcode, (int)this.opcode);
+                this.keywords |= eventAttrib.Keywords;
+                this.tags |= eventAttrib.Tags;
+                this.name = eventAttrib.Name;
+            }
+
+            if (this.name == null)
+            {
+                this.name = dataType.Name;
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/Winmeta.cs b/src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/Winmeta.cs
new file mode 100644 (file)
index 0000000..ac756b6
--- /dev/null
@@ -0,0 +1,196 @@
+// 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.
+
+/*============================================================
+**
+**
+** Purpose: 
+** Contains eventing constants defined by the Windows 
+** environment.
+** 
+============================================================*/
+#if ES_BUILD_STANDALONE
+#define FEATURE_MANAGED_ETW_CHANNELS
+#endif
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+    using System;
+
+    /// <summary>
+    /// WindowsEventLevel. Custom values must be in the range from 16 through 255
+    /// </summary>
+    public enum EventLevel
+    {
+        /// <summary>
+        /// Log always
+        /// </summary>
+        LogAlways = 0,
+        /// <summary>
+        /// Only critical errors
+        /// </summary>
+        Critical,
+        /// <summary>
+        /// All errors, including previous levels
+        /// </summary>
+        Error,
+        /// <summary>
+        /// All warnings, including previous levels
+        /// </summary>
+        Warning,
+        /// <summary>
+        /// All informational events, including previous levels
+        /// </summary>
+        Informational,
+        /// <summary>
+        /// All events, including previous levels 
+        /// </summary>
+        Verbose
+    }
+    /// <summary>
+    /// WindowsEventTask. Custom values must be in the range from 1 through 65534
+    /// </summary>
+#if (!ES_BUILD_STANDALONE && !ES_BUILD_PN)
+    [System.Runtime.CompilerServices.FriendAccessAllowed]
+#endif
+    public enum EventTask
+    {
+        /// <summary>
+        /// Undefined task
+        /// </summary>
+        None = 0
+    }
+    /// <summary>
+    /// EventOpcode. Custom values must be in the range from 11 through 239
+    /// </summary>
+#if (!ES_BUILD_STANDALONE && !ES_BUILD_PN)
+    [System.Runtime.CompilerServices.FriendAccessAllowed]
+#endif
+    public enum EventOpcode
+    {
+        /// <summary>
+        /// An informational event
+        /// </summary>
+        Info = 0,
+        /// <summary>
+        /// An activity start event
+        /// </summary>
+        Start,
+        /// <summary>
+        /// An activity end event 
+        /// </summary>
+        Stop,
+        /// <summary>
+        /// A trace collection start event
+        /// </summary>
+        DataCollectionStart,
+        /// <summary>
+        /// A trace collection end event
+        /// </summary>
+        DataCollectionStop,
+        /// <summary>
+        /// An extensional event
+        /// </summary>
+        Extension,
+        /// <summary>
+        /// A reply event
+        /// </summary>
+        Reply,
+        /// <summary>
+        /// An event representing the activity resuming from the suspension
+        /// </summary>
+        Resume,
+        /// <summary>
+        /// An event representing the activity is suspended, pending another activity's completion
+        /// </summary>
+        Suspend,
+        /// <summary>
+        /// An event representing the activity is transferred to another component, and can continue to work
+        /// </summary>
+        Send,
+        /// <summary>
+        /// An event representing receiving an activity transfer from another component 
+        /// </summary>
+        Receive = 240
+    }
+
+    // Added for CLR V4
+    /// <summary>
+    /// EventChannel. Custom values must be in the range from 16 through 255. Currently only predefined values allowed.
+    /// </summary>
+    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1028:EnumStorageShouldBeInt32", Justification = "Backwards compatibility")]
+#if (!ES_BUILD_STANDALONE && !ES_BUILD_PN)
+    [System.Runtime.CompilerServices.FriendAccessAllowed]
+#endif
+    public enum EventChannel : byte
+    {
+        /// <summary>
+        /// No channel
+        /// </summary>
+        None = 0,
+        // Channels 1 - 15 are reserved...
+        /// <summary>The admin channel</summary>
+        Admin = 16,
+        /// <summary>The operational channel</summary>
+        Operational = 17,
+        /// <summary>The analytic channel</summary>
+        Analytic = 18,
+        /// <summary>The debug channel</summary>
+        Debug = 19,
+
+    };
+
+    /// <summary>
+    /// EventOpcode
+    /// </summary>
+    [Flags]
+    public enum EventKeywords : long
+    {
+        /// <summary>
+        /// No events. 
+        /// </summary>
+        None = 0x0,
+        /// <summary>
+        /// All Events 
+        /// </summary>
+        All = ~0,
+        /// <summary>
+        /// Telemetry events
+        /// </summary>
+        MicrosoftTelemetry = 0x02000000000000,
+        /// <summary>
+        /// WDI context events
+        /// </summary>
+        WdiContext = 0x02000000000000,
+        /// <summary>
+        /// WDI diagnostic events
+        /// </summary>
+        WdiDiagnostic = 0x04000000000000,
+        /// <summary>
+        /// SQM events
+        /// </summary>
+        Sqm = 0x08000000000000,
+        /// <summary>
+        /// Failed security audits
+        /// </summary>
+        AuditFailure = 0x10000000000000,
+        /// <summary>
+        /// Successful security audits
+        /// </summary>
+        AuditSuccess = 0x20000000000000,
+        /// <summary>
+        /// Transfer events where the related Activity ID is a computed value and not a GUID
+        /// N.B. The correct value for this field is 0x40000000000000.
+        /// </summary>
+        CorrelationHint = 0x10000000000000,
+        /// <summary>
+        /// Events raised using classic eventlog API
+        /// </summary>
+        EventLogClassic = 0x80000000000000
+    }
+}
diff --git a/src/coreclr/src/mscorlib/shared/System/IO/FileLoadException.cs b/src/coreclr/src/mscorlib/shared/System/IO/FileLoadException.cs
new file mode 100644 (file)
index 0000000..a4b68a8
--- /dev/null
@@ -0,0 +1,102 @@
+// 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.Serialization;
+
+namespace System.IO
+{
+    [Serializable]
+    public partial class FileLoadException : IOException
+    {
+        public FileLoadException()
+            : base(SR.IO_FileLoad)
+        {
+            SetErrorCode(__HResults.COR_E_FILELOAD);
+        }
+
+        public FileLoadException(string message)
+            : base(message)
+        {
+            SetErrorCode(__HResults.COR_E_FILELOAD);
+        }
+
+        public FileLoadException(string message, Exception inner)
+            : base(message, inner)
+        {
+            SetErrorCode(__HResults.COR_E_FILELOAD);
+        }
+
+        public FileLoadException(string message, string fileName) : base(message)
+        {
+            SetErrorCode(__HResults.COR_E_FILELOAD);
+            FileName = fileName;
+        }
+
+        public FileLoadException(string message, string fileName, Exception inner)
+            : base(message, inner)
+        {
+            SetErrorCode(__HResults.COR_E_FILELOAD);
+            FileName = fileName;
+        }
+
+        public override string Message
+        {
+            get
+            {
+                if (_message == null)
+                {
+                    _message = FormatFileLoadExceptionMessage(FileName, HResult);
+                }
+                return _message;
+            }
+        }
+
+        public string FileName { get; }
+        public string FusionLog { get; }
+
+        public override string ToString()
+        {
+            string s = GetType().ToString() + ": " + Message;
+
+            if (FileName != null && FileName.Length != 0)
+                s += Environment.NewLine + SR.Format(SR.IO_FileName_Name, FileName);
+
+            if (InnerException != null)
+                s = s + " ---> " + InnerException.ToString();
+
+            if (StackTrace != null)
+                s += Environment.NewLine + StackTrace;
+
+            if (FusionLog != null)
+            {
+                if (s == null)
+                    s = " ";
+                s += Environment.NewLine;
+                s += Environment.NewLine;
+                s += FusionLog;
+            }
+
+            return s;
+        }
+
+        protected FileLoadException(SerializationInfo info, StreamingContext context)
+            : base(info, context)
+        {
+            // Base class constructor will check info != null.
+
+            FileName = info.GetString("FileLoad_FileName");
+            FusionLog = info.GetString("FileLoad_FusionLog");
+        }
+
+        public override void GetObjectData(SerializationInfo info, StreamingContext context)
+        {
+            // Serialize data for our base classes.  base will verify info != null.
+            base.GetObjectData(info, context);
+
+            // Serialize data for this class
+            info.AddValue("FileLoad_FileName", FileName, typeof(string));
+            info.AddValue("FileLoad_FusionLog", FusionLog, typeof(string));
+        }
+    }
+}