Re-Factor EventSource to Support Writing to EventPipe (#11435)
[platform/upstream/coreclr.git] / src / mscorlib / shared / System / Diagnostics / Tracing / EventSource.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 // This program uses code hyperlinks available as part of the HyperAddin Visual Studio plug-in.
6 // It is available from http://www.codeplex.com/hyperAddin 
7 #if !ES_BUILD_STANDALONE && !CORECLR && !ES_BUILD_PN
8 #define FEATURE_ACTIVITYSAMPLING
9 #endif // !ES_BUILD_STANDALONE
10
11 #if ES_BUILD_STANDALONE
12 #define FEATURE_MANAGED_ETW_CHANNELS
13 // #define FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
14 #endif
15
16 /* DESIGN NOTES DESIGN NOTES DESIGN NOTES DESIGN NOTES */
17 // DESIGN NOTES
18 // Over the years EventSource has become more complex and so it is important to understand
19 // the basic structure of the code to insure that it does not grow more complex.
20 //
21 // Basic Model
22 //
23 // PRINCIPLE: EventSource - ETW decoupling
24 // 
25 // Conceptually and EventSouce is something takes event logging data from the source methods 
26 // To the EventListener that can subscribe them.  Note that CONCEPTUALLY EVENTSOURCES DON'T
27 // KNOW ABOUT ETW!.   The MODEL of the system is that there is a special EventListern Which
28 // we will call the EtwEventListener, that forwards commands from ETW to EventSources and
29 // listeners to the EventSources and forwards on those events to ETW.   THus the model should
30 // be that you DON'T NEED ETW.    
31 //
32 // Now in actual practice, EventSouce have rather intimate knowledge of ETW and send events
33 // to it directly, but this can be VIEWED AS AN OPTIMIATION.  
34 //
35 // Basic Event Data Flow:
36 // 
37 // There are two ways for event Data to enter the system
38 //     1) WriteEvent* and friends.  This is called the 'contract' based approach because 
39 //        you write a method per event which forms a contract that is know at compile time.
40 //        In this scheme each event is given an EVENTID (small integer). which is its identity
41 //     2) Write<T> methods.   This is called the 'dynamic' approach because new events 
42 //        can be created on the fly.  Event identity is determined by the event NAME, and these
43 //        are not quite as efficient at runtime since you have at least a hash table lookup
44 //        on every event write.  
45 //
46 // EventSource-EventListener transfer fully support both ways of writing events (either contract
47 // based (WriteEvent*) or dynamic (Write<T>).   Both way fully support the same set of data
48 // types.   It is suggested, however, that you use the contract based approach when the event scheme 
49 // is known at compile time (that is whenever possible).  It is more efficient, but more importantly
50 // it makes the contract very explicit, and centralizes all policy about logging.  These are good 
51 // things.    The Write<T> API is really meant for more ad-hoc 
52 //
53 // Allowed Data. 
54 // 
55 // Note that EventSource-EventListeners have a conceptual serialization-deserialization that happens
56 // during the transfer.   In particular object identity is not preserved, some objects are morphed, 
57 // and not all data types are supported.   In particular you can pass
58 // 
59 // A Valid type to log to an EventSource include
60 //   * Primitive data types
61 //   * IEnumerable<T> of valid types T (this include arrays)  (* New for V4.6)
62 //   * Explicitly Opted in class or struct with public property Getters over Valid types.  (* New for V4.6)
63 // 
64 // This set of types is roughly a generalization of JSON support (Basically primitives, bags, and arrays).   
65 //
66 // Explicitly allowed structs include (* New for V4.6)
67 //   * Marked with the EventData attribute
68 //   * implicitly defined (e.g the C# new {x = 3, y = 5} syntax)
69 //   * KeyValuePair<K,V>  (thus dictionaries can be passed since they are an IEnumerable of KeyValuePair)
70 //         
71 // When classes are returned in an EventListener, what is returned is something that implements 
72 // IDictionary<string, T>.  Thus when objects are passed to an EventSource they are transformed
73 // into a key-value bag (the IDictionary<string, T>) for consumption in the listener.   These 
74 // are obvious NOT the original objects.  
75 // 
76 // ETWserialization formats:
77 // 
78 // As mentioned conceptually EventSource's send data to EventListeners and there is a conceptual 
79 // copy/morph of that data as described above.   In addition the .NET framework supports a conceptual
80 // ETWListener that will send the data to then ETW stream.   If you use this feature, the data needs 
81 // to be serialized in a way that ETW supports.  ETW supports the following serialization formats 
82 // 
83 //     1) Manifest Based serialization. 
84 //     2) SelfDescribing serialization (TraceLogging style in the TraceLogging directory)
85 //
86 // A key factor is that the Write<T> method, which support on the fly definition of events, can't
87 // support the manifest based serialization because the manifest needs the schema of all events 
88 // to be known before any events are emitted.  This implies the following
89 //
90 // If you use Write<T> and the output goes to ETW it will use the SelfDescribing format.
91 // If you use the EventSource(string) constructor for an eventSource (in which you don't
92 // create a subclass), the default is also to use Self-Describing serialization.  In addition
93 // you can use the EventSoruce(EventSourceSettings) constructor to also explicitly specify
94 // Self-Describing serialization format.   These effect the WriteEvent* APIs going to ETW.  
95 //
96 // Note that none of this ETW serialization logic affects EventListeners.   Only the ETW listener.  
97 // 
98 // *************************************************************************************
99 // *** INTERNALS: Event Propagation
100 //
101 //   Data enters the system either though
102 //
103 // 1) A user defined method in the user defined subclass of EventSource which calls 
104 //     A) A typesafe type specific overload of WriteEvent(ID, ...)  e.g. WriteEvent(ID, string, string) 
105 //           * which calls into the unsafe WriteEventCore(ID COUNT EventData*) WriteEventWithRelatedActivityIdCore()
106 //     B) The typesafe overload WriteEvent(ID, object[])  which calls the private helper WriteEventVarargs(ID, Guid* object[])
107 //     C) Directly into the unsafe WriteEventCore(ID, COUNT EventData*) or WriteEventWithRelatedActivityIdCore()
108 //
109 //     All event data eventually flows to one of 
110 //        * WriteEventWithRelatedActivityIdCore(ID, Guid*, COUNT, EventData*) 
111 //        * WriteEventVarargs(ID, Guid*, object[])
112 //
113 // 2) A call to one of the overloads of Write<T>.   All these overloads end up in 
114 //        * WriteImpl<T>(EventName, Options, Data, Guid*, Guid*)
115 // 
116 // On output there are the following routines
117 //    Writing to all listeners that are NOT ETW, we have the following routines
118 //       * WriteToAllListeners(ID, Guid*, COUNT, EventData*) 
119 //       * WriteToAllListeners(ID, Guid*, object[])
120 //       * WriteToAllListeners(NAME, Guid*, EventPayload)
121 //
122 //       EventPayload is the internal type that implements the IDictionary<string, object> interface
123 //       The EventListeners will pass back for serialized classes for nested object, but  
124 //       WriteToAllListeners(NAME, Guid*, EventPayload) unpacks this uses the fields as if they
125 //       were parameters to a method.  
126 // 
127 //       The first two are used for the WriteEvent* case, and the later is used for the Write<T> case.  
128 // 
129 //    Writing to ETW, Manifest Based 
130 //          EventProvider.WriteEvent(EventDescriptor, Guid*, COUNT, EventData*)
131 //          EventProvider.WriteEvent(EventDescriptor, Guid*, object[])
132 //    Writing to ETW, Self-Describing format
133 //          WriteMultiMerge(NAME, Options, Types, EventData*)
134 //          WriteMultiMerge(NAME, Options, Types, object[])
135 //          WriteImpl<T> has logic that knows how to serialize (like WriteMultiMerge) but also knows 
136 //             will write it to 
137 //
138 //    All ETW writes eventually call
139 //      EventWriteTransfer (native PINVOKE wrapper)
140 //      EventWriteTransferWrapper (fixes compat problem if you pass null as the related activityID)
141 //         EventProvider.WriteEventRaw   - sets last error
142 //         EventSource.WriteEventRaw     - Does EventSource exception handling logic
143 //            WriteMultiMerge
144 //            WriteImpl<T>
145 //         EventProvider.WriteEvent(EventDescriptor, Guid*, COUNT, EventData*)
146 //         EventProvider.WriteEvent(EventDescriptor, Guid*, object[])
147 // 
148 // Serialization:  We have a bit of a hodge-podge of serializers right now.   Only the one for ETW knows
149 // how to deal with nested classes or arrays.   I will call this serializer the 'TypeInfo' serializer
150 // since it is the TraceLoggingTypeInfo structure that knows how to do this.   Effectively for a type you
151 // can call one of these 
152 //      WriteMetadata - transforms the type T into serialization meta data blob for that type
153 //      WriteObjectData - transforms an object of T into serialization meta data blob for that type
154 //      GetData - transforms an object of T into its deserialized form suitable for passing to EventListener. 
155 // The first two are used to serialize something for ETW.   The second one is used to transform the object 
156 // for use by the EventListener.    We also have a 'DecodeObject' method that will take a EventData* and
157 // deserialize to pass to an EventListener, but it only works on primitive types (types supported in version V4.5). 
158 // 
159 // It is an important observation that while EventSource does support users directly calling with EventData* 
160 // blobs, we ONLY support that for the primitive types (V4.5 level support).   Thus while there is a EventData*
161 // path through the system it is only for some types.  The object[] path is the more general (but less efficient) path.  
162 //
163 // TODO There is cleanup needed There should be no divergence until WriteEventRaw.  
164 // 
165 // TODO: We should have a single choke point (right now we always have this parallel EventData* and object[] path.   This 
166 // was historical (at one point we tried to pass object directly from EventSoruce to EventListener.  That was always 
167 // fragile and a compatibility headache, but we have finally been forced into the idea that there is always a transformation.
168 // This allows us to use the EventData* form to be the canonical data format in the low level APIs.  This also gives us the
169 // opportunity to expose this format to EventListeners in the future.   
170 // 
171 using System;
172 using System.Runtime.CompilerServices;
173 #if FEATURE_ACTIVITYSAMPLING
174 using System.Collections.Concurrent;
175 #endif
176 using System.Collections.Generic;
177 using System.Collections.ObjectModel;
178 using System.Diagnostics;
179 using System.Diagnostics.CodeAnalysis;
180 using System.Globalization;
181 using System.Reflection;
182 using System.Resources;
183 using System.Security;
184 #if !CORECLR && !ES_BUILD_PN
185 using System.Security.Permissions;
186 #endif // !CORECLR && !ES_BUILD_PN
187
188 using System.Text;
189 using System.Threading;
190 using Microsoft.Win32;
191
192 #if ES_BUILD_STANDALONE
193 using EventDescriptor = Microsoft.Diagnostics.Tracing.EventDescriptor;
194 #else
195 using System.Threading.Tasks;
196 #endif
197
198 using Microsoft.Reflection;
199
200 #if !ES_BUILD_AGAINST_DOTNET_V35
201 using Contract = System.Diagnostics.Contracts.Contract;
202 #else
203 using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
204 #endif
205
206 #if CORECLR || ES_BUILD_PN
207 using Internal.Runtime.Augments;
208 #endif
209
210 #if ES_BUILD_STANDALONE
211 namespace Microsoft.Diagnostics.Tracing
212 #else
213 namespace System.Diagnostics.Tracing
214 #endif
215 {
216     /// <summary>
217     /// This class is meant to be inherited by a user-defined event source in order to define a managed
218     /// ETW provider.   Please See DESIGN NOTES above for the internal architecture.  
219     /// The minimal definition of an EventSource simply specifies a number of ETW event methods that
220     /// call one of the EventSource.WriteEvent overloads, <see cref="EventSource.WriteEventCore"/>, 
221     /// or <see cref="EventSource.WriteEventWithRelatedActivityIdCore"/> to log them. This functionality 
222     /// is sufficient for many users.
223     /// <para>
224     /// To achieve more control over the ETW provider manifest exposed by the event source type, the 
225     /// [<see cref="EventAttribute"/>] attributes can be specified for the ETW event methods.
226     /// </para><para>
227     /// For very advanced EventSources, it is possible to intercept the commands being given to the
228     /// eventSource and change what filtering is done (see EventListener.EnableEvents and 
229     /// <see cref="EventListener.DisableEvents"/>) or cause actions to be performed by the eventSource, 
230     /// e.g. dumping a data structure (see EventSource.SendCommand and
231     /// <see cref="EventSource.OnEventCommand"/>).
232     /// </para><para>
233     /// The eventSources can be turned on with Windows ETW controllers (e.g. logman), immediately. 
234     /// It is also possible to control and intercept the data dispatcher programmatically.  See 
235     /// <see cref="EventListener"/> for more.
236     /// </para>
237     /// </summary>
238     /// <remarks>
239     /// This is a minimal definition for a custom event source:
240     /// <code>
241     /// [EventSource(Name="Samples-Demos-Minimal")]
242     /// sealed class MinimalEventSource : EventSource
243     /// {
244     ///     public static MinimalEventSource Log = new MinimalEventSource();
245     ///     public void Load(long ImageBase, string Name) { WriteEvent(1, ImageBase, Name); }
246     ///     public void Unload(long ImageBase) { WriteEvent(2, ImageBase); }
247     ///     private MinimalEventSource() {}
248     /// }
249     /// </code>
250     /// </remarks>
251     public partial class EventSource : IDisposable
252     {
253
254 #if FEATURE_EVENTSOURCE_XPLAT
255         private static readonly EventListener persistent_Xplat_Listener = XplatEventLogger.InitializePersistentListener();
256 #endif //FEATURE_EVENTSOURCE_XPLAT
257
258         /// <summary>
259         /// The human-friendly name of the eventSource.  It defaults to the simple name of the class
260         /// </summary>
261         public string Name { get { return m_name; } }
262         /// <summary>
263         /// Every eventSource is assigned a GUID to uniquely identify it to the system. 
264         /// </summary>
265         public Guid Guid { get { return m_guid; } }
266
267         /// <summary>
268         /// Returns true if the eventSource has been enabled at all. This is the prefered test
269         /// to be performed before a relatively expensive EventSource operation.
270         /// </summary>
271         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
272         public bool IsEnabled()
273         {
274             return m_eventSourceEnabled;
275         }
276
277         /// <summary>
278         /// Returns true if events with greater than or equal 'level' and have one of 'keywords' set are enabled. 
279         /// 
280         /// Note that the result of this function is only an approximation on whether a particular
281         /// event is active or not. It is only meant to be used as way of avoiding expensive
282         /// computation for logging when logging is not on, therefore it sometimes returns false
283         /// positives (but is always accurate when returning false).  EventSources are free to 
284         /// have additional filtering.    
285         /// </summary>
286         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
287         public bool IsEnabled(EventLevel level, EventKeywords keywords)
288         {
289             return IsEnabled(level, keywords, EventChannel.None);
290         }
291
292         /// <summary>
293         /// Returns true if events with greater than or equal 'level' and have one of 'keywords' set are enabled, or
294         /// if 'keywords' specifies a channel bit for a channel that is enabled.
295         /// 
296         /// Note that the result of this function only an approximation on whether a particular
297         /// event is active or not. It is only meant to be used as way of avoiding expensive
298         /// computation for logging when logging is not on, therefore it sometimes returns false
299         /// positives (but is always accurate when returning false).  EventSources are free to 
300         /// have additional filtering.    
301         /// </summary>
302         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
303         public bool IsEnabled(EventLevel level, EventKeywords keywords, EventChannel channel)
304         {
305             if (!m_eventSourceEnabled)
306                 return false;
307
308             if (!IsEnabledCommon(m_eventSourceEnabled, m_level, m_matchAnyKeyword, level, keywords, channel))
309                 return false;
310
311 #if !FEATURE_ACTIVITYSAMPLING
312
313             return true;
314
315 #else // FEATURE_ACTIVITYSAMPLING
316
317             return true;
318
319 #if OPTIMIZE_IS_ENABLED
320             //================================================================================
321             // 2013/03/06 - The code below is a possible optimization for IsEnabled(level, kwd)
322             //    in case activity tracing/sampling is enabled. The added complexity of this
323             //    code however weighs against having it "on" until we know it's really needed.
324             //    For now we'll have this #ifdef-ed out in case we see evidence this is needed.
325             //================================================================================            
326
327             // At this point we believe the event is enabled, however we now need to check
328             // if we filter because of activity 
329
330             // Optimization, all activity filters also register a delegate here, so if there 
331             // is no delegate, we know there are no activity filters, which means that there
332             // is no additional filtering, which means that we can return true immediately.  
333             if (s_activityDying == null)
334                 return true;
335
336             // if there's at least one legacy ETW listener we can't filter this
337             if (m_legacySessions != null && m_legacySessions.Count > 0)
338                 return true;
339
340             // if any event ID that triggers a new activity, or "transfers" activities
341             // is covered by 'keywords' we can't filter this
342             if (unchecked(((long)keywords & m_keywordTriggers)) != 0)
343                 return true;
344
345             // See if all listeners have activity filters that would block the event.
346             for (int perEventSourceSessionId = 0; perEventSourceSessionId < SessionMask.MAX; ++perEventSourceSessionId)
347             {
348                 EtwSession etwSession = m_etwSessionIdMap[perEventSourceSessionId];
349                 if (etwSession == null)
350                     continue;
351
352                 ActivityFilter activityFilter = etwSession.m_activityFilter;
353                 if (activityFilter == null || 
354                     ActivityFilter.GetFilter(activityFilter, this) == null)
355                 {
356                     // No activity filter for ETW, if event is active for ETW, we can't filter.  
357                     for (int i = 0; i < m_eventData.Length; i++)
358                         if (m_eventData[i].EnabledForETW)
359                             return true;
360                 }
361                 else if (ActivityFilter.IsCurrentActivityActive(activityFilter))
362                     return true;
363             }
364
365             // for regular event listeners
366             var curDispatcher = m_Dispatchers;
367             while (curDispatcher != null)
368             {
369                 ActivityFilter activityFilter = curDispatcher.m_Listener.m_activityFilter;
370                 if (activityFilter == null)
371                 {
372                     // See if any event is enabled.   
373                     for (int i = 0; i < curDispatcher.m_EventEnabled.Length; i++)
374                         if (curDispatcher.m_EventEnabled[i])
375                             return true;
376                 }
377                 else if (ActivityFilter.IsCurrentActivityActive(activityFilter))
378                     return true;
379                 curDispatcher = curDispatcher.m_Next;
380             }
381
382             // Every listener has an activity filter that is blocking writing the event, 
383             // thus the event is not enabled.  
384             return false;
385 #endif // OPTIMIZE_IS_ENABLED
386
387 #endif // FEATURE_ACTIVITYSAMPLING
388         }
389
390         /// <summary>
391         /// Returns the settings for the event source instance
392         /// </summary>
393         public EventSourceSettings Settings
394         {
395             get { return m_config; }
396         }
397
398         // Manifest support 
399         /// <summary>
400         /// Returns the GUID that uniquely identifies the eventSource defined by 'eventSourceType'.  
401         /// This API allows you to compute this without actually creating an instance of the EventSource.   
402         /// It only needs to reflect over the type.  
403         /// </summary>
404         public static Guid GetGuid(Type eventSourceType)
405         {
406             if (eventSourceType == null)
407                 throw new ArgumentNullException(nameof(eventSourceType));
408             Contract.EndContractBlock();
409
410             EventSourceAttribute attrib = (EventSourceAttribute)GetCustomAttributeHelper(eventSourceType, typeof(EventSourceAttribute));
411             string name = eventSourceType.Name;
412             if (attrib != null)
413             {
414                 if (attrib.Guid != null)
415                 {
416                     Guid g = Guid.Empty;
417 #if !ES_BUILD_AGAINST_DOTNET_V35
418                     if (Guid.TryParse(attrib.Guid, out g))
419                         return g;
420 #else
421                     try { return new Guid(attrib.Guid); }
422                     catch (Exception) { }
423 #endif
424                 }
425
426                 if (attrib.Name != null)
427                     name = attrib.Name;
428             }
429
430             if (name == null)
431             {
432                 throw new ArgumentException(Resources.GetResourceString("Argument_InvalidTypeName"), nameof(eventSourceType));
433             }
434             return GenerateGuidFromName(name.ToUpperInvariant());       // Make it case insensitive.  
435         }
436         /// <summary>
437         /// Returns the official ETW Provider name for the eventSource defined by 'eventSourceType'.  
438         /// This API allows you to compute this without actually creating an instance of the EventSource.   
439         /// It only needs to reflect over the type.  
440         /// </summary>
441         public static string GetName(Type eventSourceType)
442         {
443             return GetName(eventSourceType, EventManifestOptions.None);
444         }
445
446         /// <summary>
447         /// Returns a string of the XML manifest associated with the eventSourceType. The scheme for this XML is
448         /// documented at in EventManifest Schema http://msdn.microsoft.com/en-us/library/aa384043(VS.85).aspx.
449         /// This is the preferred way of generating a manifest to be embedded in the ETW stream as it is fast and
450         /// the fact that it only includes localized entries for the current UI culture is an acceptable tradeoff.
451         /// </summary>
452         /// <param name="eventSourceType">The type of the event source class for which the manifest is generated</param>
453         /// <param name="assemblyPathToIncludeInManifest">The manifest XML fragment contains the string name of the DLL name in
454         /// which it is embedded.  This parameter specifies what name will be used</param>
455         /// <returns>The XML data string</returns>
456         public static string GenerateManifest(Type eventSourceType, string assemblyPathToIncludeInManifest)
457         {
458             return GenerateManifest(eventSourceType, assemblyPathToIncludeInManifest, EventManifestOptions.None);
459         }
460         /// <summary>
461         /// Returns a string of the XML manifest associated with the eventSourceType. The scheme for this XML is
462         /// documented at in EventManifest Schema http://msdn.microsoft.com/en-us/library/aa384043(VS.85).aspx.
463         /// Pass EventManifestOptions.AllCultures when generating a manifest to be registered on the machine. This
464         /// ensures that the entries in the event log will be "optimally" localized.
465         /// </summary>
466         /// <param name="eventSourceType">The type of the event source class for which the manifest is generated</param>
467         /// <param name="assemblyPathToIncludeInManifest">The manifest XML fragment contains the string name of the DLL name in
468         /// which it is embedded.  This parameter specifies what name will be used</param>
469         /// <param name="flags">The flags to customize manifest generation. If flags has bit OnlyIfNeededForRegistration specified
470         /// this returns null when the eventSourceType does not require explicit registration</param>
471         /// <returns>The XML data string or null</returns>
472         public static string GenerateManifest(Type eventSourceType, string assemblyPathToIncludeInManifest, EventManifestOptions flags)
473         {
474             if (eventSourceType == null)
475                 throw new ArgumentNullException(nameof(eventSourceType));
476             Contract.EndContractBlock();
477
478             byte[] manifestBytes = EventSource.CreateManifestAndDescriptors(eventSourceType, assemblyPathToIncludeInManifest, null, flags);
479             return (manifestBytes == null) ? null : Encoding.UTF8.GetString(manifestBytes, 0, manifestBytes.Length);
480         }
481
482         // EventListener support
483         /// <summary>
484         /// returns a list (IEnumerable) of all sources in the appdomain).  EventListeners typically need this.  
485         /// </summary>
486         /// <returns></returns>
487         public static IEnumerable<EventSource> GetSources()
488         {
489             var ret = new List<EventSource>();
490             lock (EventListener.EventListenersLock)
491             {
492                 foreach (WeakReference eventSourceRef in EventListener.s_EventSources)
493                 {
494                     EventSource eventSource = eventSourceRef.Target as EventSource;
495                     if (eventSource != null && !eventSource.IsDisposed)
496                         ret.Add(eventSource);
497                 }
498             }
499             return ret;
500         }
501
502         /// <summary>
503         /// Send a command to a particular EventSource identified by 'eventSource'.
504         /// Calling this routine simply forwards the command to the EventSource.OnEventCommand
505         /// callback.  What the EventSource does with the command and its arguments are from 
506         /// that point EventSource-specific.  
507         /// </summary>
508         /// <param name="eventSource">The instance of EventSource to send the command to</param>
509         /// <param name="command">A positive user-defined EventCommand, or EventCommand.SendManifest</param>
510         /// <param name="commandArguments">A set of (name-argument, value-argument) pairs associated with the command</param>
511         public static void SendCommand(EventSource eventSource, EventCommand command, IDictionary<string, string> commandArguments)
512         {
513             if (eventSource == null)
514                 throw new ArgumentNullException(nameof(eventSource));
515
516             // User-defined EventCommands should not conflict with the reserved commands.
517             if ((int)command <= (int)EventCommand.Update && (int)command != (int)EventCommand.SendManifest)
518             {
519                 throw new ArgumentException(Resources.GetResourceString("EventSource_InvalidCommand"), nameof(command));
520             }
521
522             eventSource.SendCommand(null, 0, 0, command, true, EventLevel.LogAlways, EventKeywords.None, commandArguments);
523         }
524
525 #if !ES_BUILD_STANDALONE
526         /// <summary>
527         /// This property allows EventSource code to appropriately handle as "different" 
528         /// activities started on different threads that have not had an activity created on them.
529         /// </summary>
530         internal static Guid InternalCurrentThreadActivityId
531         {
532             get
533             {
534                 Guid retval = CurrentThreadActivityId;
535                 if (retval == Guid.Empty)
536                 {
537                     retval = FallbackActivityId;
538                 }
539                 return retval;
540             }
541         }
542
543         internal static Guid FallbackActivityId
544         {
545             get
546             {
547 #pragma warning disable 612, 618
548                 int threadID = AppDomain.GetCurrentThreadId();
549
550                 // Managed thread IDs are more aggressively re-used than native thread IDs,
551                 // so we'll use the latter...
552                 return new Guid(unchecked((uint)threadID),
553                                 unchecked((ushort)s_currentPid), unchecked((ushort)(s_currentPid >> 16)),
554                                 0x94, 0x1b, 0x87, 0xd5, 0xa6, 0x5c, 0x36, 0x64);
555 #pragma warning restore 612, 618
556             }
557         }
558 #endif // !ES_BUILD_STANDALONE
559
560         // Error APIs.  (We don't throw by default, but you can probe for status)
561         /// <summary>
562         /// Because
563         /// 
564         ///     1) Logging is often optional and thus should not generate fatal errors (exceptions)
565         ///     2) EventSources are often initialized in class constructors (which propagate exceptions poorly)
566         ///     
567         /// The event source constructor does not throw exceptions.  Instead we remember any exception that 
568         /// was generated (it is also logged to Trace.WriteLine).
569         /// </summary>
570         public Exception ConstructionException { get { return m_constructionException; } }
571
572         /// <summary>
573         /// EventSources can have arbitrary string key-value pairs associated with them called Traits.  
574         /// These traits are not interpreted by the EventSource but may be interpreted by EventListeners
575         /// (e.g. like the built in ETW listener).   These traits are specififed at EventSource 
576         /// construction time and can be retrieved by using this GetTrait API.  
577         /// </summary>
578         /// <param name="key">The key to look up in the set of key-value pairs passed to the EventSource constructor</param>
579         /// <returns>The value string associated iwth key.  Will return null if there is no such key.</returns>
580         public string GetTrait(string key)
581         {
582             if (m_traits != null)
583             {
584                 for (int i = 0; i < m_traits.Length - 1; i += 2)
585                 {
586                     if (m_traits[i] == key)
587                         return m_traits[i + 1];
588                 }
589             }
590             return null;
591         }
592
593         /// <summary>
594         /// Displays the name and GUID for the eventSource for debugging purposes.  
595         /// </summary>
596         public override string ToString()
597         {
598             return Resources.GetResourceString("EventSource_ToString", Name, Guid);
599         }
600
601         /// <summary>
602         /// Fires when a Command (e.g. Enable) comes from a an EventListener.  
603         /// </summary>
604         public event EventHandler<EventCommandEventArgs> EventCommandExecuted
605         {
606             add
607             {
608                 m_eventCommandExecuted += value;
609
610                 // If we have an EventHandler<EventCommandEventArgs> attached to the EventSource before the first command arrives
611                 // It should get a chance to handle the deferred commands.
612                 EventCommandEventArgs deferredCommands = m_deferredCommands;
613                 while (deferredCommands != null)
614                 {
615                     value(this, deferredCommands);
616                     deferredCommands = deferredCommands.nextCommand;
617                 }
618             }
619             remove
620             {
621                 m_eventCommandExecuted -= value;
622             }
623         }
624
625         #region protected
626         /// <summary>
627         /// This is the constructor that most users will use to create their eventSource.   It takes 
628         /// no parameters.  The ETW provider name and GUID of the EventSource are determined by the EventSource 
629         /// custom attribute (so you can determine these things declaratively).   If the GUID for the eventSource
630         /// is not specified in the EventSourceAttribute (recommended), it is Generated by hashing the name.
631         /// If the ETW provider name of the EventSource is not given, the name of the EventSource class is used as
632         /// the ETW provider name.
633         /// </summary>
634         protected EventSource()
635             : this(EventSourceSettings.EtwManifestEventFormat)
636         {
637         }
638
639         /// <summary>
640         /// By default calling the 'WriteEvent' methods do NOT throw on errors (they silently discard the event).  
641         /// This is because in most cases users assume logging is not 'precious' and do NOT wish to have logging failures
642         /// crash the program. However for those applications where logging is 'precious' and if it fails the caller
643         /// wishes to react, setting 'throwOnEventWriteErrors' will cause an exception to be thrown if WriteEvent
644         /// fails. Note the fact that EventWrite succeeds does not necessarily mean that the event reached its destination
645         /// only that operation of writing it did not fail. These EventSources will not generate self-describing ETW events.
646         /// 
647         /// For compatibility only use the EventSourceSettings.ThrowOnEventWriteErrors flag instead.  
648         /// </summary>
649         // [Obsolete("Use the EventSource(EventSourceSettings) overload")]
650         protected EventSource(bool throwOnEventWriteErrors)
651             : this(EventSourceSettings.EtwManifestEventFormat | (throwOnEventWriteErrors ? EventSourceSettings.ThrowOnEventWriteErrors : 0))
652         { }
653
654         /// <summary>
655         /// Construct an EventSource with additional non-default settings (see EventSourceSettings for more)  
656         /// </summary>
657         protected EventSource(EventSourceSettings settings) : this(settings, null) { }
658
659         /// <summary>
660         /// Construct an EventSource with additional non-default settings.  
661         /// 
662         /// Also specify a list of key-value pairs called traits (you must pass an even number of strings).   
663         /// The first string is the key and the second is the value.   These are not interpreted by EventSource
664         /// itself but may be interprated the listeners.  Can be fetched with GetTrait(string).   
665         /// </summary>
666         /// <param name="settings">See EventSourceSettings for more.</param>
667         /// <param name="traits">A collection of key-value strings (must be an even number).</param>
668         protected EventSource(EventSourceSettings settings, params string[] traits)
669         {
670             m_config = ValidateSettings(settings);
671
672             Guid eventSourceGuid;
673             string eventSourceName;
674
675             EventMetadata[] eventDescriptors;
676             byte[] manifest;
677             GetMetadata(out eventSourceGuid, out eventSourceName, out eventDescriptors, out manifest);
678
679             if (eventSourceGuid.Equals(Guid.Empty) || eventSourceName == null)
680             {
681                 var myType = this.GetType();
682                 eventSourceGuid = GetGuid(myType);
683                 eventSourceName = GetName(myType);
684             }
685
686             Initialize(eventSourceGuid, eventSourceName, traits);
687         }
688
689         internal virtual void GetMetadata(out Guid eventSourceGuid, out string eventSourceName, out EventMetadata[] eventData, out byte[] manifestBytes)
690         {
691             //
692             // In ProjectN subclasses need to override this method, and return the data from their EventSourceAttribute and EventAttribute annotations.
693             // On other architectures it is a no-op.
694             //
695             // eventDescriptors needs to contain one EventDescriptor for each event; the event's ID should be the same as its index in this array.
696             // manifestBytes is a UTF-8 encoding of the ETW manifest for the type.
697             //
698             // 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.
699             //
700             eventSourceGuid = Guid.Empty;
701             eventSourceName = null;
702             eventData = null;
703             manifestBytes = null;
704
705             return;
706         }
707
708         /// <summary>
709         /// This method is called when the eventSource is updated by the controller.  
710         /// </summary>
711         protected virtual void OnEventCommand(EventCommandEventArgs command) { }
712
713 #pragma warning disable 1591
714         // optimized for common signatures (no args)
715         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
716         protected unsafe void WriteEvent(int eventId)
717         {
718             WriteEventCore(eventId, 0, null);
719         }
720
721         // optimized for common signatures (ints)
722         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
723         protected unsafe void WriteEvent(int eventId, int arg1)
724         {
725             if (m_eventSourceEnabled)
726             {
727                 EventSource.EventData* descrs = stackalloc EventSource.EventData[1];
728                 descrs[0].DataPointer = (IntPtr)(&arg1);
729                 descrs[0].Size = 4;
730                 WriteEventCore(eventId, 1, descrs);
731             }
732         }
733
734         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
735         protected unsafe void WriteEvent(int eventId, int arg1, int arg2)
736         {
737             if (m_eventSourceEnabled)
738             {
739                 EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
740                 descrs[0].DataPointer = (IntPtr)(&arg1);
741                 descrs[0].Size = 4;
742                 descrs[1].DataPointer = (IntPtr)(&arg2);
743                 descrs[1].Size = 4;
744                 WriteEventCore(eventId, 2, descrs);
745             }
746         }
747
748         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
749         protected unsafe void WriteEvent(int eventId, int arg1, int arg2, int arg3)
750         {
751             if (m_eventSourceEnabled)
752             {
753                 EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
754                 descrs[0].DataPointer = (IntPtr)(&arg1);
755                 descrs[0].Size = 4;
756                 descrs[1].DataPointer = (IntPtr)(&arg2);
757                 descrs[1].Size = 4;
758                 descrs[2].DataPointer = (IntPtr)(&arg3);
759                 descrs[2].Size = 4;
760                 WriteEventCore(eventId, 3, descrs);
761             }
762         }
763
764         // optimized for common signatures (longs)
765         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
766         protected unsafe void WriteEvent(int eventId, long arg1)
767         {
768             if (m_eventSourceEnabled)
769             {
770                 EventSource.EventData* descrs = stackalloc EventSource.EventData[1];
771                 descrs[0].DataPointer = (IntPtr)(&arg1);
772                 descrs[0].Size = 8;
773                 WriteEventCore(eventId, 1, descrs);
774             }
775         }
776
777         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
778         protected unsafe void WriteEvent(int eventId, long arg1, long arg2)
779         {
780             if (m_eventSourceEnabled)
781             {
782                 EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
783                 descrs[0].DataPointer = (IntPtr)(&arg1);
784                 descrs[0].Size = 8;
785                 descrs[1].DataPointer = (IntPtr)(&arg2);
786                 descrs[1].Size = 8;
787                 WriteEventCore(eventId, 2, descrs);
788             }
789         }
790
791         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
792         protected unsafe void WriteEvent(int eventId, long arg1, long arg2, long arg3)
793         {
794             if (m_eventSourceEnabled)
795             {
796                 EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
797                 descrs[0].DataPointer = (IntPtr)(&arg1);
798                 descrs[0].Size = 8;
799                 descrs[1].DataPointer = (IntPtr)(&arg2);
800                 descrs[1].Size = 8;
801                 descrs[2].DataPointer = (IntPtr)(&arg3);
802                 descrs[2].Size = 8;
803                 WriteEventCore(eventId, 3, descrs);
804             }
805         }
806
807         // optimized for common signatures (strings)
808         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
809         protected unsafe void WriteEvent(int eventId, string arg1)
810         {
811             if (m_eventSourceEnabled)
812             {
813                 if (arg1 == null) arg1 = "";
814                 fixed (char* string1Bytes = arg1)
815                 {
816                     EventSource.EventData* descrs = stackalloc EventSource.EventData[1];
817                     descrs[0].DataPointer = (IntPtr)string1Bytes;
818                     descrs[0].Size = ((arg1.Length + 1) * 2);
819                     WriteEventCore(eventId, 1, descrs);
820                 }
821             }
822         }
823
824         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
825         protected unsafe void WriteEvent(int eventId, string arg1, string arg2)
826         {
827             if (m_eventSourceEnabled)
828             {
829                 if (arg1 == null) arg1 = "";
830                 if (arg2 == null) arg2 = "";
831                 fixed (char* string1Bytes = arg1)
832                 fixed (char* string2Bytes = arg2)
833                 {
834                     EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
835                     descrs[0].DataPointer = (IntPtr)string1Bytes;
836                     descrs[0].Size = ((arg1.Length + 1) * 2);
837                     descrs[1].DataPointer = (IntPtr)string2Bytes;
838                     descrs[1].Size = ((arg2.Length + 1) * 2);
839                     WriteEventCore(eventId, 2, descrs);
840                 }
841             }
842         }
843
844         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
845         protected unsafe void WriteEvent(int eventId, string arg1, string arg2, string arg3)
846         {
847             if (m_eventSourceEnabled)
848             {
849                 if (arg1 == null) arg1 = "";
850                 if (arg2 == null) arg2 = "";
851                 if (arg3 == null) arg3 = "";
852                 fixed (char* string1Bytes = arg1)
853                 fixed (char* string2Bytes = arg2)
854                 fixed (char* string3Bytes = arg3)
855                 {
856                     EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
857                     descrs[0].DataPointer = (IntPtr)string1Bytes;
858                     descrs[0].Size = ((arg1.Length + 1) * 2);
859                     descrs[1].DataPointer = (IntPtr)string2Bytes;
860                     descrs[1].Size = ((arg2.Length + 1) * 2);
861                     descrs[2].DataPointer = (IntPtr)string3Bytes;
862                     descrs[2].Size = ((arg3.Length + 1) * 2);
863                     WriteEventCore(eventId, 3, descrs);
864                 }
865             }
866         }
867
868         // optimized for common signatures (string and ints)
869         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
870         protected unsafe void WriteEvent(int eventId, string arg1, int arg2)
871         {
872             if (m_eventSourceEnabled)
873             {
874                 if (arg1 == null) arg1 = "";
875                 fixed (char* string1Bytes = arg1)
876                 {
877                     EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
878                     descrs[0].DataPointer = (IntPtr)string1Bytes;
879                     descrs[0].Size = ((arg1.Length + 1) * 2);
880                     descrs[1].DataPointer = (IntPtr)(&arg2);
881                     descrs[1].Size = 4;
882                     WriteEventCore(eventId, 2, descrs);
883                 }
884             }
885         }
886
887         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
888         protected unsafe void WriteEvent(int eventId, string arg1, int arg2, int arg3)
889         {
890             if (m_eventSourceEnabled)
891             {
892                 if (arg1 == null) arg1 = "";
893                 fixed (char* string1Bytes = arg1)
894                 {
895                     EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
896                     descrs[0].DataPointer = (IntPtr)string1Bytes;
897                     descrs[0].Size = ((arg1.Length + 1) * 2);
898                     descrs[1].DataPointer = (IntPtr)(&arg2);
899                     descrs[1].Size = 4;
900                     descrs[2].DataPointer = (IntPtr)(&arg3);
901                     descrs[2].Size = 4;
902                     WriteEventCore(eventId, 3, descrs);
903                 }
904             }
905         }
906
907         // optimized for common signatures (string and longs)
908         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
909         protected unsafe void WriteEvent(int eventId, string arg1, long arg2)
910         {
911             if (m_eventSourceEnabled)
912             {
913                 if (arg1 == null) arg1 = "";
914                 fixed (char* string1Bytes = arg1)
915                 {
916                     EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
917                     descrs[0].DataPointer = (IntPtr)string1Bytes;
918                     descrs[0].Size = ((arg1.Length + 1) * 2);
919                     descrs[1].DataPointer = (IntPtr)(&arg2);
920                     descrs[1].Size = 8;
921                     WriteEventCore(eventId, 2, descrs);
922                 }
923             }
924         }
925
926         // optimized for common signatures (long and string)
927         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
928         protected unsafe void WriteEvent(int eventId, long arg1, string arg2)
929         {
930             if (m_eventSourceEnabled)
931             {
932                 if (arg2 == null) arg2 = "";
933                 fixed (char* string2Bytes = arg2)
934                 {
935                     EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
936                     descrs[0].DataPointer = (IntPtr)(&arg1);
937                     descrs[0].Size = 8;
938                     descrs[1].DataPointer = (IntPtr)string2Bytes;
939                     descrs[1].Size = ((arg2.Length + 1) * 2);
940                     WriteEventCore(eventId, 2, descrs);
941                 }
942             }
943         }
944
945         // optimized for common signatures (int and string)
946         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
947         protected unsafe void WriteEvent(int eventId, int arg1, string arg2)
948         {
949             if (m_eventSourceEnabled)
950             {
951                 if (arg2 == null) arg2 = "";
952                 fixed (char* string2Bytes = arg2)
953                 {
954                     EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
955                     descrs[0].DataPointer = (IntPtr)(&arg1);
956                     descrs[0].Size = 4;
957                     descrs[1].DataPointer = (IntPtr)string2Bytes;
958                     descrs[1].Size = ((arg2.Length + 1) * 2);
959                     WriteEventCore(eventId, 2, descrs);
960                 }
961             }
962         }
963
964         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
965         protected unsafe void WriteEvent(int eventId, byte[] arg1)
966         {
967             if (m_eventSourceEnabled)
968             {
969                 EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
970                 if (arg1 == null || arg1.Length == 0)
971                 {
972                     int blobSize = 0;
973                     descrs[0].DataPointer = (IntPtr)(&blobSize);
974                     descrs[0].Size = 4;
975                     descrs[1].DataPointer = (IntPtr)(&blobSize); // valid address instead of empty content 
976                     descrs[1].Size = 0;
977                     WriteEventCore(eventId, 2, descrs);
978                 }
979                 else
980                 {
981                     int blobSize = arg1.Length;
982                     fixed (byte* blob = &arg1[0])
983                     {
984                         descrs[0].DataPointer = (IntPtr)(&blobSize);
985                         descrs[0].Size = 4;
986                         descrs[1].DataPointer = (IntPtr)blob;
987                         descrs[1].Size = blobSize;
988                         WriteEventCore(eventId, 2, descrs);
989                     }
990                 }
991             }
992         }
993
994         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
995         protected unsafe void WriteEvent(int eventId, long arg1, byte[] arg2)
996         {
997             if (m_eventSourceEnabled)
998             {
999                 EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
1000                 descrs[0].DataPointer = (IntPtr)(&arg1);
1001                 descrs[0].Size = 8;
1002                 if (arg2 == null || arg2.Length == 0)
1003                 {
1004                     int blobSize = 0;
1005                     descrs[1].DataPointer = (IntPtr)(&blobSize);
1006                     descrs[1].Size = 4;
1007                     descrs[2].DataPointer = (IntPtr)(&blobSize); // valid address instead of empty contents 
1008                     descrs[2].Size = 0;
1009                     WriteEventCore(eventId, 3, descrs);
1010                 }
1011                 else
1012                 {
1013                     int blobSize = arg2.Length;
1014                     fixed (byte* blob = &arg2[0])
1015                     {
1016                         descrs[1].DataPointer = (IntPtr)(&blobSize);
1017                         descrs[1].Size = 4;
1018                         descrs[2].DataPointer = (IntPtr)blob;
1019                         descrs[2].Size = blobSize;
1020                         WriteEventCore(eventId, 3, descrs);
1021                     }
1022                 }
1023             }
1024         }
1025
1026 #pragma warning restore 1591
1027
1028         /// <summary>
1029         /// Used to construct the data structure to be passed to the native ETW APIs - EventWrite and EventWriteTransfer.
1030         /// </summary>
1031         protected internal struct EventData
1032         {
1033             /// <summary>
1034             /// Address where the one argument lives (if this points to managed memory you must ensure the
1035             /// managed object is pinned.
1036             /// </summary>
1037             public IntPtr DataPointer { get { return (IntPtr)m_Ptr; } set { m_Ptr = unchecked((long)value); } }
1038             /// <summary>
1039             /// Size of the argument referenced by DataPointer
1040             /// </summary>
1041             public int Size { get { return m_Size; } set { m_Size = value; } }
1042
1043             #region private
1044             /// <summary>
1045             /// Initializes the members of this EventData object to point at a previously-pinned
1046             /// tracelogging-compatible metadata blob.
1047             /// </summary>
1048             /// <param name="pointer">Pinned tracelogging-compatible metadata blob.</param>
1049             /// <param name="size">The size of the metadata blob.</param>
1050             /// <param name="reserved">Value for reserved: 2 for per-provider metadata, 1 for per-event metadata</param>
1051             internal unsafe void SetMetadata(byte* pointer, int size, int reserved)
1052             {
1053                 this.m_Ptr = (long)(ulong)(UIntPtr)pointer;
1054                 this.m_Size = size;
1055                 this.m_Reserved = reserved; // Mark this descriptor as containing tracelogging-compatible metadata.
1056             }
1057
1058             //Important, we pass this structure directly to the Win32 EventWrite API, so this structure must be layed out exactly
1059             // the way EventWrite wants it.  
1060             internal long m_Ptr;
1061             internal int m_Size;
1062 #pragma warning disable 0649
1063             internal int m_Reserved;       // Used to pad the size to match the Win32 API
1064 #pragma warning restore 0649
1065             #endregion
1066         }
1067
1068         /// <summary>
1069         /// This routine allows you to create efficient WriteEvent helpers, however the code that you use to
1070         /// do this, while straightforward, is unsafe.
1071         /// </summary>
1072         /// <remarks>
1073         /// <code>
1074         ///    protected unsafe void WriteEvent(int eventId, string arg1, long arg2)
1075         ///    {
1076         ///        if (IsEnabled())
1077         ///        {
1078         ///            if (arg2 == null) arg2 = "";
1079         ///            fixed (char* string2Bytes = arg2)
1080         ///            {
1081         ///                EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
1082         ///                descrs[0].DataPointer = (IntPtr)(&amp;arg1);
1083         ///                descrs[0].Size = 8;
1084         ///                descrs[1].DataPointer = (IntPtr)string2Bytes;
1085         ///                descrs[1].Size = ((arg2.Length + 1) * 2);
1086         ///                WriteEventCore(eventId, 2, descrs);
1087         ///            }
1088         ///        }
1089         ///    }
1090         /// </code>
1091         /// </remarks>
1092         [CLSCompliant(false)]
1093         protected unsafe void WriteEventCore(int eventId, int eventDataCount, EventSource.EventData* data)
1094         {
1095             WriteEventWithRelatedActivityIdCore(eventId, null, eventDataCount, data);
1096         }
1097
1098         /// <summary>
1099         /// This routine allows you to create efficient WriteEventWithRelatedActivityId helpers, however the code 
1100         /// that you use to do this, while straightforward, is unsafe. The only difference from
1101         /// <see cref="WriteEventCore"/> is that you pass the relatedActivityId from caller through to this API
1102         /// </summary>
1103         /// <remarks>
1104         /// <code>
1105         ///    protected unsafe void WriteEventWithRelatedActivityId(int eventId, Guid relatedActivityId, string arg1, long arg2)
1106         ///    {
1107         ///        if (IsEnabled())
1108         ///        {
1109         ///            if (arg2 == null) arg2 = "";
1110         ///            fixed (char* string2Bytes = arg2)
1111         ///            {
1112         ///                EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
1113         ///                descrs[0].DataPointer = (IntPtr)(&amp;arg1);
1114         ///                descrs[0].Size = 8;
1115         ///                descrs[1].DataPointer = (IntPtr)string2Bytes;
1116         ///                descrs[1].Size = ((arg2.Length + 1) * 2);
1117         ///                WriteEventWithRelatedActivityIdCore(eventId, relatedActivityId, 2, descrs);
1118         ///            }
1119         ///        }
1120         ///    }
1121         /// </code>
1122         /// </remarks>
1123         [CLSCompliant(false)]
1124         protected unsafe void WriteEventWithRelatedActivityIdCore(int eventId, Guid* relatedActivityId, int eventDataCount, EventSource.EventData* data)
1125         {
1126             if (m_eventSourceEnabled)
1127             {
1128                 try
1129                 {
1130                     Debug.Assert(m_eventData != null);  // You must have initialized this if you enabled the source.
1131                     if (relatedActivityId != null)
1132                         ValidateEventOpcodeForTransfer(ref m_eventData[eventId], m_eventData[eventId].Name);
1133
1134                     EventOpcode opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode;
1135                     EventActivityOptions activityOptions = m_eventData[eventId].ActivityOptions;
1136                     Guid* pActivityId = null;
1137                     Guid activityId = Guid.Empty;
1138                     Guid relActivityId = Guid.Empty;
1139
1140                     if (opcode != EventOpcode.Info && relatedActivityId == null &&
1141                        ((activityOptions & EventActivityOptions.Disable) == 0))
1142                     {
1143                         if (opcode == EventOpcode.Start)
1144                         {
1145                             m_activityTracker.OnStart(m_name, m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Task, ref activityId, ref relActivityId, m_eventData[eventId].ActivityOptions);
1146                         }
1147                         else if (opcode == EventOpcode.Stop)
1148                         {
1149                             m_activityTracker.OnStop(m_name, m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Task, ref activityId);
1150                         }
1151
1152                         if (activityId != Guid.Empty)
1153                             pActivityId = &activityId;
1154                         if (relActivityId != Guid.Empty)
1155                             relatedActivityId = &relActivityId;
1156                     }
1157
1158 #if FEATURE_MANAGED_ETW
1159                     if (m_eventData[eventId].EnabledForETW)
1160                     {
1161
1162 #if FEATURE_ACTIVITYSAMPLING
1163                         // this code should be kept in sync with WriteEventVarargs().
1164                         SessionMask etwSessions = SessionMask.All;
1165                         // only compute etwSessions if there are *any* ETW filters enabled...
1166                         if ((ulong)m_curLiveSessions != 0)
1167                             etwSessions = GetEtwSessionMask(eventId, relatedActivityId);
1168                         // OutputDebugString(string.Format("{0}.WriteEvent(id {1}) -> to sessions {2:x}", 
1169                         //                   m_name, m_eventData[eventId].Name, (ulong) etwSessions));
1170
1171                         if ((ulong)etwSessions != 0 || m_legacySessions != null && m_legacySessions.Count > 0)
1172                         {
1173                             if (!SelfDescribingEvents)
1174                             {
1175                                 if (etwSessions.IsEqualOrSupersetOf(m_curLiveSessions))
1176                                 {
1177                                     // OutputDebugString(string.Format("  (1) id {0}, kwd {1:x}", 
1178                                     //                   m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Keywords));
1179                                     // by default the Descriptor.Keyword will have the perEventSourceSessionId bit 
1180                                     // mask set to 0x0f so, when all ETW sessions want the event we don't need to 
1181                                     // synthesize a new one
1182                                     if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
1183                                         ThrowEventSourceException(m_eventData[eventId].Name);
1184                                 }
1185                                 else
1186                                 {
1187                                     long origKwd = unchecked((long)((ulong)m_eventData[eventId].Descriptor.Keywords & ~(SessionMask.All.ToEventKeywords())));
1188                                     // OutputDebugString(string.Format("  (2) id {0}, kwd {1:x}", 
1189                                     //                   m_eventData[eventId].Name, etwSessions.ToEventKeywords() | (ulong) origKwd));
1190                                     // only some of the ETW sessions will receive this event. Synthesize a new
1191                                     // Descriptor whose Keywords field will have the appropriate bits set.
1192                                     // etwSessions might be 0, if there are legacy ETW listeners that want this event
1193                                     var desc = new EventDescriptor(
1194                                         m_eventData[eventId].Descriptor.EventId,
1195                                         m_eventData[eventId].Descriptor.Version,
1196                                         m_eventData[eventId].Descriptor.Channel,
1197                                         m_eventData[eventId].Descriptor.Level,
1198                                         m_eventData[eventId].Descriptor.Opcode,
1199                                         m_eventData[eventId].Descriptor.Task,
1200                                         unchecked((long)etwSessions.ToEventKeywords() | origKwd));
1201
1202                                     if (!m_provider.WriteEvent(ref desc, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
1203                                         ThrowEventSourceException(m_eventData[eventId].Name);
1204                                 }
1205                             }
1206                             else
1207                             {
1208                                 TraceLoggingEventTypes tlet = m_eventData[eventId].TraceLoggingEventTypes;
1209                                 if (tlet == null)
1210                                 {
1211                                     tlet = new TraceLoggingEventTypes(m_eventData[eventId].Name,
1212                                                                             EventTags.None,
1213                                                                         m_eventData[eventId].Parameters);
1214                                     Interlocked.CompareExchange(ref m_eventData[eventId].TraceLoggingEventTypes, tlet, null);
1215
1216                                 }
1217                                 long origKwd = unchecked((long)((ulong)m_eventData[eventId].Descriptor.Keywords & ~(SessionMask.All.ToEventKeywords())));
1218                                 // TODO: activity ID support
1219                                 EventSourceOptions opt = new EventSourceOptions
1220                                 {
1221                                     Keywords = (EventKeywords)unchecked((long)etwSessions.ToEventKeywords() | origKwd),
1222                                     Level = (EventLevel)m_eventData[eventId].Descriptor.Level,
1223                                     Opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode
1224                                 };
1225
1226                                 WriteMultiMerge(m_eventData[eventId].Name, ref opt, tlet, pActivityId, relatedActivityId, data);
1227                             }
1228                         }
1229 #else
1230                         if (!SelfDescribingEvents)
1231                         {
1232                             if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
1233                                 ThrowEventSourceException(m_eventData[eventId].Name);
1234                         }
1235                         else
1236                         {
1237                             TraceLoggingEventTypes tlet = m_eventData[eventId].TraceLoggingEventTypes;
1238                             if (tlet == null)
1239                             {
1240                                 tlet = new TraceLoggingEventTypes(m_eventData[eventId].Name,
1241                                                                     m_eventData[eventId].Tags,
1242                                                                     m_eventData[eventId].Parameters);
1243                                 Interlocked.CompareExchange(ref m_eventData[eventId].TraceLoggingEventTypes, tlet, null);
1244
1245                             }
1246                             EventSourceOptions opt = new EventSourceOptions
1247                             {
1248                                 Keywords = (EventKeywords)m_eventData[eventId].Descriptor.Keywords,
1249                                 Level = (EventLevel)m_eventData[eventId].Descriptor.Level,
1250                                 Opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode
1251                             };
1252
1253                             WriteMultiMerge(m_eventData[eventId].Name, ref opt, tlet, pActivityId, relatedActivityId, data);
1254                         }
1255 #endif // FEATURE_ACTIVITYSAMPLING
1256                     }
1257 #endif // FEATURE_MANAGED_ETW
1258
1259                     if (m_Dispatchers != null && m_eventData[eventId].EnabledForAnyListener)
1260                         WriteToAllListeners(eventId, relatedActivityId, eventDataCount, data);
1261                 }
1262                 catch (Exception ex)
1263                 {
1264                     if (ex is EventSourceException)
1265                         throw;
1266                     else
1267                         ThrowEventSourceException(m_eventData[eventId].Name, ex);
1268                 }
1269             }
1270         }
1271
1272         // fallback varags helpers. 
1273         /// <summary>
1274         /// This is the varargs helper for writing an event. It does create an array and box all the arguments so it is
1275         /// relatively inefficient and should only be used for relatively rare events (e.g. less than 100 / sec). If your
1276         /// rates are faster than that you should use <see cref="WriteEventCore"/> to create fast helpers for your particular 
1277         /// method signature. Even if you use this for rare events, this call should be guarded by an <see cref="IsEnabled()"/> 
1278         /// check so that the varargs call is not made when the EventSource is not active.  
1279         /// </summary>
1280         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
1281         protected unsafe void WriteEvent(int eventId, params object[] args)
1282         {
1283             WriteEventVarargs(eventId, null, args);
1284         }
1285
1286         /// <summary>
1287         /// This is the varargs helper for writing an event which also specifies a related activity. It is completely analogous
1288         /// to corresponding WriteEvent (they share implementation). It does create an array and box all the arguments so it is
1289         /// relatively inefficient and should only be used for relatively rare events (e.g. less than 100 / sec).  If your
1290         /// rates are faster than that you should use <see cref="WriteEventWithRelatedActivityIdCore"/> to create fast helpers for your 
1291         /// particular method signature. Even if you use this for rare events, this call should be guarded by an <see cref="IsEnabled()"/>
1292         /// check so that the varargs call is not made when the EventSource is not active.
1293         /// </summary>
1294         protected unsafe void WriteEventWithRelatedActivityId(int eventId, Guid relatedActivityId, params object[] args)
1295         {
1296             WriteEventVarargs(eventId, &relatedActivityId, args);
1297         }
1298
1299         #endregion
1300
1301         #region IDisposable Members
1302         /// <summary>
1303         /// Disposes of an EventSource.
1304         /// </summary>
1305         public void Dispose()
1306         {
1307             this.Dispose(true);
1308             GC.SuppressFinalize(this);
1309         }
1310         /// <summary>
1311         /// Disposes of an EventSource.
1312         /// </summary>
1313         /// <remarks>
1314         /// Called from Dispose() with disposing=true, and from the finalizer (~EventSource) with disposing=false.
1315         /// Guidelines:
1316         /// 1. We may be called more than once: do nothing after the first call.
1317         /// 2. Avoid throwing exceptions if disposing is false, i.e. if we're being finalized.
1318         /// </remarks>
1319         /// <param name="disposing">True if called from Dispose(), false if called from the finalizer.</param>
1320         protected virtual void Dispose(bool disposing)
1321         {
1322             if (disposing)
1323             {
1324 #if FEATURE_MANAGED_ETW
1325                 // Send the manifest one more time to ensure circular buffers have a chance to get to this information
1326                 // even in scenarios with a high volume of ETW events.
1327                 if (m_eventSourceEnabled)
1328                 {
1329                     try
1330                     {
1331                         SendManifest(m_rawManifest);
1332                     }
1333                     catch (Exception)
1334                     { }           // If it fails, simply give up.   
1335                     m_eventSourceEnabled = false;
1336                 }
1337                 if (m_provider != null)
1338                 {
1339                     m_provider.Dispose();
1340                     m_provider = null;
1341                 }
1342 #endif
1343             }
1344             m_eventSourceEnabled = false;
1345             m_eventSourceDisposed = true;
1346         }
1347         /// <summary>
1348         /// Finalizer for EventSource
1349         /// </summary>
1350         ~EventSource()
1351         {
1352             this.Dispose(false);
1353         }
1354         #endregion
1355
1356         #region private
1357 #if FEATURE_ACTIVITYSAMPLING
1358         internal void WriteStringToListener(EventListener listener, string msg, SessionMask m)
1359         {
1360             Debug.Assert(listener == null || (uint)m == (uint)SessionMask.FromId(0));
1361
1362             if (m_eventSourceEnabled)
1363             {
1364                 if (listener == null)
1365                 {
1366                     WriteEventString(0, unchecked((long)m.ToEventKeywords()), msg);
1367                 }
1368                 else
1369                 {
1370                     EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this);
1371                     eventCallbackArgs.EventId = 0;
1372                     eventCallbackArgs.Message = msg;
1373                     eventCallbackArgs.Payload = new ReadOnlyCollection<object>(new List<object>() { msg });
1374                     eventCallbackArgs.PayloadNames = new ReadOnlyCollection<string>(new List<string> { "message" });
1375                     eventCallbackArgs.EventName = "EventSourceMessage";
1376                     listener.OnEventWritten(eventCallbackArgs);
1377                 }
1378             }
1379         }
1380 #endif
1381
1382         private unsafe void WriteEventRaw(
1383             string eventName,
1384             ref EventDescriptor eventDescriptor,
1385             Guid* activityID,
1386             Guid* relatedActivityID,
1387             int dataCount,
1388             IntPtr data)
1389         {
1390 #if FEATURE_MANAGED_ETW
1391             if (m_provider == null)
1392             {
1393                 ThrowEventSourceException(eventName);
1394             }
1395             else
1396             {
1397                 if (!m_provider.WriteEventRaw(ref eventDescriptor, activityID, relatedActivityID, dataCount, data))
1398                     ThrowEventSourceException(eventName);
1399             }
1400 #endif // FEATURE_MANAGED_ETW
1401         }
1402
1403         // FrameworkEventSource is on the startup path for the framework, so we have this internal overload that it can use
1404         // to prevent the working set hit from looking at the custom attributes on the type to get the Guid.
1405         internal EventSource(Guid eventSourceGuid, string eventSourceName)
1406             : this(eventSourceGuid, eventSourceName, EventSourceSettings.EtwManifestEventFormat)
1407         { }
1408
1409         // Used by the internal FrameworkEventSource constructor and the TraceLogging-style event source constructor
1410         internal EventSource(Guid eventSourceGuid, string eventSourceName, EventSourceSettings settings, string[] traits = null)
1411         {
1412             m_config = ValidateSettings(settings);
1413             Initialize(eventSourceGuid, eventSourceName, traits);
1414         }
1415
1416         /// <summary>
1417         /// This method is responsible for the common initialization path from our constructors. It must
1418         /// not leak any exceptions (otherwise, since most EventSource classes define a static member, 
1419         /// "Log", such an exception would become a cached exception for the initialization of the static
1420         /// member, and any future access to the "Log" would throw the cached exception).
1421         /// </summary>
1422         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "guid")]
1423         private unsafe void Initialize(Guid eventSourceGuid, string eventSourceName, string[] traits)
1424         {
1425             try
1426             {
1427                 m_traits = traits;
1428                 if (m_traits != null && m_traits.Length % 2 != 0)
1429                 {
1430                     throw new ArgumentException(Resources.GetResourceString("TraitEven"), nameof(traits));
1431                 }
1432
1433                 if (eventSourceGuid == Guid.Empty)
1434                 {
1435                     throw new ArgumentException(Resources.GetResourceString("EventSource_NeedGuid"));
1436                 }
1437
1438                 if (eventSourceName == null)
1439                 {
1440                     throw new ArgumentException(Resources.GetResourceString("EventSource_NeedName"));
1441                 }
1442
1443                 m_name = eventSourceName;
1444                 m_guid = eventSourceGuid;
1445 #if FEATURE_ACTIVITYSAMPLING
1446                 m_curLiveSessions = new SessionMask(0);
1447                 m_etwSessionIdMap = new EtwSession[SessionMask.MAX];
1448 #endif // FEATURE_ACTIVITYSAMPLING
1449
1450                 //Enable Implicit Activity tracker
1451                 m_activityTracker = ActivityTracker.Instance;
1452
1453 #if FEATURE_MANAGED_ETW
1454                 // Create and register our provider traits.  We do this early because it is needed to log errors 
1455                 // In the self-describing event case. 
1456                 this.InitializeProviderMetadata();
1457
1458                 // Register the provider with ETW
1459                 var provider = new OverideEventProvider(this);
1460                 provider.Register(eventSourceGuid);
1461 #endif
1462                 // Add the eventSource to the global (weak) list.  
1463                 // This also sets m_id, which is the index in the list. 
1464                 EventListener.AddEventSource(this);
1465
1466 #if FEATURE_MANAGED_ETW
1467                 // OK if we get this far without an exception, then we can at least write out error messages. 
1468                 // Set m_provider, which allows this.  
1469                 m_provider = provider;
1470
1471 #if (!ES_BUILD_STANDALONE && !ES_BUILD_PN && !PLATFORM_UNIX)
1472                 // API available on OS >= Win 8 and patched Win 7.
1473                 // Disable only for FrameworkEventSource to avoid recursion inside exception handling.
1474                 if (this.Name != "System.Diagnostics.Eventing.FrameworkEventSource" || Environment.IsWindows8OrAbove)
1475 #endif
1476                 {
1477                     int setInformationResult;
1478                     System.Runtime.InteropServices.GCHandle metadataHandle =
1479                         System.Runtime.InteropServices.GCHandle.Alloc(this.providerMetadata, System.Runtime.InteropServices.GCHandleType.Pinned);
1480                     IntPtr providerMetadata = metadataHandle.AddrOfPinnedObject();
1481
1482                     setInformationResult = m_provider.SetInformation(
1483                         UnsafeNativeMethods.ManifestEtw.EVENT_INFO_CLASS.SetTraits,
1484                         providerMetadata,
1485                         (uint)this.providerMetadata.Length);
1486
1487                     metadataHandle.Free();
1488                 }
1489 #endif // FEATURE_MANAGED_ETW
1490
1491                 Debug.Assert(!m_eventSourceEnabled);     // We can't be enabled until we are completely initted.  
1492                 // We are logically completely initialized at this point.  
1493                 m_completelyInited = true;
1494             }
1495             catch (Exception e)
1496             {
1497                 if (m_constructionException == null)
1498                     m_constructionException = e;
1499                 ReportOutOfBandMessage("ERROR: Exception during construction of EventSource " + Name + ": " + e.Message, true);
1500             }
1501
1502             // Once m_completelyInited is set, you can have concurrency, so all work is under the lock.  
1503             lock (EventListener.EventListenersLock)
1504             {
1505                 // If there are any deferred commands, we can do them now.   
1506                 // This is the most likely place for exceptions to happen.  
1507                 // Note that we are NOT resetting m_deferredCommands to NULL here, 
1508                 // We are giving for EventHandler<EventCommandEventArgs> that will be attached later
1509                 EventCommandEventArgs deferredCommands = m_deferredCommands;
1510                 while (deferredCommands != null)
1511                 {
1512                     DoCommand(deferredCommands);      // This can never throw, it catches them and reports the errors.   
1513                     deferredCommands = deferredCommands.nextCommand;
1514                 }
1515             }
1516         }
1517
1518         private static string GetName(Type eventSourceType, EventManifestOptions flags)
1519         {
1520             if (eventSourceType == null)
1521                 throw new ArgumentNullException(nameof(eventSourceType));
1522             Contract.EndContractBlock();
1523
1524             EventSourceAttribute attrib = (EventSourceAttribute)GetCustomAttributeHelper(eventSourceType, typeof(EventSourceAttribute), flags);
1525             if (attrib != null && attrib.Name != null)
1526                 return attrib.Name;
1527
1528             return eventSourceType.Name;
1529         }
1530
1531         /// <summary>
1532         /// Implements the SHA1 hashing algorithm. Note that this
1533         /// implementation is for hashing public information. Do not
1534         /// use this code to hash private data, as this implementation does
1535         /// not take any steps to avoid information disclosure.
1536         /// </summary>
1537         private struct Sha1ForNonSecretPurposes
1538         {
1539             private long length; // Total message length in bits
1540             private uint[] w; // Workspace
1541             private int pos; // Length of current chunk in bytes
1542
1543             /// <summary>
1544             /// Call Start() to initialize the hash object.
1545             /// </summary>
1546             public void Start()
1547             {
1548                 if (this.w == null)
1549                 {
1550                     this.w = new uint[85];
1551                 }
1552
1553                 this.length = 0;
1554                 this.pos = 0;
1555                 this.w[80] = 0x67452301;
1556                 this.w[81] = 0xEFCDAB89;
1557                 this.w[82] = 0x98BADCFE;
1558                 this.w[83] = 0x10325476;
1559                 this.w[84] = 0xC3D2E1F0;
1560             }
1561
1562             /// <summary>
1563             /// Adds an input byte to the hash.
1564             /// </summary>
1565             /// <param name="input">Data to include in the hash.</param>
1566             public void Append(byte input)
1567             {
1568                 this.w[this.pos / 4] = (this.w[this.pos / 4] << 8) | input;
1569                 if (64 == ++this.pos)
1570                 {
1571                     this.Drain();
1572                 }
1573             }
1574
1575             /// <summary>
1576             /// Adds input bytes to the hash.
1577             /// </summary>
1578             /// <param name="input">
1579             /// Data to include in the hash. Must not be null.
1580             /// </param>
1581             public void Append(byte[] input)
1582             {
1583                 foreach (var b in input)
1584                 {
1585                     this.Append(b);
1586                 }
1587             }
1588
1589             /// <summary>
1590             /// Retrieves the hash value.
1591             /// Note that after calling this function, the hash object should
1592             /// be considered uninitialized. Subsequent calls to Append or
1593             /// Finish will produce useless results. Call Start() to
1594             /// reinitialize.
1595             /// </summary>
1596             /// <param name="output">
1597             /// Buffer to receive the hash value. Must not be null.
1598             /// Up to 20 bytes of hash will be written to the output buffer.
1599             /// If the buffer is smaller than 20 bytes, the remaining hash
1600             /// bytes will be lost. If the buffer is larger than 20 bytes, the
1601             /// rest of the buffer is left unmodified.
1602             /// </param>
1603             public void Finish(byte[] output)
1604             {
1605                 long l = this.length + 8 * this.pos;
1606                 this.Append(0x80);
1607                 while (this.pos != 56)
1608                 {
1609                     this.Append(0x00);
1610                 }
1611
1612                 unchecked
1613                 {
1614                     this.Append((byte)(l >> 56));
1615                     this.Append((byte)(l >> 48));
1616                     this.Append((byte)(l >> 40));
1617                     this.Append((byte)(l >> 32));
1618                     this.Append((byte)(l >> 24));
1619                     this.Append((byte)(l >> 16));
1620                     this.Append((byte)(l >> 8));
1621                     this.Append((byte)l);
1622
1623                     int end = output.Length < 20 ? output.Length : 20;
1624                     for (int i = 0; i != end; i++)
1625                     {
1626                         uint temp = this.w[80 + i / 4];
1627                         output[i] = (byte)(temp >> 24);
1628                         this.w[80 + i / 4] = temp << 8;
1629                     }
1630                 }
1631             }
1632
1633             /// <summary>
1634             /// Called when this.pos reaches 64.
1635             /// </summary>
1636             private void Drain()
1637             {
1638                 for (int i = 16; i != 80; i++)
1639                 {
1640                     this.w[i] = Rol1((this.w[i - 3] ^ this.w[i - 8] ^ this.w[i - 14] ^ this.w[i - 16]));
1641                 }
1642
1643                 unchecked
1644                 {
1645                     uint a = this.w[80];
1646                     uint b = this.w[81];
1647                     uint c = this.w[82];
1648                     uint d = this.w[83];
1649                     uint e = this.w[84];
1650
1651                     for (int i = 0; i != 20; i++)
1652                     {
1653                         const uint k = 0x5A827999;
1654                         uint f = (b & c) | ((~b) & d);
1655                         uint temp = Rol5(a) + f + e + k + this.w[i]; e = d; d = c; c = Rol30(b); b = a; a = temp;
1656                     }
1657
1658                     for (int i = 20; i != 40; i++)
1659                     {
1660                         uint f = b ^ c ^ d;
1661                         const uint k = 0x6ED9EBA1;
1662                         uint temp = Rol5(a) + f + e + k + this.w[i]; e = d; d = c; c = Rol30(b); b = a; a = temp;
1663                     }
1664
1665                     for (int i = 40; i != 60; i++)
1666                     {
1667                         uint f = (b & c) | (b & d) | (c & d);
1668                         const uint k = 0x8F1BBCDC;
1669                         uint temp = Rol5(a) + f + e + k + this.w[i]; e = d; d = c; c = Rol30(b); b = a; a = temp;
1670                     }
1671
1672                     for (int i = 60; i != 80; i++)
1673                     {
1674                         uint f = b ^ c ^ d;
1675                         const uint k = 0xCA62C1D6;
1676                         uint temp = Rol5(a) + f + e + k + this.w[i]; e = d; d = c; c = Rol30(b); b = a; a = temp;
1677                     }
1678
1679                     this.w[80] += a;
1680                     this.w[81] += b;
1681                     this.w[82] += c;
1682                     this.w[83] += d;
1683                     this.w[84] += e;
1684                 }
1685
1686                 this.length += 512; // 64 bytes == 512 bits
1687                 this.pos = 0;
1688             }
1689
1690             private static uint Rol1(uint input)
1691             {
1692                 return (input << 1) | (input >> 31);
1693             }
1694
1695             private static uint Rol5(uint input)
1696             {
1697                 return (input << 5) | (input >> 27);
1698             }
1699
1700             private static uint Rol30(uint input)
1701             {
1702                 return (input << 30) | (input >> 2);
1703             }
1704         }
1705
1706         private static Guid GenerateGuidFromName(string name)
1707         {
1708             byte[] bytes = Encoding.BigEndianUnicode.GetBytes(name);
1709             var hash = new Sha1ForNonSecretPurposes();
1710             hash.Start();
1711             hash.Append(namespaceBytes);
1712             hash.Append(bytes);
1713             Array.Resize(ref bytes, 16);
1714             hash.Finish(bytes);
1715
1716             bytes[7] = unchecked((byte)((bytes[7] & 0x0F) | 0x50));    // Set high 4 bits of octet 7 to 5, as per RFC 4122
1717             return new Guid(bytes);
1718         }
1719
1720         private unsafe object DecodeObject(int eventId, int parameterId, ref EventSource.EventData* data)
1721         {
1722             // TODO FIX : We use reflection which in turn uses EventSource, right now we carefully avoid
1723             // the recursion, but can we do this in a robust way?  
1724
1725             IntPtr dataPointer = data->DataPointer;
1726             // advance to next EventData in array
1727             ++data;
1728
1729             Type dataType = GetDataType(m_eventData[eventId], parameterId);
1730
1731             Again:
1732             if (dataType == typeof(IntPtr))
1733             {
1734                 return *((IntPtr*)dataPointer);
1735             }
1736             else if (dataType == typeof(int))
1737             {
1738                 return *((int*)dataPointer);
1739             }
1740             else if (dataType == typeof(uint))
1741             {
1742                 return *((uint*)dataPointer);
1743             }
1744             else if (dataType == typeof(long))
1745             {
1746                 return *((long*)dataPointer);
1747             }
1748             else if (dataType == typeof(ulong))
1749             {
1750                 return *((ulong*)dataPointer);
1751             }
1752             else if (dataType == typeof(byte))
1753             {
1754                 return *((byte*)dataPointer);
1755             }
1756             else if (dataType == typeof(sbyte))
1757             {
1758                 return *((sbyte*)dataPointer);
1759             }
1760             else if (dataType == typeof(short))
1761             {
1762                 return *((short*)dataPointer);
1763             }
1764             else if (dataType == typeof(ushort))
1765             {
1766                 return *((ushort*)dataPointer);
1767             }
1768             else if (dataType == typeof(float))
1769             {
1770                 return *((float*)dataPointer);
1771             }
1772             else if (dataType == typeof(double))
1773             {
1774                 return *((double*)dataPointer);
1775             }
1776             else if (dataType == typeof(decimal))
1777             {
1778                 return *((decimal*)dataPointer);
1779             }
1780             else if (dataType == typeof(bool))
1781             {
1782                 // The manifest defines a bool as a 32bit type (WIN32 BOOL), not 1 bit as CLR Does.
1783                 if (*((int*)dataPointer) == 1)
1784                 {
1785                     return true;
1786                 }
1787                 else
1788                 {
1789                     return false;
1790                 }
1791             }
1792             else if (dataType == typeof(Guid))
1793             {
1794                 return *((Guid*)dataPointer);
1795             }
1796             else if (dataType == typeof(char))
1797             {
1798                 return *((char*)dataPointer);
1799             }
1800             else if (dataType == typeof(DateTime))
1801             {
1802                 long dateTimeTicks = *((long*)dataPointer);
1803                 return DateTime.FromFileTimeUtc(dateTimeTicks);
1804             }
1805             else if (dataType == typeof(byte[]))
1806             {
1807                 // byte[] are written to EventData* as an int followed by a blob
1808                 int cbSize = *((int*)dataPointer);
1809                 byte[] blob = new byte[cbSize];
1810                 dataPointer = data->DataPointer;
1811                 data++;
1812                 for (int i = 0; i < cbSize; ++i)
1813                     blob[i] = *((byte*)(dataPointer + i));
1814                 return blob;
1815             }
1816             else if (dataType == typeof(byte*))
1817             {
1818                 // TODO: how do we want to handle this? For now we ignore it...
1819                 return null;
1820             }
1821             else
1822             {
1823                 if (m_EventSourcePreventRecursion && m_EventSourceInDecodeObject)
1824                 {
1825                     return null;
1826                 }
1827
1828                 try
1829                 {
1830                     m_EventSourceInDecodeObject = true;
1831
1832                     if (dataType.IsEnum())
1833                     {
1834                         dataType = Enum.GetUnderlyingType(dataType);
1835                         goto Again;
1836                     }
1837
1838
1839                     // Everything else is marshaled as a string.
1840                     // ETW strings are NULL-terminated, so marshal everything up to the first
1841                     // null in the string.
1842                     //return System.Runtime.InteropServices.Marshal.PtrToStringUni(dataPointer);
1843                     if(dataPointer == IntPtr.Zero)
1844                     {
1845                         return null;
1846                     }
1847
1848                     return new string((char *)dataPointer);
1849
1850                 }
1851                 finally
1852                 {
1853                     m_EventSourceInDecodeObject = false;
1854                 }
1855             }
1856         }
1857
1858         // Finds the Dispatcher (which holds the filtering state), for a given dispatcher for the current
1859         // eventSource).  
1860         private EventDispatcher GetDispatcher(EventListener listener)
1861         {
1862             EventDispatcher dispatcher = m_Dispatchers;
1863             while (dispatcher != null)
1864             {
1865                 if (dispatcher.m_Listener == listener)
1866                     return dispatcher;
1867                 dispatcher = dispatcher.m_Next;
1868             }
1869             return dispatcher;
1870         }
1871
1872         private unsafe void WriteEventVarargs(int eventId, Guid* childActivityID, object[] args)
1873         {
1874             if (m_eventSourceEnabled)
1875             {
1876                 try
1877                 {
1878                     Debug.Assert(m_eventData != null);  // You must have initialized this if you enabled the source.  
1879                     if (childActivityID != null)
1880                     {
1881                         ValidateEventOpcodeForTransfer(ref m_eventData[eventId], m_eventData[eventId].Name);
1882
1883                         // If you use WriteEventWithRelatedActivityID you MUST declare the first argument to be a GUID 
1884                         // with the name 'relatedActivityID, and NOT pass this argument to the WriteEvent method.  
1885                         // During manifest creation we modify the ParameterInfo[] that we store to strip out any
1886                         // first parameter that is of type Guid and named "relatedActivityId." Thus, if you call
1887                         // WriteEventWithRelatedActivityID from a method that doesn't name its first parameter correctly
1888                         // we can end up in a state where the ParameterInfo[] doesn't have its first parameter stripped,
1889                         // and this leads to a mismatch between the number of arguments and the number of ParameterInfos,
1890                         // which would cause a cryptic IndexOutOfRangeException later if we don't catch it here.
1891                         if (!m_eventData[eventId].HasRelatedActivityID)
1892                         {
1893                             throw new ArgumentException(Resources.GetResourceString("EventSource_NoRelatedActivityId"));
1894                         }
1895                     }
1896
1897                     LogEventArgsMismatches(m_eventData[eventId].Parameters, args);
1898
1899                     Guid* pActivityId = null;
1900                     Guid activityId = Guid.Empty;
1901                     Guid relatedActivityId = Guid.Empty;
1902                     EventOpcode opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode;
1903                     EventActivityOptions activityOptions = m_eventData[eventId].ActivityOptions;
1904
1905                     if (childActivityID == null &&
1906                        ((activityOptions & EventActivityOptions.Disable) == 0))
1907                     {
1908                         if (opcode == EventOpcode.Start)
1909                         {
1910                             m_activityTracker.OnStart(m_name, m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Task, ref activityId, ref relatedActivityId, m_eventData[eventId].ActivityOptions);
1911                         }
1912                         else if (opcode == EventOpcode.Stop)
1913                         {
1914                             m_activityTracker.OnStop(m_name, m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Task, ref activityId);
1915                         }
1916
1917                         if (activityId != Guid.Empty)
1918                             pActivityId = &activityId;
1919                         if (relatedActivityId != Guid.Empty)
1920                             childActivityID = &relatedActivityId;
1921                     }
1922
1923 #if FEATURE_MANAGED_ETW
1924                     if (m_eventData[eventId].EnabledForETW)
1925                     {
1926 #if FEATURE_ACTIVITYSAMPLING
1927                         // this code should be kept in sync with WriteEventWithRelatedActivityIdCore().
1928                         SessionMask etwSessions = SessionMask.All;
1929                         // only compute etwSessions if there are *any* ETW filters enabled...
1930                         if ((ulong)m_curLiveSessions != 0)
1931                             etwSessions = GetEtwSessionMask(eventId, childActivityID);
1932
1933                         if ((ulong)etwSessions != 0 || m_legacySessions != null && m_legacySessions.Count > 0)
1934                         {
1935                             if (!SelfDescribingEvents)
1936                             {
1937                                 if (etwSessions.IsEqualOrSupersetOf(m_curLiveSessions))
1938                                 {
1939                                     // by default the Descriptor.Keyword will have the perEventSourceSessionId bit 
1940                                     // mask set to 0x0f so, when all ETW sessions want the event we don't need to 
1941                                     // synthesize a new one
1942                                     if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, childActivityID, args))
1943                                         ThrowEventSourceException(m_eventData[eventId].Name);
1944                                 }
1945                                 else
1946                                 {
1947                                     long origKwd = unchecked((long)((ulong)m_eventData[eventId].Descriptor.Keywords & ~(SessionMask.All.ToEventKeywords())));
1948                                     // only some of the ETW sessions will receive this event. Synthesize a new
1949                                     // Descriptor whose Keywords field will have the appropriate bits set.
1950                                     var desc = new EventDescriptor(
1951                                         m_eventData[eventId].Descriptor.EventId,
1952                                         m_eventData[eventId].Descriptor.Version,
1953                                         m_eventData[eventId].Descriptor.Channel,
1954                                         m_eventData[eventId].Descriptor.Level,
1955                                         m_eventData[eventId].Descriptor.Opcode,
1956                                         m_eventData[eventId].Descriptor.Task,
1957                                         unchecked((long)etwSessions.ToEventKeywords() | origKwd));
1958
1959                                     if (!m_provider.WriteEvent(ref desc, pActivityId, childActivityID, args))
1960                                         ThrowEventSourceException(m_eventData[eventId].Name);
1961                                 }
1962                             }
1963                             else
1964                             {
1965                                 TraceLoggingEventTypes tlet = m_eventData[eventId].TraceLoggingEventTypes;
1966                                 if (tlet == null)
1967                                 {
1968                                     tlet = new TraceLoggingEventTypes(m_eventData[eventId].Name,
1969                                                                         EventTags.None,
1970                                                                         m_eventData[eventId].Parameters);
1971                                     Interlocked.CompareExchange(ref m_eventData[eventId].TraceLoggingEventTypes, tlet, null);
1972
1973                                 }
1974                                 long origKwd = unchecked((long)((ulong)m_eventData[eventId].Descriptor.Keywords & ~(SessionMask.All.ToEventKeywords())));
1975                                 // TODO: activity ID support
1976                                 EventSourceOptions opt = new EventSourceOptions
1977                                 {
1978                                     Keywords = (EventKeywords)unchecked((long)etwSessions.ToEventKeywords() | origKwd),
1979                                     Level = (EventLevel)m_eventData[eventId].Descriptor.Level,
1980                                     Opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode
1981                                 };
1982
1983                                 WriteMultiMerge(m_eventData[eventId].Name, ref opt, tlet, pActivityId, childActivityID, args);
1984                             }
1985                         }
1986 #else
1987                         if (!SelfDescribingEvents)
1988                         {
1989                             if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, childActivityID, args))
1990                                 ThrowEventSourceException(m_eventData[eventId].Name);
1991                         }
1992                         else
1993                         {
1994                             TraceLoggingEventTypes tlet = m_eventData[eventId].TraceLoggingEventTypes;
1995                             if (tlet == null)
1996                             {
1997                                 tlet = new TraceLoggingEventTypes(m_eventData[eventId].Name,
1998                                                                     EventTags.None,
1999                                                                     m_eventData[eventId].Parameters);
2000                                 Interlocked.CompareExchange(ref m_eventData[eventId].TraceLoggingEventTypes, tlet, null);
2001
2002                             }
2003                             // TODO: activity ID support
2004                             EventSourceOptions opt = new EventSourceOptions
2005                             {
2006                                 Keywords = (EventKeywords)m_eventData[eventId].Descriptor.Keywords,
2007                                 Level = (EventLevel)m_eventData[eventId].Descriptor.Level,
2008                                 Opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode
2009                             };
2010
2011                             WriteMultiMerge(m_eventData[eventId].Name, ref opt, tlet, pActivityId, childActivityID, args);
2012                         }
2013 #endif // FEATURE_ACTIVITYSAMPLING
2014                     }
2015 #endif // FEATURE_MANAGED_ETW
2016                     if (m_Dispatchers != null && m_eventData[eventId].EnabledForAnyListener)
2017                     {
2018 #if (!ES_BUILD_STANDALONE && !ES_BUILD_PN)
2019                         // Maintain old behavior - object identity is preserved
2020                         if (AppContextSwitches.PreserveEventListnerObjectIdentity)
2021                         {
2022                             WriteToAllListeners(eventId, childActivityID, args);
2023                         }
2024                         else
2025 #endif // !ES_BUILD_STANDALONE
2026                         {
2027                             object[] serializedArgs = SerializeEventArgs(eventId, args);
2028                             WriteToAllListeners(eventId, childActivityID, serializedArgs);
2029                         }
2030                     }
2031                 }
2032                 catch (Exception ex)
2033                 {
2034                     if (ex is EventSourceException)
2035                         throw;
2036                     else
2037                         ThrowEventSourceException(m_eventData[eventId].Name, ex);
2038                 }
2039             }
2040         }
2041
2042         unsafe private object[] SerializeEventArgs(int eventId, object[] args)
2043         {
2044             TraceLoggingEventTypes eventTypes = m_eventData[eventId].TraceLoggingEventTypes;
2045             if (eventTypes == null)
2046             {
2047                 eventTypes = new TraceLoggingEventTypes(m_eventData[eventId].Name,
2048                                                         EventTags.None,
2049                                                         m_eventData[eventId].Parameters);
2050                 Interlocked.CompareExchange(ref m_eventData[eventId].TraceLoggingEventTypes, eventTypes, null);
2051             }
2052             var eventData = new object[eventTypes.typeInfos.Length];
2053             for (int i = 0; i < eventTypes.typeInfos.Length; i++)
2054             {
2055                 eventData[i] = eventTypes.typeInfos[i].GetData(args[i]);
2056             }
2057             return eventData;
2058         }
2059
2060         /// <summary>
2061         /// We expect that the arguments to the Event method and the arguments to WriteEvent match. This function 
2062         /// checks that they in fact match and logs a warning to the debugger if they don't.
2063         /// </summary>
2064         /// <param name="infos"></param>
2065         /// <param name="args"></param>
2066         private void LogEventArgsMismatches(ParameterInfo[] infos, object[] args)
2067         {
2068 #if (!ES_BUILD_PCL && !ES_BUILD_PN)
2069             // It would be nice to have this on PCL builds, but it would be pointless since there isn't support for 
2070             // writing to the debugger log on PCL.
2071             bool typesMatch = args.Length == infos.Length;
2072
2073             int i = 0;
2074             while (typesMatch && i < args.Length)
2075             {
2076                 Type pType = infos[i].ParameterType;
2077
2078                 // Checking to see if the Parameter types (from the Event method) match the supplied argument types.
2079                 // Fail if one of two things hold : either the argument type is not equal to the parameter type, or the 
2080                 // argument is null and the parameter type is non-nullable.
2081                 if ((args[i] != null && (args[i].GetType() != pType))
2082                     || (args[i] == null && (!(pType.IsGenericType && pType.GetGenericTypeDefinition() == typeof(Nullable<>))))
2083                     )
2084                 {
2085                     typesMatch = false;
2086                     break;
2087                 }
2088
2089                 ++i;
2090             }
2091
2092             if (!typesMatch)
2093             {
2094                 System.Diagnostics.Debugger.Log(0, null, Resources.GetResourceString("EventSource_VarArgsParameterMismatch") + "\r\n");
2095             }
2096 #endif //!ES_BUILD_PCL
2097         }
2098
2099         private int GetParamLenghtIncludingByteArray(ParameterInfo[] parameters)
2100         {
2101             int sum = 0;
2102             foreach (ParameterInfo info in parameters)
2103             {
2104                 if (info.ParameterType == typeof(byte[]))
2105                 {
2106                     sum += 2;
2107                 }
2108                 else
2109                 {
2110                     sum++;
2111                 }
2112             }
2113
2114             return sum;
2115         }
2116
2117         unsafe private void WriteToAllListeners(int eventId, Guid* childActivityID, int eventDataCount, EventSource.EventData* data)
2118         {
2119             // We represent a byte[] as a integer denoting the length  and then a blob of bytes in the data pointer. This causes a spurious
2120             // warning because eventDataCount is off by one for the byte[] case since a byte[] has 2 items associated it. So we want to check
2121             // that the number of parameters is correct against the byte[] case, but also we the args array would be one too long if
2122             // we just used the modifiedParamCount here -- so we need both.
2123             int paramCount = m_eventData[eventId].Parameters.Length;
2124             int modifiedParamCount = GetParamLenghtIncludingByteArray(m_eventData[eventId].Parameters);
2125             if (eventDataCount != modifiedParamCount)
2126             {
2127                 ReportOutOfBandMessage(Resources.GetResourceString("EventSource_EventParametersMismatch", eventId, eventDataCount, paramCount), true);
2128                 paramCount = Math.Min(paramCount, eventDataCount);
2129             }
2130
2131             object[] args = new object[paramCount];
2132
2133             EventSource.EventData* dataPtr = data;
2134             for (int i = 0; i < paramCount; i++)
2135                 args[i] = DecodeObject(eventId, i, ref dataPtr);
2136             WriteToAllListeners(eventId, childActivityID, args);
2137         }
2138
2139         // helper for writing to all EventListeners attached the current eventSource.  
2140         unsafe private void WriteToAllListeners(int eventId, Guid* childActivityID, params object[] args)
2141         {
2142             EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this);
2143             eventCallbackArgs.EventId = eventId;
2144             if (childActivityID != null)
2145                 eventCallbackArgs.RelatedActivityId = *childActivityID;
2146             eventCallbackArgs.EventName = m_eventData[eventId].Name;
2147             eventCallbackArgs.Message = m_eventData[eventId].Message;
2148             eventCallbackArgs.Payload = new ReadOnlyCollection<object>(args);
2149
2150             DispatchToAllListeners(eventId, childActivityID, eventCallbackArgs);
2151         }
2152
2153         private unsafe void DispatchToAllListeners(int eventId, Guid* childActivityID, EventWrittenEventArgs eventCallbackArgs)
2154         {
2155             Exception lastThrownException = null;
2156             for (EventDispatcher dispatcher = m_Dispatchers; dispatcher != null; dispatcher = dispatcher.m_Next)
2157             {
2158                 Debug.Assert(dispatcher.m_EventEnabled != null);
2159                 if (eventId == -1 || dispatcher.m_EventEnabled[eventId])
2160                 {
2161 #if FEATURE_ACTIVITYSAMPLING
2162                     var activityFilter = dispatcher.m_Listener.m_activityFilter;
2163                     // order below is important as PassesActivityFilter will "flow" active activities
2164                     // even when the current EventSource doesn't have filtering enabled. This allows
2165                     // interesting activities to be updated so that sources that do sample can get
2166                     // accurate data
2167                     if (activityFilter == null ||
2168                         ActivityFilter.PassesActivityFilter(activityFilter, childActivityID,
2169                                                             m_eventData[eventId].TriggersActivityTracking > 0,
2170                                                             this, eventId) ||
2171                         !dispatcher.m_activityFilteringEnabled)
2172 #endif // FEATURE_ACTIVITYSAMPLING
2173                     {
2174                         try
2175                         {
2176                             dispatcher.m_Listener.OnEventWritten(eventCallbackArgs);
2177                         }
2178                         catch (Exception e)
2179                         {
2180                             ReportOutOfBandMessage("ERROR: Exception during EventSource.OnEventWritten: "
2181                                  + e.Message, false);
2182                             lastThrownException = e;
2183                         }
2184                     }
2185                 }
2186             }
2187
2188             if (lastThrownException != null)
2189             {
2190                 throw new EventSourceException(lastThrownException);
2191             }
2192         }
2193
2194         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
2195         private unsafe void WriteEventString(EventLevel level, long keywords, string msgString)
2196         {
2197 #if FEATURE_MANAGED_ETW
2198             if (m_provider != null)
2199             {
2200                 string eventName = "EventSourceMessage";
2201                 if (SelfDescribingEvents)
2202                 {
2203                     EventSourceOptions opt = new EventSourceOptions
2204                     {
2205                         Keywords = (EventKeywords)unchecked(keywords),
2206                         Level = level
2207                     };
2208                     var msg = new { message = msgString };
2209                     var tlet = new TraceLoggingEventTypes(eventName, EventTags.None, new Type[] { msg.GetType() });
2210                     WriteMultiMergeInner(eventName, ref opt, tlet, null, null, msg);
2211                 }
2212                 else
2213                 {
2214                     // We want the name of the provider to show up so if we don't have a manifest we create 
2215                     // on that at least has the provider name (I don't define any events).   
2216                     if (m_rawManifest == null && m_outOfBandMessageCount == 1)
2217                     {
2218                         ManifestBuilder manifestBuilder = new ManifestBuilder(Name, Guid, Name, null, EventManifestOptions.None);
2219                         manifestBuilder.StartEvent(eventName, new EventAttribute(0) { Level = EventLevel.LogAlways, Task = (EventTask)0xFFFE });
2220                         manifestBuilder.AddEventParameter(typeof(string), "message");
2221                         manifestBuilder.EndEvent();
2222                         SendManifest(manifestBuilder.CreateManifest());
2223                     }
2224
2225                     // We use this low level routine to to bypass the enabled checking, since the eventSource itself is only partially inited. 
2226                     fixed (char* msgStringPtr = msgString)
2227                     {
2228                         EventDescriptor descr = new EventDescriptor(0, 0, 0, (byte)level, 0, 0, keywords);
2229                         EventProvider.EventData data = new EventProvider.EventData();
2230                         data.Ptr = (ulong)msgStringPtr;
2231                         data.Size = (uint)(2 * (msgString.Length + 1));
2232                         data.Reserved = 0;
2233                         m_provider.WriteEvent(ref descr, null, null, 1, (IntPtr)((void*)&data));
2234                     }
2235                 }
2236             }
2237 #endif // FEATURE_MANAGED_ETW
2238         }
2239
2240         /// <summary>
2241         /// Since this is a means of reporting errors (see ReportoutOfBandMessage) any failure encountered 
2242         /// while writing the message to any one of the listeners will be silently ignored.
2243         /// </summary>
2244         private void WriteStringToAllListeners(string eventName, string msg)
2245         {
2246             EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this);
2247             eventCallbackArgs.EventId = 0;
2248             eventCallbackArgs.Message = msg;
2249             eventCallbackArgs.Payload = new ReadOnlyCollection<object>(new List<object>() { msg });
2250             eventCallbackArgs.PayloadNames = new ReadOnlyCollection<string>(new List<string> { "message" });
2251             eventCallbackArgs.EventName = eventName;
2252
2253             for (EventDispatcher dispatcher = m_Dispatchers; dispatcher != null; dispatcher = dispatcher.m_Next)
2254             {
2255                 bool dispatcherEnabled = false;
2256                 if (dispatcher.m_EventEnabled == null)
2257                 {
2258                     // if the listeners that weren't correctly initialized, we will send to it
2259                     // since this is an error message and we want to see it go out. 
2260                     dispatcherEnabled = true;
2261                 }
2262                 else
2263                 {
2264                     // if there's *any* enabled event on the dispatcher we'll write out the string
2265                     // otherwise we'll treat the listener as disabled and skip it
2266                     for (int evtId = 0; evtId < dispatcher.m_EventEnabled.Length; ++evtId)
2267                     {
2268                         if (dispatcher.m_EventEnabled[evtId])
2269                         {
2270                             dispatcherEnabled = true;
2271                             break;
2272                         }
2273                     }
2274                 }
2275                 try
2276                 {
2277                     if (dispatcherEnabled)
2278                         dispatcher.m_Listener.OnEventWritten(eventCallbackArgs);
2279                 }
2280                 catch
2281                 {
2282                     // ignore any exceptions thrown by listeners' OnEventWritten
2283                 }
2284             }
2285         }
2286
2287 #if FEATURE_ACTIVITYSAMPLING
2288         unsafe private SessionMask GetEtwSessionMask(int eventId, Guid* childActivityID)
2289         {
2290             SessionMask etwSessions = new SessionMask();
2291
2292             for (int i = 0; i < SessionMask.MAX; ++i)
2293             {
2294                 EtwSession etwSession = m_etwSessionIdMap[i];
2295                 if (etwSession != null)
2296                 {
2297                     ActivityFilter activityFilter = etwSession.m_activityFilter;
2298                     // PassesActivityFilter() will flow "interesting" activities, so make sure
2299                     // to perform this test first, before ORing with ~m_activityFilteringForETWEnabled
2300                     // (note: the first test for !m_activityFilteringForETWEnabled[i] ensures we
2301                     //  do not fire events indiscriminately, when no filters are specified, but only 
2302                     //  if, in addition, the session did not also enable ActivitySampling)
2303                     if (activityFilter == null && !m_activityFilteringForETWEnabled[i] ||
2304                         activityFilter != null &&
2305                             ActivityFilter.PassesActivityFilter(activityFilter, childActivityID,
2306                                 m_eventData[eventId].TriggersActivityTracking > 0, this, eventId) ||
2307                         !m_activityFilteringForETWEnabled[i])
2308                     {
2309                         etwSessions[i] = true;
2310                     }
2311                 }
2312             }
2313             // flow "interesting" activities for all legacy sessions in which there's some 
2314             // level of activity tracing enabled (even other EventSources)
2315             if (m_legacySessions != null && m_legacySessions.Count > 0 &&
2316                 (EventOpcode)m_eventData[eventId].Descriptor.Opcode == EventOpcode.Send)
2317             {
2318                 // only calculate InternalCurrentThreadActivityId once
2319                 Guid* pCurrentActivityId = null;
2320                 Guid currentActivityId;
2321                 foreach (var legacyEtwSession in m_legacySessions)
2322                 {
2323                     if (legacyEtwSession == null)
2324                         continue;
2325
2326                     ActivityFilter activityFilter = legacyEtwSession.m_activityFilter;
2327                     if (activityFilter != null)
2328                     {
2329                         if (pCurrentActivityId == null)
2330                         {
2331                             currentActivityId = InternalCurrentThreadActivityId;
2332                             pCurrentActivityId = &currentActivityId;
2333                         }
2334                         ActivityFilter.FlowActivityIfNeeded(activityFilter, pCurrentActivityId, childActivityID);
2335                     }
2336                 }
2337             }
2338
2339             return etwSessions;
2340         }
2341 #endif // FEATURE_ACTIVITYSAMPLING
2342
2343         /// <summary>
2344         /// Returns true if 'eventNum' is enabled if you only consider the level and matchAnyKeyword filters.
2345         /// It is possible that eventSources turn off the event based on additional filtering criteria.  
2346         /// </summary>
2347         private bool IsEnabledByDefault(int eventNum, bool enable, EventLevel currentLevel, EventKeywords currentMatchAnyKeyword)
2348         {
2349             if (!enable)
2350                 return false;
2351
2352             EventLevel eventLevel = (EventLevel)m_eventData[eventNum].Descriptor.Level;
2353             EventKeywords eventKeywords = unchecked((EventKeywords)((ulong)m_eventData[eventNum].Descriptor.Keywords & (~(SessionMask.All.ToEventKeywords()))));
2354
2355 #if FEATURE_MANAGED_ETW_CHANNELS
2356             EventChannel channel = unchecked((EventChannel)m_eventData[eventNum].Descriptor.Channel);
2357 #else
2358             EventChannel channel = EventChannel.None;
2359 #endif
2360
2361             return IsEnabledCommon(enable, currentLevel, currentMatchAnyKeyword, eventLevel, eventKeywords, channel);
2362         }
2363
2364         private bool IsEnabledCommon(bool enabled, EventLevel currentLevel, EventKeywords currentMatchAnyKeyword,
2365                                                           EventLevel eventLevel, EventKeywords eventKeywords, EventChannel eventChannel)
2366         {
2367             if (!enabled)
2368                 return false;
2369
2370             // does is pass the level test?
2371             if ((currentLevel != 0) && (currentLevel < eventLevel))
2372                 return false;
2373
2374             // if yes, does it pass the keywords test?
2375             if (currentMatchAnyKeyword != 0 && eventKeywords != 0)
2376             {
2377 #if FEATURE_MANAGED_ETW_CHANNELS
2378                 // is there a channel with keywords that match currentMatchAnyKeyword?
2379                 if (eventChannel != EventChannel.None && this.m_channelData != null && this.m_channelData.Length > (int)eventChannel)
2380                 {
2381                     EventKeywords channel_keywords = unchecked((EventKeywords)(m_channelData[(int)eventChannel] | (ulong)eventKeywords));
2382                     if (channel_keywords != 0 && (channel_keywords & currentMatchAnyKeyword) == 0)
2383                         return false;
2384                 }
2385                 else
2386 #endif
2387                 {
2388                     if ((unchecked((ulong)eventKeywords & (ulong)currentMatchAnyKeyword)) == 0)
2389                         return false;
2390                 }
2391             }
2392             return true;
2393
2394         }
2395         [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
2396         private void ThrowEventSourceException(string eventName, Exception innerEx = null)
2397         {
2398             // If we fail during out of band logging we may end up trying 
2399             // to throw another EventSourceException, thus hitting a StackOverflowException. 
2400             // Avoid StackOverflow by making sure we do not recursively call this method.
2401             if (m_EventSourceExceptionRecurenceCount > 0)
2402                 return;
2403             try
2404             {
2405                 m_EventSourceExceptionRecurenceCount++;
2406
2407                 string errorPrefix = "EventSourceException";
2408                 if (eventName != null)
2409                 {
2410                     errorPrefix += " while processing event \"" + eventName + "\"";
2411                 }
2412
2413                 // TODO Create variations of EventSourceException that indicate more information using the error code.
2414                 switch (EventProvider.GetLastWriteEventError())
2415                 {
2416                     case EventProvider.WriteEventErrorCode.EventTooBig:
2417                         ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_EventTooBig"), true);
2418                         if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_EventTooBig"), innerEx);
2419                         break;
2420                     case EventProvider.WriteEventErrorCode.NoFreeBuffers:
2421                         ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_NoFreeBuffers"), true);
2422                         if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_NoFreeBuffers"), innerEx);
2423                         break;
2424                     case EventProvider.WriteEventErrorCode.NullInput:
2425                         ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_NullInput"), true);
2426                         if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_NullInput"), innerEx);
2427                         break;
2428                     case EventProvider.WriteEventErrorCode.TooManyArgs:
2429                         ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_TooManyArgs"), true);
2430                         if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_TooManyArgs"), innerEx);
2431                         break;
2432                     default:
2433                         if (innerEx != null)
2434                             ReportOutOfBandMessage(errorPrefix + ": " + innerEx.GetType() + ":" + innerEx.Message, true);
2435                         else
2436                             ReportOutOfBandMessage(errorPrefix, true);
2437                         if (ThrowOnEventWriteErrors) throw new EventSourceException(innerEx);
2438                         break;
2439                 }
2440             }
2441             finally
2442             {
2443                 m_EventSourceExceptionRecurenceCount--;
2444             }
2445         }
2446
2447         private void ValidateEventOpcodeForTransfer(ref EventMetadata eventData, string eventName)
2448         {
2449             if ((EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Send &&
2450                 (EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Receive &&
2451                 (EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Start)
2452             {
2453                 ThrowEventSourceException(eventName);
2454             }
2455         }
2456
2457         internal static EventOpcode GetOpcodeWithDefault(EventOpcode opcode, string eventName)
2458         {
2459             if (opcode == EventOpcode.Info && eventName != null)
2460             {
2461                 if (eventName.EndsWith(s_ActivityStartSuffix, StringComparison.Ordinal))
2462                 {
2463                     return EventOpcode.Start;
2464                 }
2465                 else if (eventName.EndsWith(s_ActivityStopSuffix, StringComparison.Ordinal))
2466                 {
2467                     return EventOpcode.Stop;
2468                 }
2469             }
2470
2471             return opcode;
2472         }
2473
2474 #if FEATURE_MANAGED_ETW
2475         /// <summary>
2476         /// This class lets us hook the 'OnEventCommand' from the eventSource.  
2477         /// </summary>
2478         private class OverideEventProvider : EventProvider
2479         {
2480             public OverideEventProvider(EventSource eventSource)
2481             {
2482                 this.m_eventSource = eventSource;
2483             }
2484             protected override void OnControllerCommand(ControllerCommand command, IDictionary<string, string> arguments,
2485                                                               int perEventSourceSessionId, int etwSessionId)
2486             {
2487                 // We use null to represent the ETW EventListener.  
2488                 EventListener listener = null;
2489                 m_eventSource.SendCommand(listener, perEventSourceSessionId, etwSessionId,
2490                                           (EventCommand)command, IsEnabled(), Level, MatchAnyKeyword, arguments);
2491             }
2492             private EventSource m_eventSource;
2493         }
2494 #endif
2495
2496         /// <summary>
2497         /// Used to hold all the static information about an event.  This includes everything in the event
2498         /// descriptor as well as some stuff we added specifically for EventSource. see the
2499         /// code:m_eventData for where we use this.  
2500         /// </summary>
2501
2502         /*
2503          EventMetadata was public in the separate System.Diagnostics.Tracing assembly(pre NS2.0), 
2504          now the move to CoreLib marked them as private.
2505          While they are technically private (it's a contract used between the library and the ILC toolchain), 
2506          we need them to be rooted and exported from shared library for the system to work.
2507          For now I'm simply marking them as public again.A cleaner solution might be to use.rd.xml to 
2508          root them and modify shared library definition to force export them.
2509          */
2510 #if ES_BUILD_PN
2511        public
2512 #else
2513        internal
2514 #endif
2515         partial struct EventMetadata
2516         {
2517             public EventDescriptor Descriptor;
2518             public EventTags Tags;
2519             public bool EnabledForAnyListener;      // true if any dispatcher has this event turned on
2520             public bool EnabledForETW;              // is this event on for the OS ETW data dispatcher?
2521
2522             public bool HasRelatedActivityID;       // Set if the event method's first parameter is a Guid named 'relatedActivityId'
2523 #if !FEATURE_ACTIVITYSAMPLING
2524 #pragma warning disable 0649
2525 #endif
2526             public byte TriggersActivityTracking;   // count of listeners that marked this event as trigger for start of activity logging.
2527 #if !FEATURE_ACTIVITYSAMPLING
2528 #pragma warning restore 0649
2529 #endif
2530             public string Name;                     // the name of the event
2531             public string Message;                  // If the event has a message associated with it, this is it.  
2532             public ParameterInfo[] Parameters;      // TODO can we remove? 
2533
2534             public TraceLoggingEventTypes TraceLoggingEventTypes;
2535             public EventActivityOptions ActivityOptions;
2536
2537 #if ES_BUILD_PN
2538             public EventParameterType[] ParameterTypes;
2539 #endif
2540         };
2541
2542         // This is the internal entry point that code:EventListeners call when wanting to send a command to a
2543         // eventSource. The logic is as follows
2544         // 
2545         // * if Command == Update
2546         //     * perEventSourceSessionId specifies the per-provider ETW session ID that the command applies 
2547         //         to (if listener != null)
2548         //         perEventSourceSessionId = 0 - reserved for EventListeners
2549         //         perEventSourceSessionId = 1..SessionMask.MAX - reserved for activity tracing aware ETW sessions
2550         //                  perEventSourceSessionId-1 represents the bit in the reserved field (bits 44..47) in 
2551         //                  Keywords that identifies the session
2552         //         perEventSourceSessionId = SessionMask.MAX+1 - reserved for legacy ETW sessions; these are 
2553         //                  discriminated by etwSessionId
2554         //     * etwSessionId specifies a machine-wide ETW session ID; this allows correlation of
2555         //         activity tracing across different providers (which might have different sessionIds
2556         //         for the same ETW session)
2557         //     * enable, level, matchAnyKeywords are used to set a default for all events for the
2558         //         eventSource.  In particular, if 'enabled' is false, 'level' and
2559         //         'matchAnyKeywords' are not used.  
2560         //     * OnEventCommand is invoked, which may cause calls to
2561         //         code:EventSource.EnableEventForDispatcher which may cause changes in the filtering
2562         //         depending on the logic in that routine.
2563         // * else (command != Update)
2564         //     * Simply call OnEventCommand. The expectation is that filtering is NOT changed.
2565         //     * The 'enabled' 'level', matchAnyKeyword' arguments are ignored (must be true, 0, 0).  
2566         // 
2567         // dispatcher == null has special meaning. It is the 'ETW' dispatcher.
2568         internal void SendCommand(EventListener listener, int perEventSourceSessionId, int etwSessionId,
2569                                   EventCommand command, bool enable,
2570                                   EventLevel level, EventKeywords matchAnyKeyword,
2571                                   IDictionary<string, string> commandArguments)
2572         {
2573             var commandArgs = new EventCommandEventArgs(command, commandArguments, this, listener, perEventSourceSessionId, etwSessionId, enable, level, matchAnyKeyword);
2574             lock (EventListener.EventListenersLock)
2575             {
2576                 if (m_completelyInited)
2577                 {
2578                     // After the first command arrive after construction, we are ready to get rid of the deferred commands
2579                     this.m_deferredCommands = null;
2580                     // We are fully initialized, do the command 
2581                     DoCommand(commandArgs);
2582                 }
2583                 else
2584                 {
2585                     // We can't do the command, simply remember it and we do it when we are fully constructed.  
2586                     commandArgs.nextCommand = m_deferredCommands;
2587                     m_deferredCommands = commandArgs;
2588                 }
2589             }
2590         }
2591
2592         /// <summary>
2593         /// We want the eventSource to be fully initialized when we do commands because that way we can send 
2594         /// error messages and other logging directly to the event stream.   Unfortunately we can get callbacks
2595         /// when we are not fully initialized.  In that case we store them in 'commandArgs' and do them later. 
2596         /// This helper actually does all actual command logic. 
2597         /// </summary>
2598         internal void DoCommand(EventCommandEventArgs commandArgs)
2599         {
2600             // PRECONDITION: We should be holding the EventListener.EventListenersLock
2601             // We defer commands until we are completely inited.  This allows error messages to be sent.  
2602             Debug.Assert(m_completelyInited);
2603
2604 #if FEATURE_MANAGED_ETW
2605             if (m_provider == null)     // If we failed to construct
2606                 return;
2607 #endif // FEATURE_MANAGED_ETW
2608
2609             m_outOfBandMessageCount = 0;
2610             bool shouldReport = (commandArgs.perEventSourceSessionId > 0) && (commandArgs.perEventSourceSessionId <= SessionMask.MAX);
2611             try
2612             {
2613                 EnsureDescriptorsInitialized();
2614                 Debug.Assert(m_eventData != null);
2615
2616                 // Find the per-EventSource dispatcher corresponding to registered dispatcher
2617                 commandArgs.dispatcher = GetDispatcher(commandArgs.listener);
2618                 if (commandArgs.dispatcher == null && commandArgs.listener != null)     // dispatcher == null means ETW dispatcher
2619                 {
2620                     throw new ArgumentException(Resources.GetResourceString("EventSource_ListenerNotFound"));
2621                 }
2622
2623                 if (commandArgs.Arguments == null)
2624                     commandArgs.Arguments = new Dictionary<string, string>();
2625
2626                 if (commandArgs.Command == EventCommand.Update)
2627                 {
2628                     // Set it up using the 'standard' filtering bitfields (use the "global" enable, not session specific one)
2629                     for (int i = 0; i < m_eventData.Length; i++)
2630                         EnableEventForDispatcher(commandArgs.dispatcher, i, IsEnabledByDefault(i, commandArgs.enable, commandArgs.level, commandArgs.matchAnyKeyword));
2631
2632                     if (commandArgs.enable)
2633                     {
2634                         if (!m_eventSourceEnabled)
2635                         {
2636                             // EventSource turned on for the first time, simply copy the bits.  
2637                             m_level = commandArgs.level;
2638                             m_matchAnyKeyword = commandArgs.matchAnyKeyword;
2639                         }
2640                         else
2641                         {
2642                             // Already enabled, make it the most verbose of the existing and new filter
2643                             if (commandArgs.level > m_level)
2644                                 m_level = commandArgs.level;
2645                             if (commandArgs.matchAnyKeyword == 0)
2646                                 m_matchAnyKeyword = 0;
2647                             else if (m_matchAnyKeyword != 0)
2648                                 m_matchAnyKeyword = unchecked(m_matchAnyKeyword | commandArgs.matchAnyKeyword);
2649                         }
2650                     }
2651
2652                     // interpret perEventSourceSessionId's sign, and adjust perEventSourceSessionId to 
2653                     // represent 0-based positive values
2654                     bool bSessionEnable = (commandArgs.perEventSourceSessionId >= 0);
2655                     if (commandArgs.perEventSourceSessionId == 0 && commandArgs.enable == false)
2656                         bSessionEnable = false;
2657
2658                     if (commandArgs.listener == null)
2659                     {
2660                         if (!bSessionEnable)
2661                             commandArgs.perEventSourceSessionId = -commandArgs.perEventSourceSessionId;
2662                         // for "global" enable/disable (passed in with listener == null and
2663                         //  perEventSourceSessionId == 0) perEventSourceSessionId becomes -1
2664                         --commandArgs.perEventSourceSessionId;
2665                     }
2666
2667                     commandArgs.Command = bSessionEnable ? EventCommand.Enable : EventCommand.Disable;
2668
2669                     // perEventSourceSessionId = -1 when ETW sent a notification, but the set of active sessions
2670                     // hasn't changed.
2671                     // sesisonId = SessionMask.MAX when one of the legacy ETW sessions changed
2672                     // 0 <= perEventSourceSessionId < SessionMask.MAX for activity-tracing aware sessions
2673                     Debug.Assert(commandArgs.perEventSourceSessionId >= -1 && commandArgs.perEventSourceSessionId <= SessionMask.MAX);
2674
2675                     // Send the manifest if we are enabling an ETW session
2676                     if (bSessionEnable && commandArgs.dispatcher == null)
2677                     {
2678                         // eventSourceDispatcher == null means this is the ETW manifest
2679
2680                         // Note that we unconditionally send the manifest whenever we are enabled, even if
2681                         // we were already enabled.   This is because there may be multiple sessions active
2682                         // and we can't know that all the sessions have seen the manifest.  
2683                         if (!SelfDescribingEvents)
2684                             SendManifest(m_rawManifest);
2685                     }
2686
2687 #if FEATURE_ACTIVITYSAMPLING
2688                     if (bSessionEnable && commandArgs.perEventSourceSessionId != -1)
2689                     {
2690                         bool participateInSampling = false;
2691                         string activityFilters;
2692                         int sessionIdBit;
2693
2694                         ParseCommandArgs(commandArgs.Arguments, out participateInSampling,
2695                                             out activityFilters, out sessionIdBit);
2696
2697                         if (commandArgs.listener == null && commandArgs.Arguments.Count > 0 && commandArgs.perEventSourceSessionId != sessionIdBit)
2698                         {
2699                             throw new ArgumentException(Resources.GetResourceString("EventSource_SessionIdError",
2700                                                     commandArgs.perEventSourceSessionId + SessionMask.SHIFT_SESSION_TO_KEYWORD,
2701                                                         sessionIdBit + SessionMask.SHIFT_SESSION_TO_KEYWORD));
2702                         }
2703
2704                         if (commandArgs.listener == null)
2705                         {
2706                             UpdateEtwSession(commandArgs.perEventSourceSessionId, commandArgs.etwSessionId, true, activityFilters, participateInSampling);
2707                         }
2708                         else
2709                         {
2710                             ActivityFilter.UpdateFilter(ref commandArgs.listener.m_activityFilter, this, 0, activityFilters);
2711                             commandArgs.dispatcher.m_activityFilteringEnabled = participateInSampling;
2712                         }
2713                     }
2714                     else if (!bSessionEnable && commandArgs.listener == null)
2715                     {
2716                         // if we disable an ETW session, indicate that in a synthesized command argument
2717                         if (commandArgs.perEventSourceSessionId >= 0 && commandArgs.perEventSourceSessionId < SessionMask.MAX)
2718                         {
2719                             commandArgs.Arguments["EtwSessionKeyword"] = (commandArgs.perEventSourceSessionId + SessionMask.SHIFT_SESSION_TO_KEYWORD).ToString(CultureInfo.InvariantCulture);
2720                         }
2721                     }
2722 #endif // FEATURE_ACTIVITYSAMPLING
2723
2724                     // Turn on the enable bit before making the OnEventCommand callback  This allows you to do useful
2725                     // things like log messages, or test if keywords are enabled in the callback.  
2726                     if (commandArgs.enable)
2727                     {
2728                         Debug.Assert(m_eventData != null);
2729                         m_eventSourceEnabled = true;
2730                     }
2731
2732                     this.OnEventCommand(commandArgs);
2733                     var eventCommandCallback = this.m_eventCommandExecuted;
2734                     if (eventCommandCallback != null)
2735                         eventCommandCallback(this, commandArgs);
2736
2737 #if FEATURE_ACTIVITYSAMPLING
2738                     if (commandArgs.listener == null && !bSessionEnable && commandArgs.perEventSourceSessionId != -1)
2739                     {
2740                         // if we disable an ETW session, complete disabling it
2741                         UpdateEtwSession(commandArgs.perEventSourceSessionId, commandArgs.etwSessionId, false, null, false);
2742                     }
2743 #endif // FEATURE_ACTIVITYSAMPLING
2744
2745                     if (!commandArgs.enable)
2746                     {
2747                         // If we are disabling, maybe we can turn on 'quick checks' to filter
2748                         // quickly.  These are all just optimizations (since later checks will still filter)
2749
2750 #if FEATURE_ACTIVITYSAMPLING
2751                         // Turn off (and forget) any information about Activity Tracing.  
2752                         if (commandArgs.listener == null)
2753                         {
2754                             // reset all filtering information for activity-tracing-aware sessions
2755                             for (int i = 0; i < SessionMask.MAX; ++i)
2756                             {
2757                                 EtwSession etwSession = m_etwSessionIdMap[i];
2758                                 if (etwSession != null)
2759                                     ActivityFilter.DisableFilter(ref etwSession.m_activityFilter, this);
2760                             }
2761                             m_activityFilteringForETWEnabled = new SessionMask(0);
2762                             m_curLiveSessions = new SessionMask(0);
2763                             // reset activity-tracing-aware sessions
2764                             if (m_etwSessionIdMap != null)
2765                                 for (int i = 0; i < SessionMask.MAX; ++i)
2766                                     m_etwSessionIdMap[i] = null;
2767                             // reset legacy sessions
2768                             if (m_legacySessions != null)
2769                                 m_legacySessions.Clear();
2770                         }
2771                         else
2772                         {
2773                             ActivityFilter.DisableFilter(ref commandArgs.listener.m_activityFilter, this);
2774                             commandArgs.dispatcher.m_activityFilteringEnabled = false;
2775                         }
2776 #endif // FEATURE_ACTIVITYSAMPLING
2777
2778                         // There is a good chance EnabledForAnyListener are not as accurate as
2779                         // they could be, go ahead and get a better estimate.  
2780                         for (int i = 0; i < m_eventData.Length; i++)
2781                         {
2782                             bool isEnabledForAnyListener = false;
2783                             for (EventDispatcher dispatcher = m_Dispatchers; dispatcher != null; dispatcher = dispatcher.m_Next)
2784                             {
2785                                 if (dispatcher.m_EventEnabled[i])
2786                                 {
2787                                     isEnabledForAnyListener = true;
2788                                     break;
2789                                 }
2790                             }
2791                             m_eventData[i].EnabledForAnyListener = isEnabledForAnyListener;
2792                         }
2793
2794                         // If no events are enabled, disable the global enabled bit.
2795                         if (!AnyEventEnabled())
2796                         {
2797                             m_level = 0;
2798                             m_matchAnyKeyword = 0;
2799                             m_eventSourceEnabled = false;
2800                         }
2801                     }
2802 #if FEATURE_ACTIVITYSAMPLING
2803                     UpdateKwdTriggers(commandArgs.enable);
2804 #endif // FEATURE_ACTIVITYSAMPLING
2805                 }
2806                 else
2807                 {
2808                     if (commandArgs.Command == EventCommand.SendManifest)
2809                     {
2810                         // TODO: should we generate the manifest here if we hadn't already?
2811                         if (m_rawManifest != null)
2812                             SendManifest(m_rawManifest);
2813                     }
2814
2815                     // These are not used for non-update commands and thus should always be 'default' values
2816                     // Debug.Assert(enable == true);
2817                     // Debug.Assert(level == EventLevel.LogAlways);
2818                     // Debug.Assert(matchAnyKeyword == EventKeywords.None);
2819
2820                     this.OnEventCommand(commandArgs);
2821                     var eventCommandCallback = m_eventCommandExecuted;
2822                     if (eventCommandCallback != null)
2823                         eventCommandCallback(this, commandArgs);
2824                 }
2825
2826 #if FEATURE_ACTIVITYSAMPLING
2827                 if (m_completelyInited && (commandArgs.listener != null || shouldReport))
2828                 {
2829                     SessionMask m = SessionMask.FromId(commandArgs.perEventSourceSessionId);
2830                     ReportActivitySamplingInfo(commandArgs.listener, m);
2831                 }
2832 #endif // FEATURE_ACTIVITYSAMPLING
2833             }
2834             catch (Exception e)
2835             {
2836                 // When the ETW session is created after the EventSource has registered with the ETW system
2837                 // we can send any error messages here.
2838                 ReportOutOfBandMessage("ERROR: Exception in Command Processing for EventSource " + Name + ": " + e.Message, true);
2839                 // We never throw when doing a command.  
2840             }
2841         }
2842
2843 #if FEATURE_ACTIVITYSAMPLING
2844
2845         internal void UpdateEtwSession(
2846             int sessionIdBit,
2847             int etwSessionId,
2848             bool bEnable,
2849             string activityFilters,
2850             bool participateInSampling)
2851         {
2852             if (sessionIdBit < SessionMask.MAX)
2853             {
2854                 // activity-tracing-aware etw session
2855                 if (bEnable)
2856                 {
2857                     var etwSession = EtwSession.GetEtwSession(etwSessionId, true);
2858                     ActivityFilter.UpdateFilter(ref etwSession.m_activityFilter, this, sessionIdBit, activityFilters);
2859                     m_etwSessionIdMap[sessionIdBit] = etwSession;
2860                     m_activityFilteringForETWEnabled[sessionIdBit] = participateInSampling;
2861                 }
2862                 else
2863                 {
2864                     var etwSession = EtwSession.GetEtwSession(etwSessionId);
2865                     m_etwSessionIdMap[sessionIdBit] = null;
2866                     m_activityFilteringForETWEnabled[sessionIdBit] = false;
2867                     if (etwSession != null)
2868                     {
2869                         ActivityFilter.DisableFilter(ref etwSession.m_activityFilter, this);
2870                         // the ETW session is going away; remove it from the global list
2871                         EtwSession.RemoveEtwSession(etwSession);
2872                     }
2873                 }
2874                 m_curLiveSessions[sessionIdBit] = bEnable;
2875             }
2876             else
2877             {
2878                 // legacy etw session    
2879                 if (bEnable)
2880                 {
2881                     if (m_legacySessions == null)
2882                         m_legacySessions = new List<EtwSession>(8);
2883                     var etwSession = EtwSession.GetEtwSession(etwSessionId, true);
2884                     if (!m_legacySessions.Contains(etwSession))
2885                         m_legacySessions.Add(etwSession);
2886                 }
2887                 else
2888                 {
2889                     var etwSession = EtwSession.GetEtwSession(etwSessionId);
2890                     if (etwSession != null)
2891                     {
2892                         if (m_legacySessions != null)
2893                             m_legacySessions.Remove(etwSession);
2894                         // the ETW session is going away; remove it from the global list
2895                         EtwSession.RemoveEtwSession(etwSession);
2896                     }
2897                 }
2898             }
2899         }
2900
2901         internal static bool ParseCommandArgs(
2902                         IDictionary<string, string> commandArguments,
2903                         out bool participateInSampling,
2904                         out string activityFilters,
2905                         out int sessionIdBit)
2906         {
2907             bool res = true;
2908             participateInSampling = false;
2909             string activityFilterString;
2910             if (commandArguments.TryGetValue("ActivitySamplingStartEvent", out activityFilters))
2911             {
2912                 // if a start event is specified default the event source to participate in sampling
2913                 participateInSampling = true;
2914             }
2915
2916             if (commandArguments.TryGetValue("ActivitySampling", out activityFilterString))
2917             {
2918                 if (string.Compare(activityFilterString, "false", StringComparison.OrdinalIgnoreCase) == 0 ||
2919                     activityFilterString == "0")
2920                     participateInSampling = false;
2921                 else
2922                     participateInSampling = true;
2923             }
2924
2925             string sSessionKwd;
2926             int sessionKwd = -1;
2927             if (!commandArguments.TryGetValue("EtwSessionKeyword", out sSessionKwd) ||
2928                 !int.TryParse(sSessionKwd, out sessionKwd) ||
2929                 sessionKwd < SessionMask.SHIFT_SESSION_TO_KEYWORD ||
2930                 sessionKwd >= SessionMask.SHIFT_SESSION_TO_KEYWORD + SessionMask.MAX)
2931             {
2932                 sessionIdBit = -1;
2933                 res = false;
2934             }
2935             else
2936             {
2937                 sessionIdBit = sessionKwd - SessionMask.SHIFT_SESSION_TO_KEYWORD;
2938             }
2939             return res;
2940         }
2941
2942         internal void UpdateKwdTriggers(bool enable)
2943         {
2944             if (enable)
2945             {
2946                 // recompute m_keywordTriggers
2947                 ulong gKeywords = unchecked((ulong)m_matchAnyKeyword);
2948                 if (gKeywords == 0)
2949                     gKeywords = 0xFFFFffffFFFFffff;
2950
2951                 m_keywordTriggers = 0;
2952                 for (int sessId = 0; sessId < SessionMask.MAX; ++sessId)
2953                 {
2954                     EtwSession etwSession = m_etwSessionIdMap[sessId];
2955                     if (etwSession == null)
2956                         continue;
2957
2958                     ActivityFilter activityFilter = etwSession.m_activityFilter;
2959                     ActivityFilter.UpdateKwdTriggers(activityFilter, m_guid, this, unchecked((EventKeywords)gKeywords));
2960                 }
2961             }
2962             else
2963             {
2964                 m_keywordTriggers = 0;
2965             }
2966         }
2967
2968 #endif // FEATURE_ACTIVITYSAMPLING
2969
2970         /// <summary>
2971         /// If 'value is 'true' then set the eventSource so that 'dispatcher' will receive event with the eventId
2972         /// of 'eventId.  If value is 'false' disable the event for that dispatcher.   If 'eventId' is out of
2973         /// range return false, otherwise true.  
2974         /// </summary>
2975         internal bool EnableEventForDispatcher(EventDispatcher dispatcher, int eventId, bool value)
2976         {
2977             if (dispatcher == null)
2978             {
2979                 if (eventId >= m_eventData.Length)
2980                     return false;
2981 #if FEATURE_MANAGED_ETW
2982                 if (m_provider != null)
2983                     m_eventData[eventId].EnabledForETW = value;
2984 #endif
2985             }
2986             else
2987             {
2988                 if (eventId >= dispatcher.m_EventEnabled.Length)
2989                     return false;
2990                 dispatcher.m_EventEnabled[eventId] = value;
2991                 if (value)
2992                     m_eventData[eventId].EnabledForAnyListener = true;
2993             }
2994             return true;
2995         }
2996
2997         /// <summary>
2998         /// Returns true if any event at all is on.  
2999         /// </summary>
3000         private bool AnyEventEnabled()
3001         {
3002             for (int i = 0; i < m_eventData.Length; i++)
3003                 if (m_eventData[i].EnabledForETW || m_eventData[i].EnabledForAnyListener)
3004                     return true;
3005             return false;
3006         }
3007
3008         private bool IsDisposed
3009         {
3010             get { return m_eventSourceDisposed; }
3011         }
3012
3013         private void EnsureDescriptorsInitialized()
3014         {
3015 #if !ES_BUILD_STANDALONE
3016             Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
3017 #endif
3018             if (m_eventData == null)
3019             {
3020                 Guid eventSourceGuid = Guid.Empty;
3021                 string eventSourceName = null;
3022                 EventMetadata[] eventData = null;
3023                 byte[] manifest = null;
3024
3025                 // Try the GetMetadata provided by the ILTransform in ProjectN. The default sets all to null, and in that case we fall back
3026                 // to the reflection approach.
3027                 GetMetadata(out eventSourceGuid, out eventSourceName, out eventData, out manifest);
3028
3029                 if (eventSourceGuid.Equals(Guid.Empty) || eventSourceName == null || eventData == null || manifest == null)
3030                 {
3031                     // GetMetadata failed, so we have to set it via reflection.
3032                     Debug.Assert(m_rawManifest == null);
3033                     m_rawManifest = CreateManifestAndDescriptors(this.GetType(), Name, this);
3034                     Debug.Assert(m_eventData != null);
3035
3036                 }
3037                 else
3038                 {
3039                     // GetMetadata worked, so set the fields as appropriate.
3040                     m_name = eventSourceName;
3041                     m_guid = eventSourceGuid;
3042                     m_eventData = eventData;
3043                     m_rawManifest = manifest;
3044                 }
3045                 // TODO Enforce singleton pattern 
3046                 foreach (WeakReference eventSourceRef in EventListener.s_EventSources)
3047                 {
3048                     EventSource eventSource = eventSourceRef.Target as EventSource;
3049                     if (eventSource != null && eventSource.Guid == m_guid && !eventSource.IsDisposed)
3050                     {
3051                         if (eventSource != this)
3052                         {
3053                             throw new ArgumentException(Resources.GetResourceString("EventSource_EventSourceGuidInUse", m_guid));
3054                         }
3055                     }
3056                 }
3057
3058                 // Make certain all dispatchers also have their arrays initialized
3059                 EventDispatcher dispatcher = m_Dispatchers;
3060                 while (dispatcher != null)
3061                 {
3062                     if (dispatcher.m_EventEnabled == null)
3063                         dispatcher.m_EventEnabled = new bool[m_eventData.Length];
3064                     dispatcher = dispatcher.m_Next;
3065                 }
3066             }
3067             if (s_currentPid == 0)
3068             {
3069 #if ES_BUILD_STANDALONE && !ES_BUILD_PCL && !CORECLR
3070                 // for non-BCL EventSource we must assert SecurityPermission
3071                 new SecurityPermission(PermissionState.Unrestricted).Assert();
3072 #endif
3073                 s_currentPid = Win32Native.GetCurrentProcessId();
3074             }
3075         }
3076
3077         // Send out the ETW manifest XML out to ETW
3078         // Today, we only send the manifest to ETW, custom listeners don't get it. 
3079         private unsafe bool SendManifest(byte[] rawManifest)
3080         {
3081             bool success = true;
3082
3083             if (rawManifest == null)
3084                 return false;
3085
3086             Debug.Assert(!SelfDescribingEvents);
3087
3088 #if FEATURE_MANAGED_ETW
3089             fixed (byte* dataPtr = rawManifest)
3090             {
3091                 // we don't want the manifest to show up in the event log channels so we specify as keywords 
3092                 // everything but the first 8 bits (reserved for the 8 channels)
3093                 var manifestDescr = new EventDescriptor(0xFFFE, 1, 0, 0, 0xFE, 0xFFFE, 0x00ffFFFFffffFFFF);
3094                 ManifestEnvelope envelope = new ManifestEnvelope();
3095
3096                 envelope.Format = ManifestEnvelope.ManifestFormats.SimpleXmlFormat;
3097                 envelope.MajorVersion = 1;
3098                 envelope.MinorVersion = 0;
3099                 envelope.Magic = 0x5B;              // An unusual number that can be checked for consistency. 
3100                 int dataLeft = rawManifest.Length;
3101                 envelope.ChunkNumber = 0;
3102
3103                 EventProvider.EventData* dataDescrs = stackalloc EventProvider.EventData[2];
3104
3105                 dataDescrs[0].Ptr = (ulong)&envelope;
3106                 dataDescrs[0].Size = (uint)sizeof(ManifestEnvelope);
3107                 dataDescrs[0].Reserved = 0;
3108
3109                 dataDescrs[1].Ptr = (ulong)dataPtr;
3110                 dataDescrs[1].Reserved = 0;
3111
3112                 int chunkSize = ManifestEnvelope.MaxChunkSize;
3113                 TRY_AGAIN_WITH_SMALLER_CHUNK_SIZE:
3114                 envelope.TotalChunks = (ushort)((dataLeft + (chunkSize - 1)) / chunkSize);
3115                 while (dataLeft > 0)
3116                 {
3117                     dataDescrs[1].Size = (uint)Math.Min(dataLeft, chunkSize);
3118                     if (m_provider != null)
3119                     {
3120                         if (!m_provider.WriteEvent(ref manifestDescr, null, null, 2, (IntPtr)dataDescrs))
3121                         {
3122                             // Turns out that if users set the BufferSize to something less than 64K then WriteEvent
3123                             // can fail.   If we get this failure on the first chunk try again with something smaller
3124                             // The smallest BufferSize is 1K so if we get to 256 (to account for envelope overhead), we can give up making it smaller. 
3125                             if (EventProvider.GetLastWriteEventError() == EventProvider.WriteEventErrorCode.EventTooBig)
3126                             {
3127                                 if (envelope.ChunkNumber == 0 && chunkSize > 256)
3128                                 {
3129                                     chunkSize = chunkSize / 2;
3130                                     goto TRY_AGAIN_WITH_SMALLER_CHUNK_SIZE;
3131                                 }
3132                             }
3133                             success = false;
3134                             if (ThrowOnEventWriteErrors)
3135                                 ThrowEventSourceException("SendManifest");
3136                             break;
3137                         }
3138                     }
3139                     dataLeft -= chunkSize;
3140                     dataDescrs[1].Ptr += (uint)chunkSize;
3141                     envelope.ChunkNumber++;
3142
3143                     // For large manifests we want to not overflow any receiver's buffer. Most manifests will fit within
3144                     // 5 chunks, so only the largest manifests will hit the pause.
3145                     if ((envelope.ChunkNumber % 5) == 0)
3146                     {
3147                         RuntimeThread.Sleep(15);
3148                     }
3149                 }
3150             }
3151 #endif // FEATURE_MANAGED_ETW
3152             return success;
3153         }
3154
3155 #if (ES_BUILD_PCL)
3156         internal static Attribute GetCustomAttributeHelper(Type type, Type attributeType, EventManifestOptions flags = EventManifestOptions.None)
3157         {
3158             return GetCustomAttributeHelper(type.GetTypeInfo(), attributeType, flags);
3159         }
3160 #endif
3161
3162         // Helper to deal with the fact that the type we are reflecting over might be loaded in the ReflectionOnly context.
3163         // When that is the case, we have the build the custom assemblies on a member by hand.         
3164         internal static Attribute GetCustomAttributeHelper(MemberInfo member, Type attributeType, EventManifestOptions flags = EventManifestOptions.None)
3165         {
3166             if (!member.Module.Assembly.ReflectionOnly() && (flags & EventManifestOptions.AllowEventSourceOverride) == 0)
3167             {
3168                 // Let the runtime to the work for us, since we can execute code in this context.
3169                 Attribute firstAttribute = null;
3170                 foreach (var attribute in member.GetCustomAttributes(attributeType, false))
3171                 {
3172                     firstAttribute = (Attribute)attribute;
3173                     break;
3174                 }
3175                 return firstAttribute;
3176             }
3177
3178 #if (!ES_BUILD_PCL && !ES_BUILD_PN)
3179             // In the reflection only context, we have to do things by hand.
3180             string fullTypeNameToFind = attributeType.FullName;
3181
3182 #if EVENT_SOURCE_LEGACY_NAMESPACE_SUPPORT
3183             fullTypeNameToFind = fullTypeNameToFind.Replace("System.Diagnostics.Eventing", "System.Diagnostics.Tracing");
3184 #endif
3185
3186             foreach (CustomAttributeData data in CustomAttributeData.GetCustomAttributes(member))
3187             {
3188                 if (AttributeTypeNamesMatch(attributeType, data.Constructor.ReflectedType))
3189                 {
3190                     Attribute attr = null;
3191
3192                     Debug.Assert(data.ConstructorArguments.Count <= 1);
3193
3194                     if (data.ConstructorArguments.Count == 1)
3195                     {
3196                         attr = (Attribute)Activator.CreateInstance(attributeType, new object[] { data.ConstructorArguments[0].Value });
3197                     }
3198                     else if (data.ConstructorArguments.Count == 0)
3199                     {
3200                         attr = (Attribute)Activator.CreateInstance(attributeType);
3201                     }
3202
3203                     if (attr != null)
3204                     {
3205                         Type t = attr.GetType();
3206
3207                         foreach (CustomAttributeNamedArgument namedArgument in data.NamedArguments)
3208                         {
3209                             PropertyInfo p = t.GetProperty(namedArgument.MemberInfo.Name, BindingFlags.Public | BindingFlags.Instance);
3210                             object value = namedArgument.TypedValue.Value;
3211
3212                             if (p.PropertyType.IsEnum)
3213                             {
3214                                 value = Enum.Parse(p.PropertyType, value.ToString());
3215                             }
3216
3217                             p.SetValue(attr, value, null);
3218                         }
3219
3220                         return attr;
3221                     }
3222                 }
3223             }
3224
3225             return null;
3226 #else // ES_BUILD_PCL && ES_BUILD_PN
3227             // Don't use nameof here because the resource doesn't exist on some platforms, which results in a compilation error.
3228             throw new ArgumentException(Resources.GetResourceString("EventSource", "EventSource_PCLPlatformNotSupportedReflection"));
3229 #endif
3230         }
3231
3232         /// <summary>
3233         /// Evaluates if two related "EventSource"-domain types should be considered the same
3234         /// </summary>
3235         /// <param name="attributeType">The attribute type in the load context - it's associated with the running 
3236         /// EventSource type. This type may be different fromt he base type of the user-defined EventSource.</param>
3237         /// <param name="reflectedAttributeType">The attribute type in the reflection context - it's associated with
3238         /// the user-defined EventSource, and is in the same assembly as the eventSourceType passed to 
3239         /// </param>
3240         /// <returns>True - if the types should be considered equivalent, False - otherwise</returns>
3241         private static bool AttributeTypeNamesMatch(Type attributeType, Type reflectedAttributeType)
3242         {
3243             return
3244                 // are these the same type?
3245                 attributeType == reflectedAttributeType ||
3246                 // are the full typenames equal?
3247                 string.Equals(attributeType.FullName, reflectedAttributeType.FullName, StringComparison.Ordinal) ||
3248                     // are the typenames equal and the namespaces under "Diagnostics.Tracing" (typically
3249                     // either Microsoft.Diagnostics.Tracing or System.Diagnostics.Tracing)?
3250                     string.Equals(attributeType.Name, reflectedAttributeType.Name, StringComparison.Ordinal) &&
3251                     attributeType.Namespace.EndsWith("Diagnostics.Tracing", StringComparison.Ordinal) &&
3252                     (reflectedAttributeType.Namespace.EndsWith("Diagnostics.Tracing", StringComparison.Ordinal)
3253 #if EVENT_SOURCE_LEGACY_NAMESPACE_SUPPORT
3254                      || reflectedAttributeType.Namespace.EndsWith("Diagnostics.Eventing", StringComparison.Ordinal)
3255 #endif
3256 );
3257         }
3258
3259         private static Type GetEventSourceBaseType(Type eventSourceType, bool allowEventSourceOverride, bool reflectionOnly)
3260         {
3261             // return false for "object" and interfaces
3262             if (eventSourceType.BaseType() == null)
3263                 return null;
3264
3265             // now go up the inheritance chain until hitting a concrete type ("object" at worse)
3266             do
3267             {
3268                 eventSourceType = eventSourceType.BaseType();
3269             }
3270             while (eventSourceType != null && eventSourceType.IsAbstract());
3271
3272             if (eventSourceType != null)
3273             {
3274                 if (!allowEventSourceOverride)
3275                 {
3276                     if (reflectionOnly && eventSourceType.FullName != typeof(EventSource).FullName ||
3277                         !reflectionOnly && eventSourceType != typeof(EventSource))
3278                         return null;
3279                 }
3280                 else
3281                 {
3282                     if (eventSourceType.Name != "EventSource")
3283                         return null;
3284                 }
3285             }
3286             return eventSourceType;
3287         }
3288
3289         // Use reflection to look at the attributes of a class, and generate a manifest for it (as UTF8) and
3290         // return the UTF8 bytes.  It also sets up the code:EventData structures needed to dispatch events
3291         // at run time.  'source' is the event source to place the descriptors.  If it is null,
3292         // then the descriptors are not creaed, and just the manifest is generated.  
3293         private static byte[] CreateManifestAndDescriptors(Type eventSourceType, string eventSourceDllName, EventSource source,
3294             EventManifestOptions flags = EventManifestOptions.None)
3295         {
3296             ManifestBuilder manifest = null;
3297             bool bNeedsManifest = source != null ? !source.SelfDescribingEvents : true;
3298             Exception exception = null; // exception that might get raised during validation b/c we couldn't/didn't recover from a previous error
3299             byte[] res = null;
3300
3301             if (eventSourceType.IsAbstract() && (flags & EventManifestOptions.Strict) == 0)
3302                 return null;
3303
3304 #if DEBUG && ES_BUILD_STANDALONE
3305             TestSupport.TestHooks.MaybeThrow(eventSourceType,
3306                                         TestSupport.Category.ManifestError,
3307                                         "EventSource_CreateManifestAndDescriptors",
3308                                         new ArgumentException("EventSource_CreateManifestAndDescriptors"));
3309 #endif
3310
3311             try
3312             {
3313                 MethodInfo[] methods = eventSourceType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
3314                 EventAttribute defaultEventAttribute;
3315                 int eventId = 1;        // The number given to an event that does not have a explicitly given ID. 
3316                 EventMetadata[] eventData = null;
3317                 Dictionary<string, string> eventsByName = null;
3318                 if (source != null || (flags & EventManifestOptions.Strict) != 0)
3319                 {
3320                     eventData = new EventMetadata[methods.Length + 1];
3321                     eventData[0].Name = "";         // Event 0 is the 'write messages string' event, and has an empty name.
3322                 }
3323
3324                 // See if we have localization information.  
3325                 ResourceManager resources = null;
3326                 EventSourceAttribute eventSourceAttrib = (EventSourceAttribute)GetCustomAttributeHelper(eventSourceType, typeof(EventSourceAttribute), flags);
3327                 if (eventSourceAttrib != null && eventSourceAttrib.LocalizationResources != null)
3328                     resources = new ResourceManager(eventSourceAttrib.LocalizationResources, eventSourceType.Assembly());
3329
3330                 manifest = new ManifestBuilder(GetName(eventSourceType, flags), GetGuid(eventSourceType), eventSourceDllName,
3331                                                resources, flags);
3332
3333                 // Add an entry unconditionally for event ID 0 which will be for a string message.  
3334                 manifest.StartEvent("EventSourceMessage", new EventAttribute(0) { Level = EventLevel.LogAlways, Task = (EventTask)0xFFFE });
3335                 manifest.AddEventParameter(typeof(string), "message");
3336                 manifest.EndEvent();
3337
3338                 // eventSourceType must be sealed and must derive from this EventSource
3339                 if ((flags & EventManifestOptions.Strict) != 0)
3340                 {
3341                     bool typeMatch = GetEventSourceBaseType(eventSourceType, (flags & EventManifestOptions.AllowEventSourceOverride) != 0, eventSourceType.Assembly().ReflectionOnly()) != null;
3342
3343                     if (!typeMatch)
3344                     {
3345                         manifest.ManifestError(Resources.GetResourceString("EventSource_TypeMustDeriveFromEventSource"));
3346                     }
3347                     if (!eventSourceType.IsAbstract() && !eventSourceType.IsSealed())
3348                     {
3349                         manifest.ManifestError(Resources.GetResourceString("EventSource_TypeMustBeSealedOrAbstract"));
3350                     }
3351                 }
3352
3353                 // Collect task, opcode, keyword and channel information
3354 #if FEATURE_MANAGED_ETW_CHANNELS && FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
3355                 foreach (var providerEnumKind in new string[] { "Keywords", "Tasks", "Opcodes", "Channels" })
3356 #else
3357                 foreach (var providerEnumKind in new string[] { "Keywords", "Tasks", "Opcodes" })
3358 #endif
3359                 {
3360                     Type nestedType = eventSourceType.GetNestedType(providerEnumKind);
3361                     if (nestedType != null)
3362                     {
3363                         if (eventSourceType.IsAbstract())
3364                         {
3365                             manifest.ManifestError(Resources.GetResourceString("EventSource_AbstractMustNotDeclareKTOC", nestedType.Name));
3366                         }
3367                         else
3368                         {
3369                             foreach (FieldInfo staticField in nestedType.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static))
3370                             {
3371                                 AddProviderEnumKind(manifest, staticField, providerEnumKind);
3372                             }
3373                         }
3374                     }
3375                 }
3376                 // ensure we have keywords for the session-filtering reserved bits
3377                 {
3378                     manifest.AddKeyword("Session3", (long)0x1000 << 32);
3379                     manifest.AddKeyword("Session2", (long)0x2000 << 32);
3380                     manifest.AddKeyword("Session1", (long)0x4000 << 32);
3381                     manifest.AddKeyword("Session0", (long)0x8000 << 32);
3382                 }
3383
3384                 if (eventSourceType != typeof(EventSource))
3385                 {
3386                     for (int i = 0; i < methods.Length; i++)
3387                     {
3388                         MethodInfo method = methods[i];
3389                         ParameterInfo[] args = method.GetParameters();
3390
3391                         // Get the EventDescriptor (from the Custom attributes)
3392                         EventAttribute eventAttribute = (EventAttribute)GetCustomAttributeHelper(method, typeof(EventAttribute), flags);
3393
3394                         // Compat: until v4.5.1 we ignored any non-void returning methods as well as virtual methods for 
3395                         // the only reason of limiting the number of methods considered to be events. This broke a common 
3396                         // design of having event sources implement specific interfaces. To fix this in a compatible way
3397                         // we will now allow both non-void returning and virtual methods to be Event methods, as long 
3398                         // as they are marked with the [Event] attribute
3399                         if (/* method.IsVirtual || */ method.IsStatic)
3400                         {
3401                             continue;
3402                         }
3403
3404                         if (eventSourceType.IsAbstract())
3405                         {
3406                             if (eventAttribute != null)
3407                             {
3408                                 manifest.ManifestError(Resources.GetResourceString("EventSource_AbstractMustNotDeclareEventMethods", method.Name, eventAttribute.EventId));
3409                             }
3410                             continue;
3411                         }
3412                         else if (eventAttribute == null)
3413                         {
3414                             // Methods that don't return void can't be events, if they're NOT marked with [Event].
3415                             // (see Compat comment above)
3416                             if (method.ReturnType != typeof(void))
3417                             {
3418                                 continue;
3419                             }
3420
3421                             // Continue to ignore virtual methods if they do NOT have the [Event] attribute
3422                             // (see Compat comment above)
3423                             if (method.IsVirtual)
3424                             {
3425                                 continue;
3426                             }
3427
3428                             // If we explicitly mark the method as not being an event, then honor that.  
3429                             if (GetCustomAttributeHelper(method, typeof(NonEventAttribute), flags) != null)
3430                                 continue;
3431
3432                             defaultEventAttribute = new EventAttribute(eventId);
3433                             eventAttribute = defaultEventAttribute;
3434                         }
3435                         else if (eventAttribute.EventId <= 0)
3436                         {
3437                             manifest.ManifestError(Resources.GetResourceString("EventSource_NeedPositiveId", method.Name), true);
3438                             continue;   // don't validate anything else for this event
3439                         }
3440                         if (method.Name.LastIndexOf('.') >= 0)
3441                         {
3442                             manifest.ManifestError(Resources.GetResourceString("EventSource_EventMustNotBeExplicitImplementation", method.Name, eventAttribute.EventId));
3443                         }
3444
3445                         eventId++;
3446                         string eventName = method.Name;
3447
3448                         if (eventAttribute.Opcode == EventOpcode.Info)      // We are still using the default opcode. 
3449                         {
3450                             // By default pick a task ID derived from the EventID, starting with the highest task number and working back 
3451                             bool noTask = (eventAttribute.Task == EventTask.None);
3452                             if (noTask)
3453                                 eventAttribute.Task = (EventTask)(0xFFFE - eventAttribute.EventId);
3454
3455                             // Unless we explicitly set the opcode to Info (to override the auto-generate of Start or Stop opcodes, 
3456                             // pick a default opcode based on the event name (either Info or start or stop if the name ends with that suffix).  
3457                             if (!eventAttribute.IsOpcodeSet)
3458                                 eventAttribute.Opcode = GetOpcodeWithDefault(EventOpcode.Info, eventName);
3459
3460                             // Make the stop opcode have the same task as the start opcode.
3461                             if (noTask)
3462                             {
3463                                 if (eventAttribute.Opcode == EventOpcode.Start)
3464                                 {
3465                                     string taskName = eventName.Substring(0, eventName.Length - s_ActivityStartSuffix.Length); // Remove the Stop suffix to get the task name
3466                                     if (string.Compare(eventName, 0, taskName, 0, taskName.Length) == 0 &&
3467                                         string.Compare(eventName, taskName.Length, s_ActivityStartSuffix, 0, Math.Max(eventName.Length - taskName.Length, s_ActivityStartSuffix.Length)) == 0)
3468                                     {
3469                                         // Add a task that is just the task name for the start event.   This suppress the auto-task generation
3470                                         // That would otherwise happen (and create 'TaskName'Start as task name rather than just 'TaskName'
3471                                         manifest.AddTask(taskName, (int)eventAttribute.Task);
3472                                     }
3473                                 }
3474                                 else if (eventAttribute.Opcode == EventOpcode.Stop)
3475                                 {
3476                                     // Find the start associated with this stop event.  We require start to be immediately before the stop
3477                                     int startEventId = eventAttribute.EventId - 1;
3478                                     if (eventData != null && startEventId < eventData.Length)
3479                                     {
3480                                         Debug.Assert(0 <= startEventId);                // Since we reserve id 0, we know that id-1 is <= 0
3481                                         EventMetadata startEventMetadata = eventData[startEventId];
3482
3483                                         // If you remove the Stop and add a Start does that name match the Start Event's Name?
3484                                         // Ideally we would throw an error 
3485                                         string taskName = eventName.Substring(0, eventName.Length - s_ActivityStopSuffix.Length); // Remove the Stop suffix to get the task name
3486                                         if (startEventMetadata.Descriptor.Opcode == (byte)EventOpcode.Start &&
3487                                             string.Compare(startEventMetadata.Name, 0, taskName, 0, taskName.Length) == 0 &&
3488                                             string.Compare(startEventMetadata.Name, taskName.Length, s_ActivityStartSuffix, 0, Math.Max(startEventMetadata.Name.Length - taskName.Length, s_ActivityStartSuffix.Length)) == 0)
3489                                         {
3490
3491                                             // Make the stop event match the start event
3492                                             eventAttribute.Task = (EventTask)startEventMetadata.Descriptor.Task;
3493                                             noTask = false;
3494                                         }
3495                                     }
3496                                     if (noTask && (flags & EventManifestOptions.Strict) != 0)        // Throw an error if we can compatibly.   
3497                                     {
3498                                         throw new ArgumentException(Resources.GetResourceString("EventSource_StopsFollowStarts"));
3499                                     }
3500                                 }
3501                             }
3502                         }
3503
3504                         bool hasRelatedActivityID = RemoveFirstArgIfRelatedActivityId(ref args);
3505                         if (!(source != null && source.SelfDescribingEvents))
3506                         {
3507                             manifest.StartEvent(eventName, eventAttribute);
3508                             for (int fieldIdx = 0; fieldIdx < args.Length; fieldIdx++)
3509                             {
3510                                 manifest.AddEventParameter(args[fieldIdx].ParameterType, args[fieldIdx].Name);
3511                             }
3512                             manifest.EndEvent();
3513                         }
3514
3515                         if (source != null || (flags & EventManifestOptions.Strict) != 0)
3516                         {
3517                             // Do checking for user errors (optional, but not a big deal so we do it).  
3518                             DebugCheckEvent(ref eventsByName, eventData, method, eventAttribute, manifest, flags);
3519
3520 #if FEATURE_MANAGED_ETW_CHANNELS
3521                             // add the channel keyword for Event Viewer channel based filters. This is added for creating the EventDescriptors only
3522                             // and is not required for the manifest
3523                             if (eventAttribute.Channel != EventChannel.None)
3524                             {
3525                                 unchecked
3526                                 {
3527                                     eventAttribute.Keywords |= (EventKeywords)manifest.GetChannelKeyword(eventAttribute.Channel, (ulong)eventAttribute.Keywords);
3528                                 }
3529                             }
3530 #endif
3531                             string eventKey = "event_" + eventName;
3532                             string msg = manifest.GetLocalizedMessage(eventKey, CultureInfo.CurrentUICulture, etwFormat: false);
3533                             // overwrite inline message with the localized message
3534                             if (msg != null) eventAttribute.Message = msg;
3535
3536                             AddEventDescriptor(ref eventData, eventName, eventAttribute, args, hasRelatedActivityID);
3537                         }
3538                     }
3539                 }
3540
3541                 // Tell the TraceLogging stuff where to start allocating its own IDs.  
3542                 NameInfo.ReserveEventIDsBelow(eventId);
3543
3544                 if (source != null)
3545                 {
3546                     TrimEventDescriptors(ref eventData);
3547                     source.m_eventData = eventData;     // officially initialize it. We do this at most once (it is racy otherwise). 
3548 #if FEATURE_MANAGED_ETW_CHANNELS
3549                     source.m_channelData = manifest.GetChannelData();
3550 #endif
3551                 }
3552
3553                 // if this is an abstract event source we've already performed all the validation we can
3554                 if (!eventSourceType.IsAbstract() && (source == null || !source.SelfDescribingEvents))
3555                 {
3556                     bNeedsManifest = (flags & EventManifestOptions.OnlyIfNeededForRegistration) == 0
3557 #if FEATURE_MANAGED_ETW_CHANNELS
3558                                             || manifest.GetChannelData().Length > 0
3559 #endif
3560 ;
3561
3562                     // if the manifest is not needed and we're not requested to validate the event source return early
3563                     if (!bNeedsManifest && (flags & EventManifestOptions.Strict) == 0)
3564                         return null;
3565
3566                     res = manifest.CreateManifest();
3567                 }
3568             }
3569             catch (Exception e)
3570             {
3571                 // if this is a runtime manifest generation let the exception propagate
3572                 if ((flags & EventManifestOptions.Strict) == 0)
3573                     throw;
3574                 // else store it to include it in the Argument exception we raise below
3575                 exception = e;
3576             }
3577
3578             if ((flags & EventManifestOptions.Strict) != 0 && (manifest.Errors.Count > 0 || exception != null))
3579             {
3580                 string msg = String.Empty;
3581                 if (manifest.Errors.Count > 0)
3582                 {
3583                     bool firstError = true;
3584                     foreach (string error in manifest.Errors)
3585                     {
3586                         if (!firstError)
3587                             msg += Environment.NewLine;
3588                         firstError = false;
3589                         msg += error;
3590                     }
3591                 }
3592                 else
3593                     msg = "Unexpected error: " + exception.Message;
3594
3595                 throw new ArgumentException(msg, exception);
3596             }
3597
3598             return bNeedsManifest ? res : null;
3599         }
3600
3601         private static bool RemoveFirstArgIfRelatedActivityId(ref ParameterInfo[] args)
3602         {
3603             // If the first parameter is (case insensitive) 'relatedActivityId' then skip it.  
3604             if (args.Length > 0 && args[0].ParameterType == typeof(Guid) &&
3605                 string.Compare(args[0].Name, "relatedActivityId", StringComparison.OrdinalIgnoreCase) == 0)
3606             {
3607                 var newargs = new ParameterInfo[args.Length - 1];
3608                 Array.Copy(args, 1, newargs, 0, args.Length - 1);
3609                 args = newargs;
3610
3611                 return true;
3612             }
3613
3614             return false;
3615         }
3616
3617         // adds a enumeration (keyword, opcode, task or channel) represented by 'staticField'
3618         // to the manifest.  
3619         private static void AddProviderEnumKind(ManifestBuilder manifest, FieldInfo staticField, string providerEnumKind)
3620         {
3621             bool reflectionOnly = staticField.Module.Assembly.ReflectionOnly();
3622             Type staticFieldType = staticField.FieldType;
3623             if (!reflectionOnly && (staticFieldType == typeof(EventOpcode)) || AttributeTypeNamesMatch(staticFieldType, typeof(EventOpcode)))
3624             {
3625                 if (providerEnumKind != "Opcodes") goto Error;
3626                 int value = (int)staticField.GetRawConstantValue();
3627                 manifest.AddOpcode(staticField.Name, value);
3628             }
3629             else if (!reflectionOnly && (staticFieldType == typeof(EventTask)) || AttributeTypeNamesMatch(staticFieldType, typeof(EventTask)))
3630             {
3631                 if (providerEnumKind != "Tasks") goto Error;
3632                 int value = (int)staticField.GetRawConstantValue();
3633                 manifest.AddTask(staticField.Name, value);
3634             }
3635             else if (!reflectionOnly && (staticFieldType == typeof(EventKeywords)) || AttributeTypeNamesMatch(staticFieldType, typeof(EventKeywords)))
3636             {
3637                 if (providerEnumKind != "Keywords") goto Error;
3638                 ulong value = unchecked((ulong)(long)staticField.GetRawConstantValue());
3639                 manifest.AddKeyword(staticField.Name, value);
3640             }
3641 #if FEATURE_MANAGED_ETW_CHANNELS && FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
3642             else if (!reflectionOnly && (staticFieldType == typeof(EventChannel)) || AttributeTypeNamesMatch(staticFieldType, typeof(EventChannel)))
3643             {
3644                 if (providerEnumKind != "Channels") goto Error;
3645                 var channelAttribute = (EventChannelAttribute)GetCustomAttributeHelper(staticField, typeof(EventChannelAttribute));
3646                 manifest.AddChannel(staticField.Name, (byte)staticField.GetRawConstantValue(), channelAttribute);
3647             }
3648 #endif
3649             return;
3650             Error:
3651             manifest.ManifestError(Resources.GetResourceString("EventSource_EnumKindMismatch", staticField.Name, staticField.FieldType.Name, providerEnumKind));
3652         }
3653
3654         // Helper used by code:CreateManifestAndDescriptors to add a code:EventData descriptor for a method
3655         // with the code:EventAttribute 'eventAttribute'.  resourceManger may be null in which case we populate it
3656         // it is populated if we need to look up message resources
3657         private static void AddEventDescriptor(ref EventMetadata[] eventData, string eventName,
3658                                 EventAttribute eventAttribute, ParameterInfo[] eventParameters,
3659                                 bool hasRelatedActivityID)
3660         {
3661             if (eventData == null || eventData.Length <= eventAttribute.EventId)
3662             {
3663                 EventMetadata[] newValues = new EventMetadata[Math.Max(eventData.Length + 16, eventAttribute.EventId + 1)];
3664                 Array.Copy(eventData, 0, newValues, 0, eventData.Length);
3665                 eventData = newValues;
3666             }
3667
3668             eventData[eventAttribute.EventId].Descriptor = new EventDescriptor(
3669                     eventAttribute.EventId,
3670                     eventAttribute.Version,
3671 #if FEATURE_MANAGED_ETW_CHANNELS
3672                     (byte)eventAttribute.Channel,
3673 #else
3674                     (byte)0,
3675 #endif
3676                     (byte)eventAttribute.Level,
3677                     (byte)eventAttribute.Opcode,
3678                     (int)eventAttribute.Task,
3679                     unchecked((long)((ulong)eventAttribute.Keywords | SessionMask.All.ToEventKeywords())));
3680
3681             eventData[eventAttribute.EventId].Tags = eventAttribute.Tags;
3682             eventData[eventAttribute.EventId].Name = eventName;
3683             eventData[eventAttribute.EventId].Parameters = eventParameters;
3684             eventData[eventAttribute.EventId].Message = eventAttribute.Message;
3685             eventData[eventAttribute.EventId].ActivityOptions = eventAttribute.ActivityOptions;
3686             eventData[eventAttribute.EventId].HasRelatedActivityID = hasRelatedActivityID;
3687         }
3688
3689         // Helper used by code:CreateManifestAndDescriptors that trims the m_eventData array to the correct
3690         // size after all event descriptors have been added. 
3691         private static void TrimEventDescriptors(ref EventMetadata[] eventData)
3692         {
3693             int idx = eventData.Length;
3694             while (0 < idx)
3695             {
3696                 --idx;
3697                 if (eventData[idx].Descriptor.EventId != 0)
3698                     break;
3699             }
3700             if (eventData.Length - idx > 2)      // allow one wasted slot. 
3701             {
3702                 EventMetadata[] newValues = new EventMetadata[idx + 1];
3703                 Array.Copy(eventData, 0, newValues, 0, newValues.Length);
3704                 eventData = newValues;
3705             }
3706         }
3707
3708         // Helper used by code:EventListener.AddEventSource and code:EventListener.EventListener
3709         // when a listener gets attached to a eventSource
3710         internal void AddListener(EventListener listener)
3711         {
3712             lock (EventListener.EventListenersLock)
3713             {
3714                 bool[] enabledArray = null;
3715                 if (m_eventData != null)
3716                     enabledArray = new bool[m_eventData.Length];
3717                 m_Dispatchers = new EventDispatcher(m_Dispatchers, enabledArray, listener);
3718                 listener.OnEventSourceCreated(this);
3719             }
3720         }
3721
3722         // Helper used by code:CreateManifestAndDescriptors to find user mistakes like reusing an event
3723         // index for two distinct events etc.  Throws exceptions when it finds something wrong. 
3724         private static void DebugCheckEvent(ref Dictionary<string, string> eventsByName,
3725             EventMetadata[] eventData, MethodInfo method, EventAttribute eventAttribute,
3726             ManifestBuilder manifest, EventManifestOptions options)
3727         {
3728             int evtId = eventAttribute.EventId;
3729             string evtName = method.Name;
3730             int eventArg = GetHelperCallFirstArg(method);
3731             if (eventArg >= 0 && evtId != eventArg)
3732             {
3733                 manifest.ManifestError(Resources.GetResourceString("EventSource_MismatchIdToWriteEvent", evtName, evtId, eventArg), true);
3734             }
3735
3736             if (evtId < eventData.Length && eventData[evtId].Descriptor.EventId != 0)
3737             {
3738                 manifest.ManifestError(Resources.GetResourceString("EventSource_EventIdReused", evtName, evtId, eventData[evtId].Name), true);
3739             }
3740
3741             // We give a task to things if they don't have one.  
3742             // TODO this is moderately expensive (N*N).   We probably should not even bother....   
3743             Debug.Assert(eventAttribute.Task != EventTask.None || eventAttribute.Opcode != EventOpcode.Info);
3744             for (int idx = 0; idx < eventData.Length; ++idx)
3745             {
3746                 // skip unused Event IDs. 
3747                 if (eventData[idx].Name == null)
3748                     continue;
3749
3750                 if (eventData[idx].Descriptor.Task == (int)eventAttribute.Task && eventData[idx].Descriptor.Opcode == (int)eventAttribute.Opcode)
3751                 {
3752                     manifest.ManifestError(Resources.GetResourceString("EventSource_TaskOpcodePairReused",
3753                                             evtName, evtId, eventData[idx].Name, idx));
3754                     // If we are not strict stop on first error.   We have had problems with really large providers taking forever.  because of many errors.  
3755                     if ((options & EventManifestOptions.Strict) == 0)
3756                         break;
3757                 }
3758             }
3759
3760             // for non-default event opcodes the user must define a task!
3761             if (eventAttribute.Opcode != EventOpcode.Info)
3762             {
3763                 bool failure = false;
3764                 if (eventAttribute.Task == EventTask.None)
3765                     failure = true;
3766                 else
3767                 {
3768                     // If you have the auto-assigned Task, then you did not explicitly set one.  
3769                     // This is OK for Start events because we have special logic to assign the task to a prefix derived from the event name
3770                     // But all other cases we want to catch the omission.  
3771                     var autoAssignedTask = (EventTask)(0xFFFE - evtId);
3772                     if ((eventAttribute.Opcode != EventOpcode.Start && eventAttribute.Opcode != EventOpcode.Stop) && eventAttribute.Task == autoAssignedTask)
3773                         failure = true;
3774                 }
3775                 if (failure)
3776                 {
3777                     manifest.ManifestError(Resources.GetResourceString("EventSource_EventMustHaveTaskIfNonDefaultOpcode", evtName, evtId));
3778                 }
3779             }
3780
3781             // If we ever want to enforce the rule: MethodName = TaskName + OpcodeName here's how:
3782             //  (the reason we don't is backwards compat and the need for handling this as a non-fatal error
3783             //  by eventRegister.exe)
3784             // taskName & opcodeName could be passed in by the caller which has opTab & taskTab handy
3785             // if (!(((int)eventAttribute.Opcode == 0 && evtName == taskName) || (evtName == taskName+opcodeName)))
3786             // {
3787             //     throw new WarningException(Resources.GetResourceString("EventSource_EventNameDoesNotEqualTaskPlusOpcode"));
3788             // }
3789
3790             if (eventsByName == null)
3791                 eventsByName = new Dictionary<string, string>();
3792
3793             if (eventsByName.ContainsKey(evtName))
3794             {
3795                 manifest.ManifestError(Resources.GetResourceString("EventSource_EventNameReused", evtName), true);
3796             }
3797
3798             eventsByName[evtName] = evtName;
3799         }
3800
3801         /// <summary>
3802         /// This method looks at the IL and tries to pattern match against the standard
3803         /// 'boilerplate' event body 
3804         /// <code>
3805         ///     { if (Enabled()) WriteEvent(#, ...) } 
3806         /// </code>
3807         /// If the pattern matches, it returns the literal number passed as the first parameter to
3808         /// the WriteEvent.  This is used to find common user errors (mismatching this
3809         /// number with the EventAttribute ID).  It is only used for validation.   
3810         /// </summary>
3811         /// <param name="method">The method to probe.</param>
3812         /// <returns>The literal value or -1 if the value could not be determined. </returns>
3813         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Switch statement is clearer than alternatives")]
3814         static private int GetHelperCallFirstArg(MethodInfo method)
3815         {
3816 #if (!ES_BUILD_PCL && !ES_BUILD_PN)
3817             // Currently searches for the following pattern
3818             // 
3819             // ...     // CAN ONLY BE THE INSTRUCTIONS BELOW
3820             // LDARG0
3821             // LDC.I4 XXX
3822             // ...     // CAN ONLY BE THE INSTRUCTIONS BELOW CAN'T BE A BRANCH OR A CALL
3823             // CALL 
3824             // NOP     // 0 or more times
3825             // RET
3826             // 
3827             // If we find this pattern we return the XXX.  Otherwise we return -1.  
3828 #if !CORECLR
3829             (new ReflectionPermission(ReflectionPermissionFlag.MemberAccess)).Assert();
3830 #endif
3831             byte[] instrs = method.GetMethodBody().GetILAsByteArray();
3832             int retVal = -1;
3833             for (int idx = 0; idx < instrs.Length;)
3834             {
3835                 switch (instrs[idx])
3836                 {
3837                     case 0: // NOP
3838                     case 1: // BREAK
3839                     case 2: // LDARG_0
3840                     case 3: // LDARG_1
3841                     case 4: // LDARG_2
3842                     case 5: // LDARG_3
3843                     case 6: // LDLOC_0
3844                     case 7: // LDLOC_1
3845                     case 8: // LDLOC_2
3846                     case 9: // LDLOC_3
3847                     case 10: // STLOC_0
3848                     case 11: // STLOC_1
3849                     case 12: // STLOC_2
3850                     case 13: // STLOC_3
3851                         break;
3852                     case 14: // LDARG_S
3853                     case 16: // STARG_S
3854                         idx++;
3855                         break;
3856                     case 20: // LDNULL
3857                         break;
3858                     case 21: // LDC_I4_M1
3859                     case 22: // LDC_I4_0
3860                     case 23: // LDC_I4_1
3861                     case 24: // LDC_I4_2
3862                     case 25: // LDC_I4_3
3863                     case 26: // LDC_I4_4
3864                     case 27: // LDC_I4_5
3865                     case 28: // LDC_I4_6
3866                     case 29: // LDC_I4_7
3867                     case 30: // LDC_I4_8
3868                         if (idx > 0 && instrs[idx - 1] == 2)  // preceeded by LDARG0
3869                             retVal = instrs[idx] - 22;
3870                         break;
3871                     case 31: // LDC_I4_S
3872                         if (idx > 0 && instrs[idx - 1] == 2)  // preceeded by LDARG0
3873                             retVal = instrs[idx + 1];
3874                         idx++;
3875                         break;
3876                     case 32: // LDC_I4
3877                         idx += 4;
3878                         break;
3879                     case 37: // DUP
3880                         break;
3881                     case 40: // CALL
3882                         idx += 4;
3883
3884                         if (retVal >= 0)
3885                         {
3886                             // Is this call just before return?  
3887                             for (int search = idx + 1; search < instrs.Length; search++)
3888                             {
3889                                 if (instrs[search] == 42)  // RET
3890                                     return retVal;
3891                                 if (instrs[search] != 0)   // NOP
3892                                     break;
3893                             }
3894                         }
3895                         retVal = -1;
3896                         break;
3897                     case 44: // BRFALSE_S
3898                     case 45: // BRTRUE_S
3899                         retVal = -1;
3900                         idx++;
3901                         break;
3902                     case 57: // BRFALSE
3903                     case 58: // BRTRUE
3904                         retVal = -1;
3905                         idx += 4;
3906                         break;
3907                     case 103: // CONV_I1
3908                     case 104: // CONV_I2
3909                     case 105: // CONV_I4
3910                     case 106: // CONV_I8
3911                     case 109: // CONV_U4
3912                     case 110: // CONV_U8
3913                         break;
3914                     case 140: // BOX
3915                     case 141: // NEWARR
3916                         idx += 4;
3917                         break;
3918                     case 162: // STELEM_REF
3919                         break;
3920                     case 254: // PREFIX
3921                         idx++;
3922                         // Covers the CEQ instructions used in debug code for some reason.
3923                         if (idx >= instrs.Length || instrs[idx] >= 6)
3924                             goto default;
3925                         break;
3926                     default:
3927                         /* Debug.Assert(false, "Warning: User validation code sub-optimial: Unsuported opcode " + instrs[idx] +
3928                             " at " + idx + " in method " + method.Name); */
3929                         return -1;
3930                 }
3931                 idx++;
3932             }
3933 #endif
3934             return -1;
3935         }
3936
3937 #if false // This routine is not needed at all, it was used for unit test debugging. 
3938         [Conditional("DEBUG")]
3939         private static void OutputDebugString(string msg)
3940         {
3941 #if !ES_BUILD_PCL
3942             msg = msg.TrimEnd('\r', '\n') +
3943                     string.Format(CultureInfo.InvariantCulture, ", Thrd({0})" + Environment.NewLine, Thread.CurrentThread.ManagedThreadId);
3944             System.Diagnostics.Debugger.Log(0, null, msg);
3945 #endif
3946         }
3947 #endif
3948
3949         /// <summary>
3950         /// Sends an error message to the debugger (outputDebugString), as well as the EventListeners 
3951         /// It will do this even if the EventSource is not enabled.  
3952         /// TODO remove flush parameter it is not used.  
3953         /// </summary>
3954         [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")]
3955         internal void ReportOutOfBandMessage(string msg, bool flush)
3956         {
3957             try
3958             {
3959 #if (!ES_BUILD_PCL && !ES_BUILD_PN)
3960                 // send message to debugger without delay
3961                 System.Diagnostics.Debugger.Log(0, null, String.Format("EventSource Error: {0}{1}", msg, Environment.NewLine));
3962 #endif
3963
3964                 // Send it to all listeners.
3965                 if (m_outOfBandMessageCount < 16 - 1)     // Note this is only if size byte
3966                     m_outOfBandMessageCount++;
3967                 else
3968                 {
3969                     if (m_outOfBandMessageCount == 16)
3970                         return;
3971                     m_outOfBandMessageCount = 16;    // Mark that we hit the limit.  Notify them that this is the case. 
3972                     msg = "Reached message limit.   End of EventSource error messages.";
3973                 }
3974
3975                 WriteEventString(EventLevel.LogAlways, -1, msg);
3976                 WriteStringToAllListeners("EventSourceMessage", msg);
3977             }
3978             catch (Exception) { }      // If we fail during last chance logging, well, we have to give up....
3979         }
3980
3981         private EventSourceSettings ValidateSettings(EventSourceSettings settings)
3982         {
3983             var evtFormatMask = EventSourceSettings.EtwManifestEventFormat |
3984                                 EventSourceSettings.EtwSelfDescribingEventFormat;
3985             if ((settings & evtFormatMask) == evtFormatMask)
3986             {
3987                 throw new ArgumentException(Resources.GetResourceString("EventSource_InvalidEventFormat"), nameof(settings));
3988             }
3989
3990             // If you did not explicitly ask for manifest, you get self-describing.  
3991             if ((settings & evtFormatMask) == 0)
3992                 settings |= EventSourceSettings.EtwSelfDescribingEventFormat;
3993             return settings;
3994         }
3995
3996         private bool ThrowOnEventWriteErrors
3997         {
3998             get { return (m_config & EventSourceSettings.ThrowOnEventWriteErrors) != 0; }
3999             set
4000             {
4001                 if (value) m_config |= EventSourceSettings.ThrowOnEventWriteErrors;
4002                 else m_config &= ~EventSourceSettings.ThrowOnEventWriteErrors;
4003             }
4004         }
4005
4006         private bool SelfDescribingEvents
4007         {
4008             get
4009             {
4010                 Debug.Assert(((m_config & EventSourceSettings.EtwManifestEventFormat) != 0) !=
4011                                 ((m_config & EventSourceSettings.EtwSelfDescribingEventFormat) != 0));
4012                 return (m_config & EventSourceSettings.EtwSelfDescribingEventFormat) != 0;
4013             }
4014             set
4015             {
4016                 if (!value)
4017                 {
4018                     m_config |= EventSourceSettings.EtwManifestEventFormat;
4019                     m_config &= ~EventSourceSettings.EtwSelfDescribingEventFormat;
4020                 }
4021                 else
4022                 {
4023                     m_config |= EventSourceSettings.EtwSelfDescribingEventFormat;
4024                     m_config &= ~EventSourceSettings.EtwManifestEventFormat;
4025                 }
4026             }
4027         }
4028
4029 #if FEATURE_ACTIVITYSAMPLING
4030         private void ReportActivitySamplingInfo(EventListener listener, SessionMask sessions)
4031         {
4032             Debug.Assert(listener == null || (uint)sessions == (uint)SessionMask.FromId(0));
4033
4034             for (int perEventSourceSessionId = 0; perEventSourceSessionId < SessionMask.MAX; ++perEventSourceSessionId)
4035             {
4036                 if (!sessions[perEventSourceSessionId])
4037                     continue;
4038
4039                 ActivityFilter af;
4040                 if (listener == null)
4041                 {
4042                     EtwSession etwSession = m_etwSessionIdMap[perEventSourceSessionId];
4043                     Debug.Assert(etwSession != null);
4044                     af = etwSession.m_activityFilter;
4045                 }
4046                 else
4047                 {
4048                     af = listener.m_activityFilter;
4049                 }
4050
4051                 if (af == null)
4052                     continue;
4053
4054                 SessionMask m = new SessionMask();
4055                 m[perEventSourceSessionId] = true;
4056
4057                 foreach (var t in af.GetFilterAsTuple(m_guid))
4058                 {
4059                     WriteStringToListener(listener, string.Format(CultureInfo.InvariantCulture, "Session {0}: {1} = {2}", perEventSourceSessionId, t.Item1, t.Item2), m);
4060                 }
4061
4062                 bool participateInSampling = (listener == null) ?
4063                                                m_activityFilteringForETWEnabled[perEventSourceSessionId] :
4064                                                GetDispatcher(listener).m_activityFilteringEnabled;
4065                 WriteStringToListener(listener, string.Format(CultureInfo.InvariantCulture, "Session {0}: Activity Sampling support: {1}",
4066                                           perEventSourceSessionId, participateInSampling ? "enabled" : "disabled"), m);
4067             }
4068         }
4069 #endif // FEATURE_ACTIVITYSAMPLING
4070
4071         // private instance state 
4072         private string m_name;                          // My friendly name (privided in ctor)
4073         internal int m_id;                              // A small integer that is unique to this instance.  
4074         private Guid m_guid;                            // GUID representing the ETW eventSource to the OS.  
4075         internal volatile EventMetadata[] m_eventData;  // None per-event data
4076         private volatile byte[] m_rawManifest;          // Bytes to send out representing the event schema
4077
4078         private EventHandler<EventCommandEventArgs> m_eventCommandExecuted;
4079
4080         private EventSourceSettings m_config;      // configuration information
4081
4082         private bool m_eventSourceDisposed;              // has Dispose been called.
4083
4084         // Enabling bits
4085         private bool m_eventSourceEnabled;              // am I enabled (any of my events are enabled for any dispatcher)
4086         internal EventLevel m_level;                    // highest level enabled by any output dispatcher
4087         internal EventKeywords m_matchAnyKeyword;       // the logical OR of all levels enabled by any output dispatcher (zero is a special case) meaning 'all keywords'
4088
4089         // Dispatching state 
4090         internal volatile EventDispatcher m_Dispatchers;    // Linked list of code:EventDispatchers we write the data to (we also do ETW specially)
4091 #if FEATURE_MANAGED_ETW
4092         private volatile OverideEventProvider m_provider;   // This hooks up ETW commands to our 'OnEventCommand' callback
4093 #endif
4094         private bool m_completelyInited;                // The EventSource constructor has returned without exception.   
4095         private Exception m_constructionException;      // If there was an exception construction, this is it 
4096         private byte m_outOfBandMessageCount;           // The number of out of band messages sent (we throttle them
4097         private EventCommandEventArgs m_deferredCommands;// If we get commands before we are fully we store them here and run the when we are fully inited.  
4098
4099         private string[] m_traits;                      // Used to implement GetTraits
4100
4101         internal static uint s_currentPid;              // current process id, used in synthesizing quasi-GUIDs
4102         [ThreadStatic]
4103         private static byte m_EventSourceExceptionRecurenceCount = 0; // current recursion count inside ThrowEventSourceException
4104
4105         [ThreadStatic]
4106         private static bool m_EventSourceInDecodeObject = false;
4107
4108 #if FEATURE_MANAGED_ETW_CHANNELS
4109         internal volatile ulong[] m_channelData;
4110 #endif
4111
4112 #if FEATURE_ACTIVITYSAMPLING
4113         private SessionMask m_curLiveSessions;          // the activity-tracing aware sessions' bits
4114         private EtwSession[] m_etwSessionIdMap;         // the activity-tracing aware sessions
4115         private List<EtwSession> m_legacySessions;      // the legacy ETW sessions listening to this source
4116         internal long m_keywordTriggers;                // a bit is set if it corresponds to a keyword that's part of an enabled triggering event
4117         internal SessionMask m_activityFilteringForETWEnabled; // does THIS EventSource have activity filtering turned on for each ETW session
4118         static internal Action<Guid> s_activityDying;   // Fires when something calls SetCurrentThreadToActivity()
4119         // Also used to mark that activity tracing is on for some case
4120 #endif // FEATURE_ACTIVITYSAMPLING
4121
4122         // We use a single instance of ActivityTracker for all EventSources instances to allow correlation between multiple event providers.
4123         // We have m_activityTracker field simply because instance field is more efficient than static field fetch.
4124         ActivityTracker m_activityTracker;
4125         internal const string s_ActivityStartSuffix = "Start";
4126         internal const string s_ActivityStopSuffix = "Stop";
4127
4128         // used for generating GUID from eventsource name
4129         private static readonly byte[] namespaceBytes = new byte[] {
4130             0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8,
4131             0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB,
4132         };
4133
4134         #endregion
4135     }
4136
4137     /// <summary>
4138     /// Enables specifying event source configuration options to be used in the EventSource constructor.
4139     /// </summary>
4140     [Flags]
4141     public enum EventSourceSettings
4142     {
4143         /// <summary>
4144         /// This specifies none of the special configuration options should be enabled.
4145         /// </summary>
4146         Default = 0,
4147         /// <summary>
4148         /// Normally an EventSource NEVER throws; setting this option will tell it to throw when it encounters errors.  
4149         /// </summary>
4150         ThrowOnEventWriteErrors = 1,
4151         /// <summary>
4152         /// Setting this option is a directive to the ETW listener should use manifest-based format when
4153         /// firing events. This is the default option when defining a type derived from EventSource 
4154         /// (using the protected EventSource constructors).
4155         /// Only one of EtwManifestEventFormat or EtwSelfDescribingEventFormat should be specified
4156         /// </summary>
4157         EtwManifestEventFormat = 4,
4158         /// <summary>
4159         /// Setting this option is a directive to the ETW listener should use self-describing event format
4160         /// when firing events. This is the default option when creating a new instance of the EventSource
4161         /// type (using the public EventSource constructors).  
4162         /// Only one of EtwManifestEventFormat or EtwSelfDescribingEventFormat should be specified
4163         /// </summary>
4164         EtwSelfDescribingEventFormat = 8,
4165     }
4166
4167     /// <summary>
4168     /// An EventListener represents a target for the events generated by EventSources (that is subclasses
4169     /// of <see cref="EventSource"/>), in the current appdomain. When a new EventListener is created
4170     /// it is logically attached to all eventSources in that appdomain. When the EventListener is Disposed, then
4171     /// it is disconnected from the event eventSources. Note that there is a internal list of STRONG references
4172     /// to EventListeners, which means that relying on the lack of references to EventListeners to clean up
4173     /// EventListeners will NOT work. You must call EventListener.Dispose explicitly when a dispatcher is no
4174     /// longer needed.
4175     /// <para>
4176     /// Once created, EventListeners can enable or disable on a per-eventSource basis using verbosity levels
4177     /// (<see cref="EventLevel"/>) and bitfields (<see cref="EventKeywords"/>) to further restrict the set of 
4178     /// events to be sent to the dispatcher. The dispatcher can also send arbitrary commands to a particular 
4179     /// eventSource using the 'SendCommand' method. The meaning of the commands are eventSource specific.
4180     /// </para><para>
4181     /// The Null Guid (that is (new Guid()) has special meaning as a wildcard for 'all current eventSources in
4182     /// the appdomain'. Thus it is relatively easy to turn on all events in the appdomain if desired.
4183     /// </para><para>
4184     /// It is possible for there to be many EventListener's defined in a single appdomain. Each dispatcher is
4185     /// logically independent of the other listeners. Thus when one dispatcher enables or disables events, it
4186     /// affects only that dispatcher (other listeners get the events they asked for). It is possible that
4187     /// commands sent with 'SendCommand' would do a semantic operation that would affect the other listeners
4188     /// (like doing a GC, or flushing data ...), but this is the exception rather than the rule.
4189     /// </para><para>
4190     /// Thus the model is that each EventSource keeps a list of EventListeners that it is sending events
4191     /// to. Associated with each EventSource-dispatcher pair is a set of filtering criteria that determine for
4192     /// that eventSource what events that dispatcher will receive.
4193     /// </para><para>
4194     /// Listeners receive the events on their 'OnEventWritten' method. Thus subclasses of EventListener must
4195     /// override this method to do something useful with the data.
4196     /// </para><para>
4197     /// In addition, when new eventSources are created, the 'OnEventSourceCreate' method is called. The
4198     /// invariant associated with this callback is that every eventSource gets exactly one
4199     /// 'OnEventSourceCreate' call for ever eventSource that can potentially send it log messages. In
4200     /// particular when a EventListener is created, typically a series of OnEventSourceCreate' calls are
4201     /// made to notify the new dispatcher of all the eventSources that existed before the EventListener was
4202     /// created.
4203     /// </para>
4204     /// </summary>
4205     public class EventListener : IDisposable
4206     {
4207         private event EventHandler<EventSourceCreatedEventArgs> _EventSourceCreated;
4208
4209         /// <summary>
4210         /// This event is raised whenever a new eventSource is 'attached' to the dispatcher.
4211         /// This can happen for all existing EventSources when the EventListener is created
4212         /// as well as for any EventSources that come into existence after the EventListener
4213         /// has been created.
4214         /// 
4215         /// These 'catch up' events are called during the construction of the EventListener.
4216         /// Subclasses need to be prepared for that.
4217         /// 
4218         /// In a multi-threaded environment, it is possible that 'EventSourceEventWrittenCallback' 
4219         /// events for a particular eventSource to occur BEFORE the EventSourceCreatedCallback is issued.
4220         /// </summary>
4221         public event EventHandler<EventSourceCreatedEventArgs> EventSourceCreated
4222         {
4223             add
4224             {
4225                 CallBackForExistingEventSources(false, value);
4226
4227                 this._EventSourceCreated = (EventHandler<EventSourceCreatedEventArgs>)Delegate.Combine(_EventSourceCreated, value);
4228             }
4229             remove
4230             {
4231                 this._EventSourceCreated = (EventHandler<EventSourceCreatedEventArgs>)Delegate.Remove(_EventSourceCreated, value);
4232             }
4233         }
4234
4235         /// <summary>
4236         /// This event is raised whenever an event has been written by a EventSource for which 
4237         /// the EventListener has enabled events.  
4238         /// </summary>
4239         public event EventHandler<EventWrittenEventArgs> EventWritten;
4240
4241         /// <summary>
4242         /// Create a new EventListener in which all events start off turned off (use EnableEvents to turn
4243         /// them on).  
4244         /// </summary>
4245         public EventListener()
4246         {
4247             // This will cause the OnEventSourceCreated callback to fire. 
4248             CallBackForExistingEventSources(true, (obj, args) => args.EventSource.AddListener((EventListener)obj));
4249         }
4250
4251         /// <summary>
4252         /// Dispose should be called when the EventListener no longer desires 'OnEvent*' callbacks. Because
4253         /// there is an internal list of strong references to all EventListeners, calling 'Dispose' directly
4254         /// is the only way to actually make the listen die. Thus it is important that users of EventListener
4255         /// call Dispose when they are done with their logging.
4256         /// </summary>
4257 #if ES_BUILD_STANDALONE
4258         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")]
4259 #endif
4260         public virtual void Dispose()
4261         {
4262             lock (EventListenersLock)
4263             {
4264                 if (s_Listeners != null)
4265                 {
4266                     if (this == s_Listeners)
4267                     {
4268                         EventListener cur = s_Listeners;
4269                         s_Listeners = this.m_Next;
4270                         RemoveReferencesToListenerInEventSources(cur);
4271                     }
4272                     else
4273                     {
4274                         // Find 'this' from the s_Listeners linked list.  
4275                         EventListener prev = s_Listeners;
4276                         for (;;)
4277                         {
4278                             EventListener cur = prev.m_Next;
4279                             if (cur == null)
4280                                 break;
4281                             if (cur == this)
4282                             {
4283                                 // Found our Listener, remove references to to it in the eventSources
4284                                 prev.m_Next = cur.m_Next;       // Remove entry. 
4285                                 RemoveReferencesToListenerInEventSources(cur);
4286                                 break;
4287                             }
4288                             prev = cur;
4289                         }
4290                     }
4291                 }
4292                 Validate();
4293             }
4294         }
4295         // We don't expose a Dispose(bool), because the contract is that you don't have any non-syncronous
4296         // 'cleanup' associated with this object
4297
4298         /// <summary>
4299         /// Enable all events from the eventSource identified by 'eventSource' to the current 
4300         /// dispatcher that have a verbosity level of 'level' or lower.
4301         ///   
4302         /// This call can have the effect of REDUCING the number of events sent to the 
4303         /// dispatcher if 'level' indicates a less verbose level than was previously enabled.
4304         /// 
4305         /// This call never has an effect on other EventListeners.
4306         ///
4307         /// </summary>
4308         public void EnableEvents(EventSource eventSource, EventLevel level)
4309         {
4310             EnableEvents(eventSource, level, EventKeywords.None);
4311         }
4312         /// <summary>
4313         /// Enable all events from the eventSource identified by 'eventSource' to the current
4314         /// dispatcher that have a verbosity level of 'level' or lower and have a event keyword
4315         /// matching any of the bits in 'matchAnyKeyword'.
4316         /// 
4317         /// This call can have the effect of REDUCING the number of events sent to the 
4318         /// dispatcher if 'level' indicates a less verbose level than was previously enabled or
4319         /// if 'matchAnyKeyword' has fewer keywords set than where previously set.
4320         /// 
4321         /// This call never has an effect on other EventListeners.
4322         /// </summary>
4323         public void EnableEvents(EventSource eventSource, EventLevel level, EventKeywords matchAnyKeyword)
4324         {
4325             EnableEvents(eventSource, level, matchAnyKeyword, null);
4326         }
4327         /// <summary>
4328         /// Enable all events from the eventSource identified by 'eventSource' to the current
4329         /// dispatcher that have a verbosity level of 'level' or lower and have a event keyword
4330         /// matching any of the bits in 'matchAnyKeyword' as well as any (eventSource specific)
4331         /// effect passing additional 'key-value' arguments 'arguments' might have.  
4332         /// 
4333         /// This call can have the effect of REDUCING the number of events sent to the 
4334         /// dispatcher if 'level' indicates a less verbose level than was previously enabled or
4335         /// if 'matchAnyKeyword' has fewer keywords set than where previously set.
4336         /// 
4337         /// This call never has an effect on other EventListeners.
4338         /// </summary>       
4339         public void EnableEvents(EventSource eventSource, EventLevel level, EventKeywords matchAnyKeyword, IDictionary<string, string> arguments)
4340         {
4341             if (eventSource == null)
4342             {
4343                 throw new ArgumentNullException(nameof(eventSource));
4344             }
4345             Contract.EndContractBlock();
4346
4347             eventSource.SendCommand(this, 0, 0, EventCommand.Update, true, level, matchAnyKeyword, arguments);
4348         }
4349         /// <summary>
4350         /// Disables all events coming from eventSource identified by 'eventSource'.  
4351         /// 
4352         /// This call never has an effect on other EventListeners.      
4353         /// </summary>
4354         public void DisableEvents(EventSource eventSource)
4355         {
4356             if (eventSource == null)
4357             {
4358                 throw new ArgumentNullException(nameof(eventSource));
4359             }
4360             Contract.EndContractBlock();
4361
4362             eventSource.SendCommand(this, 0, 0, EventCommand.Update, false, EventLevel.LogAlways, EventKeywords.None, null);
4363         }
4364
4365         /// <summary>
4366         /// EventSourceIndex is small non-negative integer (suitable for indexing in an array)
4367         /// identifying EventSource. It is unique per-appdomain. Some EventListeners might find
4368         /// it useful to store additional information about each eventSource connected to it,
4369         /// and EventSourceIndex allows this extra information to be efficiently stored in a
4370         /// (growable) array (eg List(T)).
4371         /// </summary>
4372         public static int EventSourceIndex(EventSource eventSource) { return eventSource.m_id; }
4373
4374         /// <summary>
4375         /// This method is called whenever a new eventSource is 'attached' to the dispatcher.
4376         /// This can happen for all existing EventSources when the EventListener is created
4377         /// as well as for any EventSources that come into existence after the EventListener
4378         /// has been created.
4379         /// 
4380         /// These 'catch up' events are called during the construction of the EventListener.
4381         /// Subclasses need to be prepared for that.
4382         /// 
4383         /// In a multi-threaded environment, it is possible that 'OnEventWritten' callbacks
4384         /// for a particular eventSource to occur BEFORE the OnEventSourceCreated is issued.
4385         /// </summary>
4386         /// <param name="eventSource"></param>
4387         internal protected virtual void OnEventSourceCreated(EventSource eventSource)
4388         {
4389             EventHandler<EventSourceCreatedEventArgs> callBack = this._EventSourceCreated;
4390             if (callBack != null)
4391             {
4392                 EventSourceCreatedEventArgs args = new EventSourceCreatedEventArgs();
4393                 args.EventSource = eventSource;
4394                 callBack(this, args);
4395             }
4396         }
4397
4398         /// <summary>
4399         /// This method is called whenever an event has been written by a EventSource for which 
4400         /// the EventListener has enabled events.  
4401         /// </summary>
4402         /// <param name="eventData"></param>
4403         internal protected virtual void OnEventWritten(EventWrittenEventArgs eventData)
4404         {
4405             EventHandler<EventWrittenEventArgs> callBack = this.EventWritten;
4406             if (callBack != null)
4407             {
4408                 callBack(this, eventData);
4409             }
4410         }
4411
4412
4413         #region private
4414         /// <summary>
4415         /// This routine adds newEventSource to the global list of eventSources, it also assigns the
4416         /// ID to the eventSource (which is simply the ordinal in the global list).
4417         /// 
4418         /// EventSources currently do not pro-actively remove themselves from this list. Instead
4419         /// when eventSources's are GCed, the weak handle in this list naturally gets nulled, and
4420         /// we will reuse the slot. Today this list never shrinks (but we do reuse entries
4421         /// that are in the list). This seems OK since the expectation is that EventSources
4422         /// tend to live for the lifetime of the appdomain anyway (they tend to be used in
4423         /// global variables).
4424         /// </summary>
4425         /// <param name="newEventSource"></param>
4426         internal static void AddEventSource(EventSource newEventSource)
4427         {
4428             lock (EventListenersLock)
4429             {
4430                 if (s_EventSources == null)
4431                     s_EventSources = new List<WeakReference>(2);
4432
4433                 if (!s_EventSourceShutdownRegistered)
4434                 {
4435                     s_EventSourceShutdownRegistered = true;
4436                 }
4437
4438
4439                 // Periodically search the list for existing entries to reuse, this avoids
4440                 // unbounded memory use if we keep recycling eventSources (an unlikely thing). 
4441                 int newIndex = -1;
4442                 if (s_EventSources.Count % 64 == 63)   // on every block of 64, fill up the block before continuing
4443                 {
4444                     int i = s_EventSources.Count;      // Work from the top down. 
4445                     while (0 < i)
4446                     {
4447                         --i;
4448                         WeakReference weakRef = s_EventSources[i];
4449                         if (!weakRef.IsAlive)
4450                         {
4451                             newIndex = i;
4452                             weakRef.Target = newEventSource;
4453                             break;
4454                         }
4455                     }
4456                 }
4457                 if (newIndex < 0)
4458                 {
4459                     newIndex = s_EventSources.Count;
4460                     s_EventSources.Add(new WeakReference(newEventSource));
4461                 }
4462                 newEventSource.m_id = newIndex;
4463
4464                 // Add every existing dispatcher to the new EventSource
4465                 for (EventListener listener = s_Listeners; listener != null; listener = listener.m_Next)
4466                     newEventSource.AddListener(listener);
4467
4468                 Validate();
4469             }
4470         }
4471
4472         // Whenver we have async callbacks from native code, there is an ugly issue where
4473         // during .NET shutdown native code could be calling the callback, but the CLR
4474         // has already prohibited callbacks to managed code in the appdomain, causing the CLR 
4475         // to throw a COMPLUS_BOOT_EXCEPTION.   The guideline we give is that you must unregister
4476         // such callbacks on process shutdown or appdomain so that unmanaged code will never 
4477         // do this.  This is what this callback is for.  
4478         // See bug 724140 for more
4479         private static void DisposeOnShutdown(object sender, EventArgs e)
4480         {
4481             lock (EventListenersLock)
4482             {
4483                 foreach (var esRef in s_EventSources)
4484                 {
4485                     EventSource es = esRef.Target as EventSource;
4486                     if (es != null)
4487                         es.Dispose();
4488                 }
4489             }
4490         }
4491
4492         /// <summary>
4493         /// Helper used in code:Dispose that removes any references to 'listenerToRemove' in any of the
4494         /// eventSources in the appdomain.  
4495         /// 
4496         /// The EventListenersLock must be held before calling this routine. 
4497         /// </summary>
4498         private static void RemoveReferencesToListenerInEventSources(EventListener listenerToRemove)
4499         {
4500 #if !ES_BUILD_STANDALONE
4501             Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
4502 #endif
4503             // Foreach existing EventSource in the appdomain
4504             foreach (WeakReference eventSourceRef in s_EventSources)
4505             {
4506                 EventSource eventSource = eventSourceRef.Target as EventSource;
4507                 if (eventSource != null)
4508                 {
4509                     // Is the first output dispatcher the dispatcher we are removing?
4510                     if (eventSource.m_Dispatchers.m_Listener == listenerToRemove)
4511                         eventSource.m_Dispatchers = eventSource.m_Dispatchers.m_Next;
4512                     else
4513                     {
4514                         // Remove 'listenerToRemove' from the eventSource.m_Dispatchers linked list.  
4515                         EventDispatcher prev = eventSource.m_Dispatchers;
4516                         for (;;)
4517                         {
4518                             EventDispatcher cur = prev.m_Next;
4519                             if (cur == null)
4520                             {
4521                                 Debug.Assert(false, "EventSource did not have a registered EventListener!");
4522                                 break;
4523                             }
4524                             if (cur.m_Listener == listenerToRemove)
4525                             {
4526                                 prev.m_Next = cur.m_Next;       // Remove entry. 
4527                                 break;
4528                             }
4529                             prev = cur;
4530                         }
4531                     }
4532                 }
4533             }
4534         }
4535
4536         /// <summary>
4537         /// Checks internal consistency of EventSources/Listeners. 
4538         /// </summary>
4539         [Conditional("DEBUG")]
4540         internal static void Validate()
4541         {
4542             lock (EventListenersLock)
4543             {
4544                 // Get all listeners 
4545                 Dictionary<EventListener, bool> allListeners = new Dictionary<EventListener, bool>();
4546                 EventListener cur = s_Listeners;
4547                 while (cur != null)
4548                 {
4549                     allListeners.Add(cur, true);
4550                     cur = cur.m_Next;
4551                 }
4552
4553                 // For all eventSources 
4554                 int id = -1;
4555                 foreach (WeakReference eventSourceRef in s_EventSources)
4556                 {
4557                     id++;
4558                     EventSource eventSource = eventSourceRef.Target as EventSource;
4559                     if (eventSource == null)
4560                         continue;
4561                     Debug.Assert(eventSource.m_id == id, "Unexpected event source ID.");
4562
4563                     // None listeners on eventSources exist in the dispatcher list.   
4564                     EventDispatcher dispatcher = eventSource.m_Dispatchers;
4565                     while (dispatcher != null)
4566                     {
4567                         Debug.Assert(allListeners.ContainsKey(dispatcher.m_Listener), "EventSource has a listener not on the global list.");
4568                         dispatcher = dispatcher.m_Next;
4569                     }
4570
4571                     // Every dispatcher is on Dispatcher List of every eventSource. 
4572                     foreach (EventListener listener in allListeners.Keys)
4573                     {
4574                         dispatcher = eventSource.m_Dispatchers;
4575                         for (;;)
4576                         {
4577                             Debug.Assert(dispatcher != null, "Listener is not on all eventSources.");
4578                             if (dispatcher.m_Listener == listener)
4579                                 break;
4580                             dispatcher = dispatcher.m_Next;
4581                         }
4582                     }
4583                 }
4584             }
4585         }
4586
4587         /// <summary>
4588         /// Gets a global lock that is intended to protect the code:s_Listeners linked list and the
4589         /// code:s_EventSources WeakReference list.  (We happen to use the s_EventSources list as
4590         /// the lock object)
4591         /// </summary>
4592         internal static object EventListenersLock
4593         {
4594             get
4595             {
4596                 if (s_EventSources == null)
4597                     Interlocked.CompareExchange(ref s_EventSources, new List<WeakReference>(2), null);
4598                 return s_EventSources;
4599             }
4600         }
4601
4602         private void CallBackForExistingEventSources(bool addToListenersList, EventHandler<EventSourceCreatedEventArgs> callback)
4603         {
4604             lock (EventListenersLock)
4605             {
4606                 // Disallow creating EventListener reentrancy. 
4607                 if (s_CreatingListener)
4608                 {
4609                     throw new InvalidOperationException(Resources.GetResourceString("EventSource_ListenerCreatedInsideCallback"));
4610                 }
4611
4612                 try
4613                 {
4614                     s_CreatingListener = true;
4615
4616                     if (addToListenersList)
4617                     {
4618                         // Add to list of listeners in the system, do this BEFORE firing the 'OnEventSourceCreated' so that 
4619                         // Those added sources see this listener.
4620                         this.m_Next = s_Listeners;
4621                         s_Listeners = this;
4622                     }
4623
4624                     // Find all existing eventSources call OnEventSourceCreated to 'catchup'
4625                     // Note that we DO have reentrancy here because 'AddListener' calls out to user code (via OnEventSourceCreated callback) 
4626                     // We tolerate this by iterating over a copy of the list here. New event sources will take care of adding listeners themselves
4627                     // EventSources are not guaranteed to be added at the end of the s_EventSource list -- We re-use slots when a new source
4628                     // is created.
4629                     WeakReference[] eventSourcesSnapshot = s_EventSources.ToArray();
4630
4631                     for (int i = 0; i < eventSourcesSnapshot.Length; i++)
4632                     {
4633                         WeakReference eventSourceRef = eventSourcesSnapshot[i];
4634                         EventSource eventSource = eventSourceRef.Target as EventSource;
4635                         if (eventSource != null)
4636                         {
4637                             EventSourceCreatedEventArgs args = new EventSourceCreatedEventArgs();
4638                             args.EventSource = eventSource;
4639                             callback(this, args);
4640                         }
4641                     }
4642
4643                     Validate();
4644                 }
4645                 finally
4646                 {
4647                     s_CreatingListener = false;
4648                 }
4649             }
4650
4651         }
4652
4653         // Instance fields
4654         internal volatile EventListener m_Next;                         // These form a linked list in s_Listeners
4655 #if FEATURE_ACTIVITYSAMPLING
4656         internal ActivityFilter m_activityFilter;                       // If we are filtering by activity on this Listener, this keeps track of it. 
4657 #endif // FEATURE_ACTIVITYSAMPLING
4658
4659         // static fields
4660
4661         /// <summary>
4662         /// The list of all listeners in the appdomain.  Listeners must be explicitly disposed to remove themselves 
4663         /// from this list.   Note that EventSources point to their listener but NOT the reverse.  
4664         /// </summary>
4665         internal static EventListener s_Listeners;
4666         /// <summary>
4667         /// The list of all active eventSources in the appdomain.  Note that eventSources do NOT 
4668         /// remove themselves from this list this is a weak list and the GC that removes them may
4669         /// not have happened yet.  Thus it can contain event sources that are dead (thus you have 
4670         /// to filter those out.  
4671         /// </summary>
4672         internal static List<WeakReference> s_EventSources;
4673
4674         /// <summary>
4675         /// Used to disallow reentrancy.  
4676         /// </summary>
4677         private static bool s_CreatingListener = false;
4678
4679         /// <summary>
4680         /// Used to register AD/Process shutdown callbacks.
4681         /// </summary>
4682         private static bool s_EventSourceShutdownRegistered = false;
4683         #endregion
4684     }
4685
4686     /// <summary>
4687     /// Passed to the code:EventSource.OnEventCommand callback
4688     /// </summary>
4689     public class EventCommandEventArgs : EventArgs
4690     {
4691         /// <summary>
4692         /// Gets the command for the callback.
4693         /// </summary>
4694         public EventCommand Command { get; internal set; }
4695
4696         /// <summary>
4697         /// Gets the arguments for the callback.
4698         /// </summary>
4699         public IDictionary<String, String> Arguments { get; internal set; }
4700
4701         /// <summary>
4702         /// Enables the event that has the specified identifier.
4703         /// </summary>
4704         /// <param name="eventId">Event ID of event to be enabled</param>
4705         /// <returns>true if eventId is in range</returns>
4706         public bool EnableEvent(int eventId)
4707         {
4708             if (Command != EventCommand.Enable && Command != EventCommand.Disable)
4709                 throw new InvalidOperationException();
4710             return eventSource.EnableEventForDispatcher(dispatcher, eventId, true);
4711         }
4712
4713         /// <summary>
4714         /// Disables the event that have the specified identifier.
4715         /// </summary>
4716         /// <param name="eventId">Event ID of event to be disabled</param>
4717         /// <returns>true if eventId is in range</returns>
4718         public bool DisableEvent(int eventId)
4719         {
4720             if (Command != EventCommand.Enable && Command != EventCommand.Disable)
4721                 throw new InvalidOperationException();
4722             return eventSource.EnableEventForDispatcher(dispatcher, eventId, false);
4723         }
4724
4725         #region private
4726
4727         internal EventCommandEventArgs(EventCommand command, IDictionary<string, string> arguments, EventSource eventSource,
4728             EventListener listener, int perEventSourceSessionId, int etwSessionId, bool enable, EventLevel level, EventKeywords matchAnyKeyword)
4729         {
4730             this.Command = command;
4731             this.Arguments = arguments;
4732             this.eventSource = eventSource;
4733             this.listener = listener;
4734             this.perEventSourceSessionId = perEventSourceSessionId;
4735             this.etwSessionId = etwSessionId;
4736             this.enable = enable;
4737             this.level = level;
4738             this.matchAnyKeyword = matchAnyKeyword;
4739         }
4740
4741         internal EventSource eventSource;
4742         internal EventDispatcher dispatcher;
4743
4744         // These are the arguments of sendCommand and are only used for deferring commands until after we are fully initialized. 
4745         internal EventListener listener;
4746         internal int perEventSourceSessionId;
4747         internal int etwSessionId;
4748         internal bool enable;
4749         internal EventLevel level;
4750         internal EventKeywords matchAnyKeyword;
4751         internal EventCommandEventArgs nextCommand;     // We form a linked list of these deferred commands.      
4752
4753         #endregion
4754     }
4755
4756     /// <summary>
4757     /// EventSourceCreatedEventArgs is passed to <see cref="EventListener.EventSourceCreated"/>
4758     /// </summary>
4759     public class EventSourceCreatedEventArgs : EventArgs
4760     {
4761         /// <summary>
4762         /// The EventSource that is attaching to the listener.
4763         /// </summary>
4764         public EventSource EventSource
4765         {
4766             get;
4767             internal set;
4768         }
4769     }
4770
4771     /// <summary>
4772     /// EventWrittenEventArgs is passed to the user-provided override for
4773     /// <see cref="EventListener.OnEventWritten"/> when an event is fired.
4774     /// </summary>
4775     public class EventWrittenEventArgs : EventArgs
4776     {
4777         /// <summary>
4778         /// The name of the event.   
4779         /// </summary>
4780         public string EventName
4781         {
4782             get
4783             {
4784                 if (m_eventName != null || EventId < 0)      // TraceLogging convention EventID == -1
4785                 {
4786                     return m_eventName;
4787                 }
4788                 else
4789                     return m_eventSource.m_eventData[EventId].Name;
4790             }
4791             internal set
4792             {
4793                 m_eventName = value;
4794             }
4795         }
4796
4797         /// <summary>
4798         /// Gets the event ID for the event that was written.
4799         /// </summary>
4800         public int EventId { get; internal set; }
4801
4802         /// <summary>
4803         /// Gets the activity ID for the thread on which the event was written.
4804         /// </summary>
4805         public Guid ActivityId
4806         {
4807             get { return EventSource.CurrentThreadActivityId; }
4808         }
4809
4810         /// <summary>
4811         /// Gets the related activity ID if one was specified when the event was written.
4812         /// </summary>
4813         public Guid RelatedActivityId
4814         {
4815             get;
4816             internal set;
4817         }
4818
4819         /// <summary>
4820         /// Gets the payload for the event.
4821         /// </summary>
4822         public ReadOnlyCollection<Object> Payload { get; internal set; }
4823
4824         /// <summary>
4825         /// Gets the payload argument names.
4826         /// </summary>
4827         public ReadOnlyCollection<string> PayloadNames
4828         {
4829             get
4830             {
4831                 // For contract based events we create the list lazily.
4832                 if (m_payloadNames == null)
4833                 {
4834                     // Self described events are identified by id -1.
4835                     Debug.Assert(EventId != -1);
4836
4837                     var names = new List<string>();
4838                     foreach (var parameter in m_eventSource.m_eventData[EventId].Parameters)
4839                     {
4840                         names.Add(parameter.Name);
4841                     }
4842                     m_payloadNames = new ReadOnlyCollection<string>(names);
4843                 }
4844
4845                 return m_payloadNames;
4846             }
4847
4848             internal set
4849             {
4850                 m_payloadNames = value;
4851             }
4852         }
4853
4854         /// <summary>
4855         /// Gets the event source object.
4856         /// </summary>
4857         public EventSource EventSource { get { return m_eventSource; } }
4858
4859         /// <summary>
4860         /// Gets the keywords for the event.
4861         /// </summary>
4862         public EventKeywords Keywords
4863         {
4864             get
4865             {
4866                 if (EventId < 0)      // TraceLogging convention EventID == -1
4867                     return m_keywords;
4868
4869                 return (EventKeywords)m_eventSource.m_eventData[EventId].Descriptor.Keywords;
4870             }
4871         }
4872
4873         /// <summary>
4874         /// Gets the operation code for the event.
4875         /// </summary>
4876         public EventOpcode Opcode
4877         {
4878             get
4879             {
4880                 if (EventId <= 0)      // TraceLogging convention EventID == -1
4881                     return m_opcode;
4882                 return (EventOpcode)m_eventSource.m_eventData[EventId].Descriptor.Opcode;
4883             }
4884         }
4885
4886         /// <summary>
4887         /// Gets the task for the event.
4888         /// </summary>
4889         public EventTask Task
4890         {
4891             get
4892             {
4893                 if (EventId <= 0)      // TraceLogging convention EventID == -1
4894                     return EventTask.None;
4895
4896                 return (EventTask)m_eventSource.m_eventData[EventId].Descriptor.Task;
4897             }
4898         }
4899
4900         /// <summary>
4901         /// Any provider/user defined options associated with the event.  
4902         /// </summary>
4903         public EventTags Tags
4904         {
4905             get
4906             {
4907                 if (EventId <= 0)      // TraceLogging convention EventID == -1
4908                     return m_tags;
4909                 return m_eventSource.m_eventData[EventId].Tags;
4910             }
4911         }
4912
4913         /// <summary>
4914         /// Gets the message for the event.  If the message has {N} parameters they are NOT substituted.  
4915         /// </summary>
4916         public string Message
4917         {
4918             get
4919             {
4920                 if (EventId <= 0)      // TraceLogging convention EventID == -1
4921                     return m_message;
4922                 else
4923                     return m_eventSource.m_eventData[EventId].Message;
4924             }
4925             internal set
4926             {
4927                 m_message = value;
4928             }
4929         }
4930
4931
4932 #if FEATURE_MANAGED_ETW_CHANNELS
4933         /// <summary>
4934         /// Gets the channel for the event.
4935         /// </summary>
4936         public EventChannel Channel
4937         {
4938             get
4939             {
4940                 if (EventId <= 0)      // TraceLogging convention EventID == -1
4941                     return EventChannel.None;
4942                 return (EventChannel)m_eventSource.m_eventData[EventId].Descriptor.Channel;
4943             }
4944         }
4945 #endif
4946
4947         /// <summary>
4948         /// Gets the version of the event.
4949         /// </summary>
4950         public byte Version
4951         {
4952             get
4953             {
4954                 if (EventId <= 0)      // TraceLogging convention EventID == -1
4955                     return 0;
4956                 return m_eventSource.m_eventData[EventId].Descriptor.Version;
4957             }
4958         }
4959
4960         /// <summary>
4961         /// Gets the level for the event.
4962         /// </summary>
4963         public EventLevel Level
4964         {
4965             get
4966             {
4967                 if (EventId <= 0)      // TraceLogging convention EventID == -1
4968                     return m_level;
4969                 return (EventLevel)m_eventSource.m_eventData[EventId].Descriptor.Level;
4970             }
4971         }
4972
4973         #region private
4974         internal EventWrittenEventArgs(EventSource eventSource)
4975         {
4976             m_eventSource = eventSource;
4977         }
4978         private string m_message;
4979         private string m_eventName;
4980         private EventSource m_eventSource;
4981         private ReadOnlyCollection<string> m_payloadNames;
4982         internal EventTags m_tags;
4983         internal EventOpcode m_opcode;
4984         internal EventLevel m_level;
4985         internal EventKeywords m_keywords;
4986         #endregion
4987     }
4988
4989     /// <summary>
4990     /// Allows customizing defaults and specifying localization support for the event source class to which it is applied. 
4991     /// </summary>
4992     [AttributeUsage(AttributeTargets.Class)]
4993     public sealed class EventSourceAttribute : Attribute
4994     {
4995         /// <summary>
4996         /// Overrides the ETW name of the event source (which defaults to the class name)
4997         /// </summary>
4998         public string Name { get; set; }
4999
5000         /// <summary>
5001         /// Overrides the default (calculated) Guid of an EventSource type. Explicitly defining a GUID is discouraged, 
5002         /// except when upgrading existing ETW providers to using event sources.
5003         /// </summary>
5004         public string Guid { get; set; }
5005
5006         /// <summary>
5007         /// <para>
5008         /// EventSources support localization of events. The names used for events, opcodes, tasks, keywords and maps 
5009         /// can be localized to several languages if desired. This works by creating a ResX style string table 
5010         /// (by simply adding a 'Resource File' to your project). This resource file is given a name e.g. 
5011         /// 'DefaultNameSpace.ResourceFileName' which can be passed to the ResourceManager constructor to read the 
5012         /// resources. This name is the value of the LocalizationResources property. 
5013         /// </para><para>
5014         /// If LocalizationResources property is non-null, then EventSource will look up the localized strings for events by 
5015         /// using the following resource naming scheme
5016         /// </para>
5017         ///     <para>* event_EVENTNAME</para>
5018         ///     <para>* task_TASKNAME</para>
5019         ///     <para>* keyword_KEYWORDNAME</para>
5020         ///     <para>* map_MAPNAME</para>
5021         /// <para>
5022         /// where the capitalized name is the name of the event, task, keyword, or map value that should be localized.   
5023         /// Note that the localized string for an event corresponds to the Message string, and can have {0} values 
5024         /// which represent the payload values.  
5025         /// </para>
5026         /// </summary>
5027         public string LocalizationResources { get; set; }
5028     }
5029
5030     /// <summary>
5031     /// Any instance methods in a class that subclasses <see cref="EventSource"/> and that return void are
5032     /// assumed by default to be methods that generate an ETW event. Enough information can be deduced from the
5033     /// name of the method and its signature to generate basic schema information for the event. The
5034     /// <see cref="EventAttribute"/> class allows you to specify additional event schema information for an event if
5035     /// desired.
5036     /// </summary>
5037     [AttributeUsage(AttributeTargets.Method)]
5038     public sealed class EventAttribute : Attribute
5039     {
5040         /// <summary>Construct an EventAttribute with specified eventId</summary>
5041         /// <param name="eventId">ID of the ETW event (an integer between 1 and 65535)</param>
5042         public EventAttribute(int eventId) { this.EventId = eventId; Level = EventLevel.Informational; this.m_opcodeSet = false; }
5043         /// <summary>Event's ID</summary>
5044         public int EventId { get; private set; }
5045         /// <summary>Event's severity level: indicates the severity or verbosity of the event</summary>
5046         public EventLevel Level { get; set; }
5047         /// <summary>Event's keywords: allows classification of events by "categories"</summary>
5048         public EventKeywords Keywords { get; set; }
5049         /// <summary>Event's operation code: allows defining operations, generally used with Tasks</summary>
5050         public EventOpcode Opcode
5051         {
5052             get
5053             {
5054                 return m_opcode;
5055             }
5056             set
5057             {
5058                 this.m_opcode = value;
5059                 this.m_opcodeSet = true;
5060             }
5061         }
5062
5063         internal bool IsOpcodeSet
5064         {
5065             get
5066             {
5067                 return m_opcodeSet;
5068             }
5069         }
5070
5071         /// <summary>Event's task: allows logical grouping of events</summary>
5072         public EventTask Task { get; set; }
5073 #if FEATURE_MANAGED_ETW_CHANNELS
5074         /// <summary>Event's channel: defines an event log as an additional destination for the event</summary>
5075         public EventChannel Channel { get; set; }
5076 #endif
5077         /// <summary>Event's version</summary>
5078         public byte Version { get; set; }
5079
5080         /// <summary>
5081         /// This can be specified to enable formatting and localization of the event's payload. You can 
5082         /// use standard .NET substitution operators (eg {1}) in the string and they will be replaced 
5083         /// with the 'ToString()' of the corresponding part of the  event payload.   
5084         /// </summary>
5085         public string Message { get; set; }
5086
5087         /// <summary>
5088         /// User defined options associated with the event.  These do not have meaning to the EventSource but
5089         /// are passed through to listeners which given them semantics.  
5090         /// </summary>
5091         public EventTags Tags { get; set; }
5092
5093         /// <summary>
5094         /// Allows fine control over the Activity IDs generated by start and stop events
5095         /// </summary>
5096         public EventActivityOptions ActivityOptions { get; set; }
5097
5098         #region private
5099         EventOpcode m_opcode;
5100         private bool m_opcodeSet;
5101         #endregion
5102     }
5103
5104     /// <summary>
5105     /// By default all instance methods in a class that subclasses code:EventSource that and return
5106     /// void are assumed to be methods that generate an event. This default can be overridden by specifying
5107     /// the code:NonEventAttribute
5108     /// </summary>
5109     [AttributeUsage(AttributeTargets.Method)]
5110     public sealed class NonEventAttribute : Attribute
5111     {
5112         /// <summary>
5113         /// Constructs a default NonEventAttribute
5114         /// </summary>
5115         public NonEventAttribute() { }
5116     }
5117
5118     // FUTURE we may want to expose this at some point once we have a partner that can help us validate the design.
5119 #if FEATURE_MANAGED_ETW_CHANNELS
5120     /// <summary>
5121     /// EventChannelAttribute allows customizing channels supported by an EventSource. This attribute must be
5122     /// applied to an member of type EventChannel defined in a Channels class nested in the EventSource class:
5123     /// <code>
5124     ///     public static class Channels
5125     ///     {
5126     ///         [Channel(Enabled = true, EventChannelType = EventChannelType.Admin)]
5127     ///         public const EventChannel Admin = (EventChannel)16;
5128     ///     
5129     ///         [Channel(Enabled = false, EventChannelType = EventChannelType.Operational)]
5130     ///         public const EventChannel Operational = (EventChannel)17;
5131     ///     }
5132     /// </code>
5133     /// </summary>
5134     [AttributeUsage(AttributeTargets.Field)]
5135 #if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
5136     public 
5137 #endif
5138     class EventChannelAttribute : Attribute
5139     {
5140         /// <summary>
5141         /// Specified whether the channel is enabled by default
5142         /// </summary>
5143         public bool Enabled { get; set; }
5144
5145         /// <summary>
5146         /// Legal values are in EventChannelType
5147         /// </summary>
5148         public EventChannelType EventChannelType { get; set; }
5149
5150 #if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
5151         /// <summary>
5152         /// Specifies the isolation for the channel
5153         /// </summary>
5154         public EventChannelIsolation Isolation { get; set; }
5155
5156         /// <summary>
5157         /// Specifies an SDDL access descriptor that controls access to the log file that backs the channel.
5158         /// See MSDN ((http://msdn.microsoft.com/en-us/library/windows/desktop/aa382741.aspx) for details.
5159         /// </summary>
5160         public string Access { get; set; } 
5161
5162         /// <summary>
5163         /// Allows importing channels defined in external manifests
5164         /// </summary>
5165         public string ImportChannel { get; set; }
5166 #endif
5167
5168         // TODO: there is a convention that the name is the Provider/Type   Should we provide an override?
5169         // public string Name { get; set; }
5170     }
5171
5172     /// <summary>
5173     /// Allowed channel types
5174     /// </summary>
5175 #if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
5176     public 
5177 #endif
5178     enum EventChannelType
5179     {
5180         /// <summary>The admin channel</summary>
5181         Admin = 1,
5182         /// <summary>The operational channel</summary>
5183         Operational,
5184         /// <summary>The Analytic channel</summary>
5185         Analytic,
5186         /// <summary>The debug channel</summary>
5187         Debug,
5188     }
5189
5190 #if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
5191     /// <summary>
5192     /// Allowed isolation levels. See MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/aa382741.aspx) 
5193     /// for the default permissions associated with each level. EventChannelIsolation and Access allows control over the 
5194     /// access permissions for the channel and backing file.
5195     /// </summary>
5196     public 
5197     enum EventChannelIsolation
5198     {
5199         /// <summary>
5200         /// This is the default isolation level. All channels that specify Application isolation use the same ETW session
5201         /// </summary>
5202         Application = 1,
5203         /// <summary>
5204         /// All channels that specify System isolation use the same ETW session
5205         /// </summary>
5206         System,
5207         /// <summary>
5208         /// Use sparingly! When specifying Custom isolation, a separate ETW session is created for the channel.
5209         /// Using Custom isolation lets you control the access permissions for the channel and backing file.
5210         /// Because there are only 64 ETW sessions available, you should limit your use of Custom isolation.
5211         /// </summary>
5212         Custom,
5213     }
5214 #endif
5215 #endif
5216
5217     /// <summary>
5218     /// Describes the pre-defined command (EventCommandEventArgs.Command property) that is passed to the OnEventCommand callback.
5219     /// </summary>
5220     public enum EventCommand
5221     {
5222         /// <summary>
5223         /// Update EventSource state
5224         /// </summary>
5225         Update = 0,
5226         /// <summary>
5227         /// Request EventSource to generate and send its manifest
5228         /// </summary>
5229         SendManifest = -1,
5230         /// <summary>
5231         /// Enable event
5232         /// </summary>
5233         Enable = -2,
5234         /// <summary>
5235         /// Disable event
5236         /// </summary>
5237         Disable = -3
5238     };
5239
5240
5241     #region private classes
5242
5243 #if FEATURE_ACTIVITYSAMPLING
5244
5245     /// <summary>
5246     /// ActivityFilter is a helper structure that is used to keep track of run-time state
5247     /// associated with activity filtering. It is 1-1 with EventListeners (logically
5248     /// every listener has one of these, however we actually allocate them lazily), as well
5249     /// as 1-to-1 with tracing-aware EtwSessions.
5250     /// 
5251     /// This structure also keeps track of the sampling counts associated with 'trigger'
5252     /// events.  Because these trigger events are rare, and you typically only have one of
5253     /// them, we store them here as a linked list.
5254     /// </summary>
5255     internal sealed class ActivityFilter : IDisposable
5256     {
5257         /// <summary>
5258         /// Disable all activity filtering for the listener associated with 'filterList', 
5259         /// (in the session associated with it) that is triggered by any event in 'source'.
5260         /// </summary>
5261         public static void DisableFilter(ref ActivityFilter filterList, EventSource source)
5262         {
5263 #if !ES_BUILD_STANDALONE
5264             Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
5265 #endif
5266
5267             if (filterList == null)
5268                 return;
5269
5270             ActivityFilter cur;
5271             // Remove it from anywhere in the list (except the first element, which has to 
5272             // be treated specially)
5273             ActivityFilter prev = filterList;
5274             cur = prev.m_next;
5275             while (cur != null)
5276             {
5277                 if (cur.m_providerGuid == source.Guid)
5278                 {
5279                     // update TriggersActivityTracking bit
5280                     if (cur.m_eventId >= 0 && cur.m_eventId < source.m_eventData.Length)
5281                         --source.m_eventData[cur.m_eventId].TriggersActivityTracking;
5282
5283                     // Remove it from the linked list.
5284                     prev.m_next = cur.m_next;
5285                     // dispose of the removed node
5286                     cur.Dispose();
5287                     // update cursor
5288                     cur = prev.m_next;
5289                 }
5290                 else
5291                 {
5292                     // update cursors
5293                     prev = cur;
5294                     cur = prev.m_next;
5295                 }
5296             }
5297
5298             // Sadly we have to treat the first element specially in linked list removal in C#
5299             if (filterList.m_providerGuid == source.Guid)
5300             {
5301                 // update TriggersActivityTracking bit
5302                 if (filterList.m_eventId >= 0 && filterList.m_eventId < source.m_eventData.Length)
5303                     --source.m_eventData[filterList.m_eventId].TriggersActivityTracking;
5304
5305                 // We are the first element in the list.   
5306                 var first = filterList;
5307                 filterList = first.m_next;
5308                 // dispose of the removed node
5309                 first.Dispose();
5310             }
5311             // the above might have removed the one ActivityFilter in the session that contains the 
5312             // cleanup delegate; re-create the delegate if needed
5313             if (filterList != null)
5314             {
5315                 EnsureActivityCleanupDelegate(filterList);
5316             }
5317         }
5318
5319         /// <summary>
5320         /// Currently this has "override" semantics. We first disable all filters
5321         /// associated with 'source', and next we add new filters for each entry in the 
5322         /// string 'startEvents'. participateInSampling specifies whether non-startEvents 
5323         /// always trigger or only trigger when current activity is 'active'.
5324         /// </summary>
5325         public static void UpdateFilter(
5326                                     ref ActivityFilter filterList,
5327                                     EventSource source,
5328                                     int perEventSourceSessionId,
5329                                     string startEvents)
5330         {
5331 #if !ES_BUILD_STANDALONE
5332             Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
5333 #endif
5334
5335             // first remove all filters associated with 'source'
5336             DisableFilter(ref filterList, source);
5337
5338             if (!string.IsNullOrEmpty(startEvents))
5339             {
5340                 // ActivitySamplingStartEvents is a space-separated list of Event:Frequency pairs.
5341                 // The Event may be specified by name or by ID. Errors in parsing such a pair 
5342                 // result in the error being reported to the listeners, and the pair being ignored.
5343                 // E.g. "CustomActivityStart:1000 12:10" specifies that for event CustomActivityStart
5344                 // we should initiate activity tracing once every 1000 events, *and* for event ID 12
5345                 // we should initiate activity tracing once every 10 events.
5346                 string[] activityFilterStrings = startEvents.Split(' ');
5347
5348                 for (int i = 0; i < activityFilterStrings.Length; ++i)
5349                 {
5350                     string activityFilterString = activityFilterStrings[i];
5351                     int sampleFreq = 1;
5352                     int eventId = -1;
5353                     int colonIdx = activityFilterString.IndexOf(':');
5354                     if (colonIdx < 0)
5355                     {
5356                         source.ReportOutOfBandMessage("ERROR: Invalid ActivitySamplingStartEvent specification: " +
5357                             activityFilterString, false);
5358                         // ignore failure...
5359                         continue;
5360                     }
5361                     string sFreq = activityFilterString.Substring(colonIdx + 1);
5362                     if (!int.TryParse(sFreq, out sampleFreq))
5363                     {
5364                         source.ReportOutOfBandMessage("ERROR: Invalid sampling frequency specification: " + sFreq, false);
5365                         continue;
5366                     }
5367                     activityFilterString = activityFilterString.Substring(0, colonIdx);
5368                     if (!int.TryParse(activityFilterString, out eventId))
5369                     {
5370                         // reset eventId
5371                         eventId = -1;
5372                         // see if it's an event name
5373                         for (int j = 0; j < source.m_eventData.Length; j++)
5374                         {
5375                             EventSource.EventMetadata[] ed = source.m_eventData;
5376                             if (ed[j].Name != null && ed[j].Name.Length == activityFilterString.Length &&
5377                                 string.Compare(ed[j].Name, activityFilterString, StringComparison.OrdinalIgnoreCase) == 0)
5378                             {
5379                                 eventId = ed[j].Descriptor.EventId;
5380                                 break;
5381                             }
5382                         }
5383                     }
5384                     if (eventId < 0 || eventId >= source.m_eventData.Length)
5385                     {
5386                         source.ReportOutOfBandMessage("ERROR: Invalid eventId specification: " + activityFilterString, false);
5387                         continue;
5388                     }
5389                     EnableFilter(ref filterList, source, perEventSourceSessionId, eventId, sampleFreq);
5390                 }
5391             }
5392         }
5393
5394         /// <summary>
5395         /// Returns the first ActivityFilter from 'filterList' corresponding to 'source'.
5396         /// </summary>
5397         public static ActivityFilter GetFilter(ActivityFilter filterList, EventSource source)
5398         {
5399             for (var af = filterList; af != null; af = af.m_next)
5400             {
5401                 if (af.m_providerGuid == source.Guid && af.m_samplingFreq != -1)
5402                     return af;
5403             }
5404             return null;
5405         }
5406
5407         /// <summary>
5408         /// Returns a session mask representing all sessions in which the activity 
5409         /// associated with the current thread is allowed  through the activity filter. 
5410         /// If 'triggeringEvent' is true the event MAY be a triggering event. Ideally 
5411         /// most of the time this is false as you can guarentee this event is NOT a 
5412         /// triggering event. If 'triggeringEvent' is true, then it checks the 
5413         /// 'EventSource' and 'eventID' of the event being logged to see if it is actually
5414         /// a trigger. If so it activates the current activity. 
5415         /// 
5416         /// If 'childActivityID' is present, it will be added to the active set if the 
5417         /// current activity is active.  
5418         /// </summary>
5419         unsafe public static bool PassesActivityFilter(
5420                                     ActivityFilter filterList,
5421                                     Guid* childActivityID,
5422                                     bool triggeringEvent,
5423                                     EventSource source,
5424                                     int eventId)
5425         {
5426             Debug.Assert(filterList != null && filterList.m_activeActivities != null);
5427             bool shouldBeLogged = false;
5428             if (triggeringEvent)
5429             {
5430                 for (ActivityFilter af = filterList; af != null; af = af.m_next)
5431                 {
5432                     if (eventId == af.m_eventId && source.Guid == af.m_providerGuid)
5433                     {
5434                         // Update the sampling count with wrap-around
5435                         int curSampleCount, newSampleCount;
5436                         do
5437                         {
5438                             curSampleCount = af.m_curSampleCount;
5439                             if (curSampleCount <= 1)
5440                                 newSampleCount = af.m_samplingFreq;        // Wrap around, counting down to 1
5441                             else
5442                                 newSampleCount = curSampleCount - 1;
5443                         }
5444                         while (Interlocked.CompareExchange(ref af.m_curSampleCount, newSampleCount, curSampleCount) != curSampleCount);
5445                         // If we hit zero, then start tracking the activity.  
5446                         if (curSampleCount <= 1)
5447                         {
5448                             Guid currentActivityId = EventSource.InternalCurrentThreadActivityId;
5449                             Tuple<Guid, int> startId;
5450                             // only add current activity if it's not already a root activity
5451                             if (!af.m_rootActiveActivities.TryGetValue(currentActivityId, out startId))
5452                             {
5453                                 // EventSource.OutputDebugString(string.Format("  PassesAF - Triggering(session {0}, evt {1})", af.m_perEventSourceSessionId, eventId));
5454                                 shouldBeLogged = true;
5455                                 af.m_activeActivities[currentActivityId] = Environment.TickCount;
5456                                 af.m_rootActiveActivities[currentActivityId] = Tuple.Create(source.Guid, eventId);
5457                             }
5458                         }
5459                         else
5460                         {
5461                             // a start event following a triggering start event
5462                             Guid currentActivityId = EventSource.InternalCurrentThreadActivityId;
5463                             Tuple<Guid, int> startId;
5464                             // only remove current activity if we added it
5465                             if (af.m_rootActiveActivities.TryGetValue(currentActivityId, out startId) &&
5466                                 startId.Item1 == source.Guid && startId.Item2 == eventId)
5467                             {
5468                                 // EventSource.OutputDebugString(string.Format("Activity dying: {0} -> StartEvent({1})", currentActivityId, eventId));
5469                                 // remove activity only from current logging scope (af)
5470                                 int dummy;
5471                                 af.m_activeActivities.TryRemove(currentActivityId, out dummy);
5472                             }
5473                         }
5474                         break;
5475                     }
5476                 }
5477             }
5478
5479             var activeActivities = GetActiveActivities(filterList);
5480             if (activeActivities != null)
5481             {
5482                 // if we hadn't already determined this should be logged, test further
5483                 if (!shouldBeLogged)
5484                 {
5485                     shouldBeLogged = !activeActivities.IsEmpty &&
5486                                      activeActivities.ContainsKey(EventSource.InternalCurrentThreadActivityId);
5487                 }
5488                 if (shouldBeLogged && childActivityID != null &&
5489                     ((EventOpcode)source.m_eventData[eventId].Descriptor.Opcode == EventOpcode.Send))
5490                 {
5491                     FlowActivityIfNeeded(filterList, null, childActivityID);
5492                     // EventSource.OutputDebugString(string.Format("  PassesAF - activity {0}", *childActivityID));
5493                 }
5494             }
5495             // EventSource.OutputDebugString(string.Format("  PassesAF - shouldBeLogged(evt {0}) = {1:x}", eventId, shouldBeLogged));
5496             return shouldBeLogged;
5497         }
5498
5499         public static bool IsCurrentActivityActive(ActivityFilter filterList)
5500         {
5501             var activeActivities = GetActiveActivities(filterList);
5502             if (activeActivities != null &&
5503                 activeActivities.ContainsKey(EventSource.InternalCurrentThreadActivityId))
5504                 return true;
5505
5506             return false;
5507         }
5508
5509         /// <summary>
5510         /// For the EventListener/EtwSession associated with 'filterList', add 'childActivityid'
5511         /// to list of active activities IF 'currentActivityId' is also active. Passing in a null
5512         /// value for  'currentActivityid' is an indication tha caller has already verified
5513         /// that the current activity is active.
5514         /// </summary>
5515         unsafe public static void FlowActivityIfNeeded(ActivityFilter filterList, Guid* currentActivityId, Guid* childActivityID)
5516         {
5517             Debug.Assert(childActivityID != null);
5518
5519             var activeActivities = GetActiveActivities(filterList);
5520             Debug.Assert(activeActivities != null);
5521
5522             // take currentActivityId == null to mean we *know* the current activity is "active"
5523             if (currentActivityId != null && !activeActivities.ContainsKey(*currentActivityId))
5524                 return;
5525
5526             if (activeActivities.Count > MaxActivityTrackCount)
5527             {
5528                 TrimActiveActivityStore(activeActivities);
5529                 // make sure current activity is still in the set:
5530                 activeActivities[EventSource.InternalCurrentThreadActivityId] = Environment.TickCount;
5531             }
5532             // add child activity to list of actives
5533             activeActivities[*childActivityID] = Environment.TickCount;
5534
5535         }
5536
5537         /// <summary>
5538         /// </summary>
5539         public static void UpdateKwdTriggers(ActivityFilter activityFilter, Guid sourceGuid, EventSource source, EventKeywords sessKeywords)
5540         {
5541             for (var af = activityFilter; af != null; af = af.m_next)
5542             {
5543                 if ((sourceGuid == af.m_providerGuid) &&
5544                     (source.m_eventData[af.m_eventId].TriggersActivityTracking > 0 ||
5545                     ((EventOpcode)source.m_eventData[af.m_eventId].Descriptor.Opcode == EventOpcode.Send)))
5546                 {
5547                     // we could be more precise here, if we tracked 'anykeywords' per session
5548                     unchecked
5549                     {
5550                         source.m_keywordTriggers |= (source.m_eventData[af.m_eventId].Descriptor.Keywords & (long)sessKeywords);
5551                     }
5552                 }
5553             }
5554         }
5555
5556         /// <summary>
5557         /// For the EventSource specified by 'sourceGuid' and the EventListener/EtwSession 
5558         /// associated with 'this' ActivityFilter list, return configured sequence of 
5559         /// [eventId, sampleFreq] pairs that defines the sampling policy.
5560         /// </summary>
5561         public IEnumerable<Tuple<int, int>> GetFilterAsTuple(Guid sourceGuid)
5562         {
5563             for (ActivityFilter af = this; af != null; af = af.m_next)
5564             {
5565                 if (af.m_providerGuid == sourceGuid)
5566                     yield return Tuple.Create(af.m_eventId, af.m_samplingFreq);
5567             }
5568         }
5569
5570         /// <summary>
5571         /// The cleanup being performed consists of removing the m_myActivityDelegate from
5572         /// the static s_activityDying, therefore allowing the ActivityFilter to be reclaimed.
5573         /// </summary>
5574         public void Dispose()
5575         {
5576 #if !ES_BUILD_STANDALONE
5577             Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
5578 #endif
5579             // m_myActivityDelegate is still alive (held by the static EventSource.s_activityDying). 
5580             // Therefore we are ok to take a dependency on m_myActivityDelegate being valid even 
5581             // during the finalization of the ActivityFilter
5582             if (m_myActivityDelegate != null)
5583             {
5584                 EventSource.s_activityDying = (Action<Guid>)Delegate.Remove(EventSource.s_activityDying, m_myActivityDelegate);
5585                 m_myActivityDelegate = null;
5586             }
5587         }
5588
5589         #region private
5590
5591         /// <summary>
5592         /// Creates a new ActivityFilter that is triggered by 'eventId' from 'source' ever
5593         /// 'samplingFreq' times the event fires. You can have several of these forming a 
5594         /// linked list.
5595         /// </summary>
5596         private ActivityFilter(EventSource source, int perEventSourceSessionId, int eventId, int samplingFreq, ActivityFilter existingFilter = null)
5597         {
5598             m_providerGuid = source.Guid;
5599             m_perEventSourceSessionId = perEventSourceSessionId;
5600             m_eventId = eventId;
5601             m_samplingFreq = samplingFreq;
5602             m_next = existingFilter;
5603
5604             Debug.Assert(existingFilter == null ||
5605                             (existingFilter.m_activeActivities == null) == (existingFilter.m_rootActiveActivities == null));
5606
5607             // if this is the first filter we add for this session, we need to create a new 
5608             // table of activities. m_activeActivities is common across EventSources in the same
5609             // session
5610             ConcurrentDictionary<Guid, int> activeActivities = null;
5611             if (existingFilter == null ||
5612                 (activeActivities = GetActiveActivities(existingFilter)) == null)
5613             {
5614                 m_activeActivities = new ConcurrentDictionary<Guid, int>();
5615                 m_rootActiveActivities = new ConcurrentDictionary<Guid, Tuple<Guid, int>>();
5616
5617                 // Add a delegate to the 'SetCurrentThreadToActivity callback so that I remove 'dead' activities
5618                 m_myActivityDelegate = GetActivityDyingDelegate(this);
5619                 EventSource.s_activityDying = (Action<Guid>)Delegate.Combine(EventSource.s_activityDying, m_myActivityDelegate);
5620             }
5621             else
5622             {
5623                 m_activeActivities = activeActivities;
5624                 m_rootActiveActivities = existingFilter.m_rootActiveActivities;
5625             }
5626
5627         }
5628
5629         /// <summary>
5630         /// Ensure there's at least one ActivityFilter in the 'filterList' that contains an
5631         /// activity-removing delegate for the listener/session associated with 'filterList'.
5632         /// </summary>
5633         private static void EnsureActivityCleanupDelegate(ActivityFilter filterList)
5634         {
5635             if (filterList == null)
5636                 return;
5637
5638             for (ActivityFilter af = filterList; af != null; af = af.m_next)
5639             {
5640                 if (af.m_myActivityDelegate != null)
5641                     return;
5642             }
5643
5644             // we didn't find a delegate
5645             filterList.m_myActivityDelegate = GetActivityDyingDelegate(filterList);
5646             EventSource.s_activityDying = (Action<Guid>)Delegate.Combine(EventSource.s_activityDying, filterList.m_myActivityDelegate);
5647         }
5648
5649         /// <summary>
5650         /// Builds the delegate to be called when an activity is dying. This is responsible
5651         /// for performing whatever cleanup is needed for the ActivityFilter list passed in.
5652         /// This gets "added" to EventSource.s_activityDying and ends up being called from
5653         /// EventSource.SetCurrentThreadActivityId and ActivityFilter.PassesActivityFilter.
5654         /// </summary>
5655         /// <returns>The delegate to be called when an activity is dying</returns>
5656         private static Action<Guid> GetActivityDyingDelegate(ActivityFilter filterList)
5657         {
5658             return (Guid oldActivity) =>
5659             {
5660                 int dummy;
5661                 filterList.m_activeActivities.TryRemove(oldActivity, out dummy);
5662                 Tuple<Guid, int> dummyTuple;
5663                 filterList.m_rootActiveActivities.TryRemove(oldActivity, out dummyTuple);
5664             };
5665         }
5666
5667         /// <summary>
5668         /// Enables activity filtering for the listener associated with 'filterList', triggering on
5669         /// the event 'eventID' from 'source' with a sampling frequency of 'samplingFreq'
5670         /// 
5671         /// if 'eventID' is out of range (e.g. negative), it means we are not triggering (but we are 
5672         /// activitySampling if something else triggered).  
5673         /// </summary>
5674         /// <returns>true if activity sampling is enabled the samplingFreq is non-zero </returns>
5675         private static bool EnableFilter(ref ActivityFilter filterList, EventSource source, int perEventSourceSessionId, int eventId, int samplingFreq)
5676         {
5677 #if !ES_BUILD_STANDALONE
5678             Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
5679 #endif
5680             Debug.Assert(samplingFreq > 0);
5681             Debug.Assert(eventId >= 0);
5682
5683             filterList = new ActivityFilter(source, perEventSourceSessionId, eventId, samplingFreq, filterList);
5684
5685             // Mark the 'quick Check' that indicates this is a trigger event.  
5686             // If eventId is out of range then this mark is not done which has the effect of ignoring 
5687             // the trigger.
5688             if (0 <= eventId && eventId < source.m_eventData.Length)
5689                 ++source.m_eventData[eventId].TriggersActivityTracking;
5690
5691             return true;
5692         }
5693
5694         /// <summary>
5695         /// Normally this code never runs, it is here just to prevent run-away resource usage.  
5696         /// </summary>
5697         private static void TrimActiveActivityStore(ConcurrentDictionary<Guid, int> activities)
5698         {
5699             if (activities.Count > MaxActivityTrackCount)
5700             {
5701                 // Remove half of the oldest activity ids.  
5702                 var keyValues = activities.ToArray();
5703                 var tickNow = Environment.TickCount;
5704
5705                 // Sort by age, taking into account wrap-around.   As long as x and y are within 
5706                 // 23 days of now then (0x7FFFFFFF & (tickNow - x.Value)) is the delta (even if 
5707                 // TickCount wraps).  I then sort by DESCENDING age.  (that is oldest value first)
5708                 Array.Sort(keyValues, (x, y) => (0x7FFFFFFF & (tickNow - y.Value)) - (0x7FFFFFFF & (tickNow - x.Value)));
5709                 for (int i = 0; i < keyValues.Length / 2; i++)
5710                 {
5711                     int dummy;
5712                     activities.TryRemove(keyValues[i].Key, out dummy);
5713                 }
5714             }
5715         }
5716
5717         private static ConcurrentDictionary<Guid, int> GetActiveActivities(
5718                                     ActivityFilter filterList)
5719         {
5720             for (ActivityFilter af = filterList; af != null; af = af.m_next)
5721             {
5722                 if (af.m_activeActivities != null)
5723                     return af.m_activeActivities;
5724             }
5725             return null;
5726         }
5727
5728         // m_activeActivities always points to the sample dictionary for EVERY ActivityFilter  
5729         // in the m_next list. The 'int' value in the m_activities set is a timestamp 
5730         // (Environment.TickCount) of when the entry was put in the system and is used to 
5731         // remove 'old' entries that if the set gets too big.
5732         ConcurrentDictionary<Guid, int> m_activeActivities;
5733
5734         // m_rootActiveActivities holds the "root" active activities, i.e. the activities 
5735         // that were marked as active because a Start event fired on them. We need to keep
5736         // track of these to enable sampling in the scenario of an app's main thread that 
5737         // never explicitly sets distinct activity IDs as it executes. To handle these
5738         // situations we manufacture a Guid from the thread's ID, and:
5739         //   (a) we consider the firing of a start event when the sampling counter reaches 
5740         //       zero to mark the beginning of an interesting activity, and 
5741         //   (b) we consider the very next firing of the same start event to mark the
5742         //       ending of that activity.
5743         // We use a ConcurrentDictionary to avoid taking explicit locks.
5744         //   The key (a guid) represents the activity ID of the root active activity
5745         //   The value is made up of the Guid of the event provider and the eventId of
5746         //      the start event.
5747         ConcurrentDictionary<Guid, Tuple<Guid, int>> m_rootActiveActivities;
5748         Guid m_providerGuid;        // We use the GUID rather than object identity because we don't want to keep the eventSource alive
5749         int m_eventId;              // triggering event
5750         int m_samplingFreq;         // Counter reset to this when it hits 0
5751         int m_curSampleCount;       // We count down to 0 and then activate the activity. 
5752         int m_perEventSourceSessionId;  // session ID bit for ETW, 0 for EventListeners
5753
5754         const int MaxActivityTrackCount = 100000;   // maximum number of tracked activities
5755
5756         ActivityFilter m_next;      // We create a linked list of these
5757         Action<Guid> m_myActivityDelegate;
5758         #endregion
5759     };
5760
5761
5762     /// <summary>
5763     /// An EtwSession instance represents an activity-tracing-aware ETW session. Since these
5764     /// are limited to 8 concurrent sessions per machine (currently) we're going to store
5765     /// the active ones in a singly linked list.
5766     /// </summary>
5767     internal class EtwSession
5768     {
5769         public static EtwSession GetEtwSession(int etwSessionId, bool bCreateIfNeeded = false)
5770         {
5771             if (etwSessionId < 0)
5772                 return null;
5773
5774             EtwSession etwSession;
5775             foreach (var wrEtwSession in s_etwSessions)
5776             {
5777 #if ES_BUILD_STANDALONE
5778                 if ((etwSession = (EtwSession) wrEtwSession.Target) != null && etwSession.m_etwSessionId == etwSessionId)
5779                     return etwSession;
5780 #else
5781                 if (wrEtwSession.TryGetTarget(out etwSession) && etwSession.m_etwSessionId == etwSessionId)
5782                     return etwSession;
5783 #endif
5784             }
5785
5786             if (!bCreateIfNeeded)
5787                 return null;
5788
5789 #if ES_BUILD_STANDALONE
5790             if (s_etwSessions == null)
5791                 s_etwSessions = new List<WeakReference>();
5792
5793             etwSession = new EtwSession(etwSessionId);
5794             s_etwSessions.Add(new WeakReference(etwSession));
5795 #else
5796             if (s_etwSessions == null)
5797                 s_etwSessions = new List<WeakReference<EtwSession>>();
5798
5799             etwSession = new EtwSession(etwSessionId);
5800             s_etwSessions.Add(new WeakReference<EtwSession>(etwSession));
5801 #endif
5802
5803             if (s_etwSessions.Count > s_thrSessionCount)
5804                 TrimGlobalList();
5805
5806             return etwSession;
5807
5808         }
5809
5810         public static void RemoveEtwSession(EtwSession etwSession)
5811         {
5812             Debug.Assert(etwSession != null);
5813             if (s_etwSessions == null || etwSession == null)
5814                 return;
5815
5816             s_etwSessions.RemoveAll((wrEtwSession) =>
5817                 {
5818                     EtwSession session;
5819 #if ES_BUILD_STANDALONE
5820                     return (session = (EtwSession) wrEtwSession.Target) != null &&
5821                            (session.m_etwSessionId == etwSession.m_etwSessionId);
5822 #else
5823                     return wrEtwSession.TryGetTarget(out session) &&
5824                            (session.m_etwSessionId == etwSession.m_etwSessionId);
5825 #endif
5826                 });
5827
5828             if (s_etwSessions.Count > s_thrSessionCount)
5829                 TrimGlobalList();
5830         }
5831
5832         private static void TrimGlobalList()
5833         {
5834             if (s_etwSessions == null)
5835                 return;
5836
5837             s_etwSessions.RemoveAll((wrEtwSession) =>
5838                 {
5839 #if ES_BUILD_STANDALONE
5840                     return wrEtwSession.Target == null;
5841 #else
5842                     EtwSession session;
5843                     return !wrEtwSession.TryGetTarget(out session);
5844 #endif
5845                 });
5846         }
5847
5848         private EtwSession(int etwSessionId)
5849         {
5850             m_etwSessionId = etwSessionId;
5851         }
5852
5853         public readonly int m_etwSessionId;        // ETW session ID (as retrieved by EventProvider)
5854         public ActivityFilter m_activityFilter;    // all filters enabled for this session
5855
5856 #if ES_BUILD_STANDALONE
5857         private static List<WeakReference> s_etwSessions = new List<WeakReference>();
5858 #else
5859         private static List<WeakReference<EtwSession>> s_etwSessions = new List<WeakReference<EtwSession>>();
5860 #endif
5861         private const int s_thrSessionCount = 16;
5862     }
5863
5864 #endif // FEATURE_ACTIVITYSAMPLING
5865
5866     // holds a bitfield representing a session mask
5867     /// <summary>
5868     /// A SessionMask represents a set of (at most MAX) sessions as a bit mask. The perEventSourceSessionId
5869     /// is the index in the SessionMask of the bit that will be set. These can translate to
5870     /// EventSource's reserved keywords bits using the provided ToEventKeywords() and
5871     /// FromEventKeywords() methods.
5872     /// </summary>
5873     internal struct SessionMask
5874     {
5875         public SessionMask(SessionMask m)
5876         { m_mask = m.m_mask; }
5877
5878         public SessionMask(uint mask = 0)
5879         { m_mask = mask & MASK; }
5880
5881         public bool IsEqualOrSupersetOf(SessionMask m)
5882         {
5883             return (this.m_mask | m.m_mask) == this.m_mask;
5884         }
5885
5886         public static SessionMask All
5887         {
5888             get { return new SessionMask(MASK); }
5889         }
5890
5891         public static SessionMask FromId(int perEventSourceSessionId)
5892         {
5893             Debug.Assert(perEventSourceSessionId < MAX);
5894             return new SessionMask((uint)1 << perEventSourceSessionId);
5895         }
5896
5897         public ulong ToEventKeywords()
5898         {
5899             return (ulong)m_mask << SHIFT_SESSION_TO_KEYWORD;
5900         }
5901
5902         public static SessionMask FromEventKeywords(ulong m)
5903         {
5904             return new SessionMask((uint)(m >> SHIFT_SESSION_TO_KEYWORD));
5905         }
5906
5907         public bool this[int perEventSourceSessionId]
5908         {
5909             get
5910             {
5911                 Debug.Assert(perEventSourceSessionId < MAX);
5912                 return (m_mask & (1 << perEventSourceSessionId)) != 0;
5913             }
5914             set
5915             {
5916                 Debug.Assert(perEventSourceSessionId < MAX);
5917                 if (value) m_mask |= ((uint)1 << perEventSourceSessionId);
5918                 else m_mask &= ~((uint)1 << perEventSourceSessionId);
5919             }
5920         }
5921
5922         public static SessionMask operator |(SessionMask m1, SessionMask m2)
5923         {
5924             return new SessionMask(m1.m_mask | m2.m_mask);
5925         }
5926
5927         public static SessionMask operator &(SessionMask m1, SessionMask m2)
5928         {
5929             return new SessionMask(m1.m_mask & m2.m_mask);
5930         }
5931
5932         public static SessionMask operator ^(SessionMask m1, SessionMask m2)
5933         {
5934             return new SessionMask(m1.m_mask ^ m2.m_mask);
5935         }
5936
5937         public static SessionMask operator ~(SessionMask m)
5938         {
5939             return new SessionMask(MASK & ~(m.m_mask));
5940         }
5941
5942         public static explicit operator ulong(SessionMask m)
5943         { return m.m_mask; }
5944
5945         public static explicit operator uint(SessionMask m)
5946         { return m.m_mask; }
5947
5948         private uint m_mask;
5949
5950         internal const int SHIFT_SESSION_TO_KEYWORD = 44;         // bits 44-47 inclusive are reserved
5951         internal const uint MASK = 0x0fU;                         // the mask of 4 reserved bits
5952         internal const uint MAX = 4;                              // maximum number of simultaneous ETW sessions supported
5953     }
5954
5955     /// <summary>
5956     /// code:EventDispatchers are a simple 'helper' structure that holds the filtering state
5957     /// (m_EventEnabled) for a particular EventSource X EventListener tuple
5958     /// 
5959     /// Thus a single EventListener may have many EventDispatchers (one for every EventSource 
5960     /// that that EventListener has activate) and a Single EventSource may also have many
5961     /// event Dispatchers (one for every EventListener that has activated it). 
5962     /// 
5963     /// Logically a particular EventDispatcher belongs to exactly one EventSource and exactly  
5964     /// one EventListener (alhtough EventDispatcher does not 'remember' the EventSource it is
5965     /// associated with. 
5966     /// </summary>
5967     internal class EventDispatcher
5968     {
5969         internal EventDispatcher(EventDispatcher next, bool[] eventEnabled, EventListener listener)
5970         {
5971             m_Next = next;
5972             m_EventEnabled = eventEnabled;
5973             m_Listener = listener;
5974         }
5975
5976         // Instance fields
5977         readonly internal EventListener m_Listener;   // The dispatcher this entry is for
5978         internal bool[] m_EventEnabled;               // For every event in a the eventSource, is it enabled?
5979 #if FEATURE_ACTIVITYSAMPLING
5980         internal bool m_activityFilteringEnabled;     // does THIS EventSource have activity filtering turned on for this listener?
5981 #endif // FEATURE_ACTIVITYSAMPLING
5982
5983         // Only guaranteed to exist after a InsureInit()
5984         internal EventDispatcher m_Next;              // These form a linked list in code:EventSource.m_Dispatchers
5985         // Of all listeners for that eventSource.  
5986     }
5987
5988     /// <summary>
5989     /// Flags that can be used with EventSource.GenerateManifest to control how the ETW manifest for the EventSource is
5990     /// generated.
5991     /// </summary>
5992     [Flags]
5993     public enum EventManifestOptions
5994     {
5995         /// <summary>
5996         /// Only the resources associated with current UI culture are included in the  manifest
5997         /// </summary>
5998         None = 0x0,
5999         /// <summary>
6000         /// Throw exceptions for any inconsistency encountered
6001         /// </summary>
6002         Strict = 0x1,
6003         /// <summary>
6004         /// Generate a "resources" node under "localization" for every satellite assembly provided
6005         /// </summary>
6006         AllCultures = 0x2,
6007         /// <summary>
6008         /// Generate the manifest only if the event source needs to be registered on the machine,
6009         /// otherwise return null (but still perform validation if Strict is specified)
6010         /// </summary>
6011         OnlyIfNeededForRegistration = 0x4,
6012         /// <summary>
6013         /// When generating the manifest do *not* enforce the rule that the current EventSource class
6014         /// must be the base class for the user-defined type passed in. This allows validation of .net
6015         /// event sources using the new validation code
6016         /// </summary>
6017         AllowEventSourceOverride = 0x8,
6018     }
6019
6020     /// <summary>
6021     /// ManifestBuilder is designed to isolate the details of the message of the event from the
6022     /// rest of EventSource.  This one happens to create XML. 
6023     /// </summary>
6024     internal partial class ManifestBuilder
6025     {
6026         /// <summary>
6027         /// Build a manifest for 'providerName' with the given GUID, which will be packaged into 'dllName'.
6028         /// 'resources, is a resource manager.  If specified all messages are localized using that manager.  
6029         /// </summary>
6030         public ManifestBuilder(string providerName, Guid providerGuid, string dllName, ResourceManager resources,
6031                                EventManifestOptions flags)
6032         {
6033 #if FEATURE_MANAGED_ETW_CHANNELS
6034             this.providerName = providerName;
6035 #endif
6036             this.flags = flags;
6037
6038             this.resources = resources;
6039             sb = new StringBuilder();
6040             events = new StringBuilder();
6041             templates = new StringBuilder();
6042             opcodeTab = new Dictionary<int, string>();
6043             stringTab = new Dictionary<string, string>();
6044             errors = new List<string>();
6045             perEventByteArrayArgIndices = new Dictionary<string, List<int>>();
6046
6047             sb.AppendLine("<instrumentationManifest xmlns=\"http://schemas.microsoft.com/win/2004/08/events\">");
6048             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\">");
6049             sb.AppendLine("  <events xmlns=\"http://schemas.microsoft.com/win/2004/08/events\">");
6050             sb.Append("<provider name=\"").Append(providerName).
6051                Append("\" guid=\"{").Append(providerGuid.ToString()).Append("}");
6052             if (dllName != null)
6053                 sb.Append("\" resourceFileName=\"").Append(dllName).Append("\" messageFileName=\"").Append(dllName);
6054
6055             var symbolsName = providerName.Replace("-", "").Replace(".", "_");  // Period and - are illegal replace them.
6056             sb.Append("\" symbol=\"").Append(symbolsName);
6057             sb.Append("\">").AppendLine();
6058         }
6059
6060         public void AddOpcode(string name, int value)
6061         {
6062             if ((flags & EventManifestOptions.Strict) != 0)
6063             {
6064                 if (value <= 10 || value >= 239)
6065                 {
6066                     ManifestError(Resources.GetResourceString("EventSource_IllegalOpcodeValue", name, value));
6067                 }
6068                 string prevName;
6069                 if (opcodeTab.TryGetValue(value, out prevName) && !name.Equals(prevName, StringComparison.Ordinal))
6070                 {
6071                     ManifestError(Resources.GetResourceString("EventSource_OpcodeCollision", name, prevName, value));
6072                 }
6073             }
6074             opcodeTab[value] = name;
6075         }
6076         public void AddTask(string name, int value)
6077         {
6078             if ((flags & EventManifestOptions.Strict) != 0)
6079             {
6080                 if (value <= 0 || value >= 65535)
6081                 {
6082                     ManifestError(Resources.GetResourceString("EventSource_IllegalTaskValue", name, value));
6083                 }
6084                 string prevName;
6085                 if (taskTab != null && taskTab.TryGetValue(value, out prevName) && !name.Equals(prevName, StringComparison.Ordinal))
6086                 {
6087                     ManifestError(Resources.GetResourceString("EventSource_TaskCollision", name, prevName, value));
6088                 }
6089             }
6090             if (taskTab == null)
6091                 taskTab = new Dictionary<int, string>();
6092             taskTab[value] = name;
6093         }
6094         public void AddKeyword(string name, ulong value)
6095         {
6096             if ((value & (value - 1)) != 0)   // Is it a power of 2?
6097             {
6098                 ManifestError(Resources.GetResourceString("EventSource_KeywordNeedPowerOfTwo", "0x" + value.ToString("x", CultureInfo.CurrentCulture), name), true);
6099             }
6100             if ((flags & EventManifestOptions.Strict) != 0)
6101             {
6102                 if (value >= 0x0000100000000000UL && !name.StartsWith("Session", StringComparison.Ordinal))
6103                 {
6104                     ManifestError(Resources.GetResourceString("EventSource_IllegalKeywordsValue", name, "0x" + value.ToString("x", CultureInfo.CurrentCulture)));
6105                 }
6106                 string prevName;
6107                 if (keywordTab != null && keywordTab.TryGetValue(value, out prevName) && !name.Equals(prevName, StringComparison.Ordinal))
6108                 {
6109                     ManifestError(Resources.GetResourceString("EventSource_KeywordCollision", name, prevName, "0x" + value.ToString("x", CultureInfo.CurrentCulture)));
6110                 }
6111             }
6112             if (keywordTab == null)
6113                 keywordTab = new Dictionary<ulong, string>();
6114             keywordTab[value] = name;
6115         }
6116
6117 #if FEATURE_MANAGED_ETW_CHANNELS
6118         /// <summary>
6119         /// Add a channel.  channelAttribute can be null
6120         /// </summary>
6121         public void AddChannel(string name, int value, EventChannelAttribute channelAttribute)
6122         {
6123             EventChannel chValue = (EventChannel)value;
6124             if (value < (int)EventChannel.Admin || value > 255)
6125                 ManifestError(Resources.GetResourceString("EventSource_EventChannelOutOfRange", name, value));
6126             else if (chValue >= EventChannel.Admin && chValue <= EventChannel.Debug &&
6127                      channelAttribute != null && EventChannelToChannelType(chValue) != channelAttribute.EventChannelType)
6128             {
6129                 // we want to ensure developers do not define EventChannels that conflict with the builtin ones,
6130                 // but we want to allow them to override the default ones...
6131                 ManifestError(Resources.GetResourceString("EventSource_ChannelTypeDoesNotMatchEventChannelValue",
6132                                                                             name, ((EventChannel)value).ToString()));
6133             }
6134
6135             // TODO: validate there are no conflicting manifest exposed names (generally following the format "provider/type")
6136
6137             ulong kwd = GetChannelKeyword(chValue);
6138
6139             if (channelTab == null)
6140                 channelTab = new Dictionary<int, ChannelInfo>(4);
6141             channelTab[value] = new ChannelInfo { Name = name, Keywords = kwd, Attribs = channelAttribute };
6142         }
6143
6144         private EventChannelType EventChannelToChannelType(EventChannel channel)
6145         {
6146 #if !ES_BUILD_STANDALONE
6147             Debug.Assert(channel >= EventChannel.Admin && channel <= EventChannel.Debug);
6148 #endif
6149             return (EventChannelType)((int)channel - (int)EventChannel.Admin + (int)EventChannelType.Admin);
6150         }
6151         private EventChannelAttribute GetDefaultChannelAttribute(EventChannel channel)
6152         {
6153             EventChannelAttribute attrib = new EventChannelAttribute();
6154             attrib.EventChannelType = EventChannelToChannelType(channel);
6155             if (attrib.EventChannelType <= EventChannelType.Operational)
6156                 attrib.Enabled = true;
6157             return attrib;
6158         }
6159
6160         public ulong[] GetChannelData()
6161         {
6162             if (this.channelTab == null)
6163             {
6164                 return new ulong[0];
6165             }
6166
6167             // We create an array indexed by the channel id for fast look up.
6168             // E.g. channelMask[Admin] will give you the bit mask for Admin channel.
6169             int maxkey = -1;
6170             foreach (var item in this.channelTab.Keys)
6171             {
6172                 if (item > maxkey)
6173                 {
6174                     maxkey = item;
6175                 }
6176             }
6177
6178             ulong[] channelMask = new ulong[maxkey + 1];
6179             foreach (var item in this.channelTab)
6180             {
6181                 channelMask[item.Key] = item.Value.Keywords;
6182             }
6183
6184             return channelMask;
6185         }
6186
6187 #endif
6188         public void StartEvent(string eventName, EventAttribute eventAttribute)
6189         {
6190             Debug.Assert(numParams == 0);
6191             Debug.Assert(this.eventName == null);
6192             this.eventName = eventName;
6193             numParams = 0;
6194             byteArrArgIndices = null;
6195
6196             events.Append("  <event").
6197                  Append(" value=\"").Append(eventAttribute.EventId).Append("\"").
6198                  Append(" version=\"").Append(eventAttribute.Version).Append("\"").
6199                  Append(" level=\"").Append(GetLevelName(eventAttribute.Level)).Append("\"").
6200                  Append(" symbol=\"").Append(eventName).Append("\"");
6201
6202             // at this point we add to the manifest's stringTab a message that is as-of-yet 
6203             // "untranslated to manifest convention", b/c we don't have the number or position 
6204             // of any byte[] args (which require string format index updates)
6205             WriteMessageAttrib(events, "event", eventName, eventAttribute.Message);
6206
6207             if (eventAttribute.Keywords != 0)
6208                 events.Append(" keywords=\"").Append(GetKeywords((ulong)eventAttribute.Keywords, eventName)).Append("\"");
6209             if (eventAttribute.Opcode != 0)
6210                 events.Append(" opcode=\"").Append(GetOpcodeName(eventAttribute.Opcode, eventName)).Append("\"");
6211             if (eventAttribute.Task != 0)
6212                 events.Append(" task=\"").Append(GetTaskName(eventAttribute.Task, eventName)).Append("\"");
6213 #if FEATURE_MANAGED_ETW_CHANNELS
6214             if (eventAttribute.Channel != 0)
6215             {
6216                 events.Append(" channel=\"").Append(GetChannelName(eventAttribute.Channel, eventName, eventAttribute.Message)).Append("\"");
6217             }
6218 #endif
6219         }
6220
6221         public void AddEventParameter(Type type, string name)
6222         {
6223             if (numParams == 0)
6224                 templates.Append("  <template tid=\"").Append(eventName).Append("Args\">").AppendLine();
6225             if (type == typeof(byte[]))
6226             {
6227                 // mark this index as "extraneous" (it has no parallel in the managed signature)
6228                 // we use these values in TranslateToManifestConvention()
6229                 if (byteArrArgIndices == null)
6230                     byteArrArgIndices = new List<int>(4);
6231                 byteArrArgIndices.Add(numParams);
6232
6233                 // add an extra field to the template representing the length of the binary blob
6234                 numParams++;
6235                 templates.Append("   <data name=\"").Append(name).Append("Size\" inType=\"win:UInt32\"/>").AppendLine();
6236             }
6237             numParams++;
6238             templates.Append("   <data name=\"").Append(name).Append("\" inType=\"").Append(GetTypeName(type)).Append("\"");
6239             // TODO: for 'byte*' types it assumes the user provided length is named using the same naming convention
6240             //       as for 'byte[]' args (blob_arg_name + "Size")
6241             if ((type.IsArray || type.IsPointer) && type.GetElementType() == typeof(byte))
6242             {
6243                 // add "length" attribute to the "blob" field in the template (referencing the field added above)
6244                 templates.Append(" length=\"").Append(name).Append("Size\"");
6245             }
6246             // ETW does not support 64-bit value maps, so we don't specify these as ETW maps
6247             if (type.IsEnum() && Enum.GetUnderlyingType(type) != typeof(UInt64) && Enum.GetUnderlyingType(type) != typeof(Int64))
6248             {
6249                 templates.Append(" map=\"").Append(type.Name).Append("\"");
6250                 if (mapsTab == null)
6251                     mapsTab = new Dictionary<string, Type>();
6252                 if (!mapsTab.ContainsKey(type.Name))
6253                     mapsTab.Add(type.Name, type);        // Remember that we need to dump the type enumeration  
6254             }
6255
6256             templates.Append("/>").AppendLine();
6257         }
6258         public void EndEvent()
6259         {
6260             if (numParams > 0)
6261             {
6262                 templates.Append("  </template>").AppendLine();
6263                 events.Append(" template=\"").Append(eventName).Append("Args\"");
6264             }
6265             events.Append("/>").AppendLine();
6266
6267             if (byteArrArgIndices != null)
6268                 perEventByteArrayArgIndices[eventName] = byteArrArgIndices;
6269
6270             // at this point we have all the information we need to translate the C# Message
6271             // to the manifest string we'll put in the stringTab
6272             string msg;
6273             if (stringTab.TryGetValue("event_" + eventName, out msg))
6274             {
6275                 msg = TranslateToManifestConvention(msg, eventName);
6276                 stringTab["event_" + eventName] = msg;
6277             }
6278
6279             eventName = null;
6280             numParams = 0;
6281             byteArrArgIndices = null;
6282         }
6283
6284 #if FEATURE_MANAGED_ETW_CHANNELS
6285         // Channel keywords are generated one per channel to allow channel based filtering in event viewer. These keywords are autogenerated
6286         // by mc.exe for compiling a manifest and are based on the order of the channels (fields) in the Channels inner class (when advanced
6287         // channel support is enabled), or based on the order the predefined channels appear in the EventAttribute properties (for simple 
6288         // support). The manifest generated *MUST* have the channels specified in the same order (that's how our computed keywords are mapped
6289         // to channels by the OS infrastructure).
6290         // If channelKeyworkds is present, and has keywords bits in the ValidPredefinedChannelKeywords then it is 
6291         // assumed that that the keyword for that channel should be that bit.   
6292         // otherwise we allocate a channel bit for the channel.  
6293         // explicit channel bits are only used by WCF to mimic an existing manifest, 
6294         // so we don't dont do error checking.  
6295         public ulong GetChannelKeyword(EventChannel channel, ulong channelKeyword = 0)
6296         {
6297             // strip off any non-channel keywords, since we are only interested in channels here.  
6298             channelKeyword &= ValidPredefinedChannelKeywords;
6299             if (channelTab == null)
6300             {
6301                 channelTab = new Dictionary<int, ChannelInfo>(4);
6302             }
6303
6304             if (channelTab.Count == MaxCountChannels)
6305                 ManifestError(Resources.GetResourceString("EventSource_MaxChannelExceeded"));
6306
6307             ChannelInfo info;
6308             if (!channelTab.TryGetValue((int)channel, out info))
6309             {
6310                 // If we were not given an explicit channel, allocate one.  
6311                 if (channelKeyword != 0)
6312                 {
6313                     channelKeyword = nextChannelKeywordBit;
6314                     nextChannelKeywordBit >>= 1;
6315                 }
6316             }
6317             else
6318             {
6319                 channelKeyword = info.Keywords;
6320             }
6321
6322             return channelKeyword;
6323         }
6324 #endif
6325
6326         public byte[] CreateManifest()
6327         {
6328             string str = CreateManifestString();
6329             return Encoding.UTF8.GetBytes(str);
6330         }
6331
6332         public IList<string> Errors { get { return errors; } }
6333
6334         /// <summary>
6335         /// When validating an event source it adds the error to the error collection.
6336         /// When not validating it throws an exception if runtimeCritical is "true".
6337         /// Otherwise the error is ignored.
6338         /// </summary>
6339         /// <param name="msg"></param>
6340         /// <param name="runtimeCritical"></param>
6341         public void ManifestError(string msg, bool runtimeCritical = false)
6342         {
6343             if ((flags & EventManifestOptions.Strict) != 0)
6344                 errors.Add(msg);
6345             else if (runtimeCritical)
6346                 throw new ArgumentException(msg);
6347         }
6348
6349         private string CreateManifestString()
6350         {
6351
6352 #if FEATURE_MANAGED_ETW_CHANNELS
6353             // Write out the channels
6354             if (channelTab != null)
6355             {
6356                 sb.Append(" <channels>").AppendLine();
6357                 var sortedChannels = new List<KeyValuePair<int, ChannelInfo>>();
6358                 foreach (KeyValuePair<int, ChannelInfo> p in channelTab) { sortedChannels.Add(p); }
6359                 sortedChannels.Sort((p1, p2) => -Comparer<ulong>.Default.Compare(p1.Value.Keywords, p2.Value.Keywords));
6360                 foreach (var kvpair in sortedChannels)
6361                 {
6362                     int channel = kvpair.Key;
6363                     ChannelInfo channelInfo = kvpair.Value;
6364
6365                     string channelType = null;
6366                     string elementName = "channel";
6367                     bool enabled = false;
6368                     string fullName = null;
6369 #if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
6370                     string isolation = null;
6371                     string access = null;
6372 #endif
6373                     if (channelInfo.Attribs != null)
6374                     {
6375                         var attribs = channelInfo.Attribs;
6376                         if (Enum.IsDefined(typeof(EventChannelType), attribs.EventChannelType))
6377                             channelType = attribs.EventChannelType.ToString();
6378                         enabled = attribs.Enabled;
6379 #if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
6380                         if (attribs.ImportChannel != null)
6381                         {
6382                             fullName = attribs.ImportChannel;
6383                             elementName = "importChannel";
6384                         }
6385                         if (Enum.IsDefined(typeof(EventChannelIsolation), attribs.Isolation))
6386                             isolation = attribs.Isolation.ToString();
6387                         access = attribs.Access;
6388 #endif
6389                     }
6390                     if (fullName == null)
6391                         fullName = providerName + "/" + channelInfo.Name;
6392
6393                     sb.Append("  <").Append(elementName);
6394                     sb.Append(" chid=\"").Append(channelInfo.Name).Append("\"");
6395                     sb.Append(" name=\"").Append(fullName).Append("\"");
6396                     if (elementName == "channel")   // not applicable to importChannels.
6397                     {
6398                         WriteMessageAttrib(sb, "channel", channelInfo.Name, null);
6399                         sb.Append(" value=\"").Append(channel).Append("\"");
6400                         if (channelType != null)
6401                             sb.Append(" type=\"").Append(channelType).Append("\"");
6402                         sb.Append(" enabled=\"").Append(enabled.ToString().ToLower()).Append("\"");
6403 #if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
6404                         if (access != null)
6405                             sb.Append(" access=\"").Append(access).Append("\"");
6406                         if (isolation != null)
6407                             sb.Append(" isolation=\"").Append(isolation).Append("\"");
6408 #endif
6409                     }
6410                     sb.Append("/>").AppendLine();
6411                 }
6412                 sb.Append(" </channels>").AppendLine();
6413             }
6414 #endif
6415
6416             // Write out the tasks
6417             if (taskTab != null)
6418             {
6419
6420                 sb.Append(" <tasks>").AppendLine();
6421                 var sortedTasks = new List<int>(taskTab.Keys);
6422                 sortedTasks.Sort();
6423                 foreach (int task in sortedTasks)
6424                 {
6425                     sb.Append("  <task");
6426                     WriteNameAndMessageAttribs(sb, "task", taskTab[task]);
6427                     sb.Append(" value=\"").Append(task).Append("\"/>").AppendLine();
6428                 }
6429                 sb.Append(" </tasks>").AppendLine();
6430             }
6431
6432             // Write out the maps
6433             if (mapsTab != null)
6434             {
6435                 sb.Append(" <maps>").AppendLine();
6436                 foreach (Type enumType in mapsTab.Values)
6437                 {
6438                     bool isbitmap = EventSource.GetCustomAttributeHelper(enumType, typeof(FlagsAttribute), flags) != null;
6439                     string mapKind = isbitmap ? "bitMap" : "valueMap";
6440                     sb.Append("  <").Append(mapKind).Append(" name=\"").Append(enumType.Name).Append("\">").AppendLine();
6441
6442                     // write out each enum value 
6443                     FieldInfo[] staticFields = enumType.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static);
6444                     foreach (FieldInfo staticField in staticFields)
6445                     {
6446                         object constantValObj = staticField.GetRawConstantValue();
6447                         if (constantValObj != null)
6448                         {
6449                             long hexValue;
6450                             if (constantValObj is int)
6451                                 hexValue = ((int)constantValObj);
6452                             else if (constantValObj is long)
6453                                 hexValue = ((long)constantValObj);
6454                             else
6455                                 continue;
6456
6457                             // ETW requires all bitmap values to be powers of 2.  Skip the ones that are not. 
6458                             // TODO: Warn people about the dropping of values. 
6459                             if (isbitmap && ((hexValue & (hexValue - 1)) != 0 || hexValue == 0))
6460                                 continue;
6461
6462                             sb.Append("   <map value=\"0x").Append(hexValue.ToString("x", CultureInfo.InvariantCulture)).Append("\"");
6463                             WriteMessageAttrib(sb, "map", enumType.Name + "." + staticField.Name, staticField.Name);
6464                             sb.Append("/>").AppendLine();
6465                         }
6466                     }
6467                     sb.Append("  </").Append(mapKind).Append(">").AppendLine();
6468                 }
6469                 sb.Append(" </maps>").AppendLine();
6470             }
6471
6472             // Write out the opcodes
6473             sb.Append(" <opcodes>").AppendLine();
6474             var sortedOpcodes = new List<int>(opcodeTab.Keys);
6475             sortedOpcodes.Sort();
6476             foreach (int opcode in sortedOpcodes)
6477             {
6478                 sb.Append("  <opcode");
6479                 WriteNameAndMessageAttribs(sb, "opcode", opcodeTab[opcode]);
6480                 sb.Append(" value=\"").Append(opcode).Append("\"/>").AppendLine();
6481             }
6482             sb.Append(" </opcodes>").AppendLine();
6483
6484             // Write out the keywords
6485             if (keywordTab != null)
6486             {
6487                 sb.Append(" <keywords>").AppendLine();
6488                 var sortedKeywords = new List<ulong>(keywordTab.Keys);
6489                 sortedKeywords.Sort();
6490                 foreach (ulong keyword in sortedKeywords)
6491                 {
6492                     sb.Append("  <keyword");
6493                     WriteNameAndMessageAttribs(sb, "keyword", keywordTab[keyword]);
6494                     sb.Append(" mask=\"0x").Append(keyword.ToString("x", CultureInfo.InvariantCulture)).Append("\"/>").AppendLine();
6495                 }
6496                 sb.Append(" </keywords>").AppendLine();
6497             }
6498
6499             sb.Append(" <events>").AppendLine();
6500             sb.Append(events);
6501             sb.Append(" </events>").AppendLine();
6502
6503             sb.Append(" <templates>").AppendLine();
6504             if (templates.Length > 0)
6505             {
6506                 sb.Append(templates);
6507             }
6508             else
6509             {
6510                 // Work around a cornercase ETW issue where a manifest with no templates causes 
6511                 // ETW events to not get sent to their associated channel.
6512                 sb.Append("    <template tid=\"_empty\"></template>").AppendLine();
6513             }
6514             sb.Append(" </templates>").AppendLine();
6515
6516             sb.Append("</provider>").AppendLine();
6517             sb.Append("</events>").AppendLine();
6518             sb.Append("</instrumentation>").AppendLine();
6519
6520             // Output the localization information.  
6521             sb.Append("<localization>").AppendLine();
6522
6523             List<CultureInfo> cultures = null;
6524             if (resources != null && (flags & EventManifestOptions.AllCultures) != 0)
6525             {
6526                 cultures = GetSupportedCultures(resources);
6527             }
6528             else
6529             {
6530                 cultures = new List<CultureInfo>();
6531                 cultures.Add(CultureInfo.CurrentUICulture);
6532             }
6533 #if ES_BUILD_STANDALONE || ES_BUILD_PN
6534             var sortedStrings = new List<string>(stringTab.Keys);
6535             sortedStrings.Sort();
6536 #else
6537             // DD 947936
6538             var sortedStrings = new string[stringTab.Keys.Count];
6539             stringTab.Keys.CopyTo(sortedStrings, 0);
6540             // Avoid using public Array.Sort as that attempts to access BinaryCompatibility. Unfortunately FrameworkEventSource gets called 
6541             // very early in the app domain creation, when _FusionStore is not set up yet, resulting in a failure to run the static constructory
6542             // for BinaryCompatibility. This failure is then cached and a TypeInitializationException is thrown every time some code attampts to
6543             // access BinaryCompatibility.
6544             ArraySortHelper<string>.IntrospectiveSort(sortedStrings, 0, sortedStrings.Length, string.Compare);
6545 #endif
6546             foreach (var ci in cultures)
6547             {
6548                 sb.Append(" <resources culture=\"").Append(ci.Name).Append("\">").AppendLine();
6549                 sb.Append("  <stringTable>").AppendLine();
6550
6551                 foreach (var stringKey in sortedStrings)
6552                 {
6553                     string val = GetLocalizedMessage(stringKey, ci, etwFormat: true);
6554                     sb.Append("   <string id=\"").Append(stringKey).Append("\" value=\"").Append(val).Append("\"/>").AppendLine();
6555                 }
6556                 sb.Append("  </stringTable>").AppendLine();
6557                 sb.Append(" </resources>").AppendLine();
6558             }
6559             sb.Append("</localization>").AppendLine();
6560             sb.AppendLine("</instrumentationManifest>");
6561             return sb.ToString();
6562         }
6563
6564         #region private
6565         private void WriteNameAndMessageAttribs(StringBuilder stringBuilder, string elementName, string name)
6566         {
6567             stringBuilder.Append(" name=\"").Append(name).Append("\"");
6568             WriteMessageAttrib(sb, elementName, name, name);
6569         }
6570         private void WriteMessageAttrib(StringBuilder stringBuilder, string elementName, string name, string value)
6571         {
6572             string key = elementName + "_" + name;
6573             // See if the user wants things localized.  
6574             if (resources != null)
6575             {
6576                 // resource fallback: strings in the neutral culture will take precedence over inline strings
6577                 string localizedString = resources.GetString(key, CultureInfo.InvariantCulture);
6578                 if (localizedString != null)
6579                     value = localizedString;
6580             }
6581             if (value == null)
6582                 return;
6583
6584             stringBuilder.Append(" message=\"$(string.").Append(key).Append(")\"");
6585             string prevValue;
6586             if (stringTab.TryGetValue(key, out prevValue) && !prevValue.Equals(value))
6587             {
6588                 ManifestError(Resources.GetResourceString("EventSource_DuplicateStringKey", key), true);
6589                 return;
6590             }
6591
6592             stringTab[key] = value;
6593         }
6594         internal string GetLocalizedMessage(string key, CultureInfo ci, bool etwFormat)
6595         {
6596             string value = null;
6597             if (resources != null)
6598             {
6599                 string localizedString = resources.GetString(key, ci);
6600                 if (localizedString != null)
6601                 {
6602                     value = localizedString;
6603                     if (etwFormat && key.StartsWith("event_", StringComparison.Ordinal))
6604                     {
6605                         var evtName = key.Substring("event_".Length);
6606                         value = TranslateToManifestConvention(value, evtName);
6607                     }
6608                 }
6609             }
6610             if (etwFormat && value == null)
6611                 stringTab.TryGetValue(key, out value);
6612
6613             return value;
6614         }
6615
6616         /// <summary>
6617         /// There's no API to enumerate all languages an assembly is localized into, so instead
6618         /// we enumerate through all the "known" cultures and attempt to load a corresponding satellite 
6619         /// assembly
6620         /// </summary>
6621         /// <param name="resources"></param>
6622         /// <returns></returns>
6623         private static List<CultureInfo> GetSupportedCultures(ResourceManager resources)
6624         {
6625             var cultures = new List<CultureInfo>();
6626
6627             if (!cultures.Contains(CultureInfo.CurrentUICulture))
6628                 cultures.Insert(0, CultureInfo.CurrentUICulture);
6629             return cultures;
6630         }
6631
6632         private static string GetLevelName(EventLevel level)
6633         {
6634             return (((int)level >= 16) ? "" : "win:") + level.ToString();
6635         }
6636
6637 #if FEATURE_MANAGED_ETW_CHANNELS
6638         private string GetChannelName(EventChannel channel, string eventName, string eventMessage)
6639         {
6640             ChannelInfo info = null;
6641             if (channelTab == null || !channelTab.TryGetValue((int)channel, out info))
6642             {
6643                 if (channel < EventChannel.Admin) // || channel > EventChannel.Debug)
6644                     ManifestError(Resources.GetResourceString("EventSource_UndefinedChannel", channel, eventName));
6645
6646                 // allow channels to be auto-defined.  The well known ones get their well known names, and the
6647                 // rest get names Channel<N>.  This allows users to modify the Manifest if they want more advanced features. 
6648                 if (channelTab == null)
6649                     channelTab = new Dictionary<int, ChannelInfo>(4);
6650
6651                 string channelName = channel.ToString();        // For well know channels this is a nice name, otherwise a number 
6652                 if (EventChannel.Debug < channel)
6653                     channelName = "Channel" + channelName;      // Add a 'Channel' prefix for numbers.  
6654
6655                 AddChannel(channelName, (int)channel, GetDefaultChannelAttribute(channel));
6656                 if (!channelTab.TryGetValue((int)channel, out info))
6657                     ManifestError(Resources.GetResourceString("EventSource_UndefinedChannel", channel, eventName));
6658             }
6659             // events that specify admin channels *must* have non-null "Message" attributes
6660             if (resources != null && eventMessage == null)
6661                 eventMessage = resources.GetString("event_" + eventName, CultureInfo.InvariantCulture);
6662             if (info.Attribs.EventChannelType == EventChannelType.Admin && eventMessage == null)
6663                 ManifestError(Resources.GetResourceString("EventSource_EventWithAdminChannelMustHaveMessage", eventName, info.Name));
6664             return info.Name;
6665         }
6666 #endif
6667         private string GetTaskName(EventTask task, string eventName)
6668         {
6669             if (task == EventTask.None)
6670                 return "";
6671
6672             string ret;
6673             if (taskTab == null)
6674                 taskTab = new Dictionary<int, string>();
6675             if (!taskTab.TryGetValue((int)task, out ret))
6676                 ret = taskTab[(int)task] = eventName;
6677             return ret;
6678         }
6679
6680         private string GetOpcodeName(EventOpcode opcode, string eventName)
6681         {
6682             switch (opcode)
6683             {
6684                 case EventOpcode.Info:
6685                     return "win:Info";
6686                 case EventOpcode.Start:
6687                     return "win:Start";
6688                 case EventOpcode.Stop:
6689                     return "win:Stop";
6690                 case EventOpcode.DataCollectionStart:
6691                     return "win:DC_Start";
6692                 case EventOpcode.DataCollectionStop:
6693                     return "win:DC_Stop";
6694                 case EventOpcode.Extension:
6695                     return "win:Extension";
6696                 case EventOpcode.Reply:
6697                     return "win:Reply";
6698                 case EventOpcode.Resume:
6699                     return "win:Resume";
6700                 case EventOpcode.Suspend:
6701                     return "win:Suspend";
6702                 case EventOpcode.Send:
6703                     return "win:Send";
6704                 case EventOpcode.Receive:
6705                     return "win:Receive";
6706             }
6707
6708             string ret;
6709             if (opcodeTab == null || !opcodeTab.TryGetValue((int)opcode, out ret))
6710             {
6711                 ManifestError(Resources.GetResourceString("EventSource_UndefinedOpcode", opcode, eventName), true);
6712                 ret = null;
6713             }
6714             return ret;
6715         }
6716
6717         private string GetKeywords(ulong keywords, string eventName)
6718         {
6719 #if FEATURE_MANAGED_ETW_CHANNELS
6720             // ignore keywords associate with channels
6721             // See ValidPredefinedChannelKeywords def for more. 
6722             keywords &= ~ValidPredefinedChannelKeywords;
6723 #endif
6724
6725             string ret = "";
6726             for (ulong bit = 1; bit != 0; bit <<= 1)
6727             {
6728                 if ((keywords & bit) != 0)
6729                 {
6730                     string keyword = null;
6731                     if ((keywordTab == null || !keywordTab.TryGetValue(bit, out keyword)) &&
6732                         (bit >= (ulong)0x1000000000000))
6733                     {
6734                         // do not report Windows reserved keywords in the manifest (this allows the code
6735                         // to be resilient to potential renaming of these keywords)
6736                         keyword = string.Empty;
6737                     }
6738                     if (keyword == null)
6739                     {
6740                         ManifestError(Resources.GetResourceString("EventSource_UndefinedKeyword", "0x" + bit.ToString("x", CultureInfo.CurrentCulture), eventName), true);
6741                         keyword = string.Empty;
6742                     }
6743                     if (ret.Length != 0 && keyword.Length != 0)
6744                         ret = ret + " ";
6745                     ret = ret + keyword;
6746                 }
6747             }
6748             return ret;
6749         }
6750
6751         private string GetTypeName(Type type)
6752         {
6753             if (type.IsEnum())
6754             {
6755                 FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
6756                 var typeName = GetTypeName(fields[0].FieldType);
6757                 return typeName.Replace("win:Int", "win:UInt"); // ETW requires enums to be unsigned.  
6758             }
6759
6760             return GetTypeNameHelper(type);
6761         }
6762
6763         private static void UpdateStringBuilder(ref StringBuilder stringBuilder, string eventMessage, int startIndex, int count)
6764         {
6765             if (stringBuilder == null)
6766                 stringBuilder = new StringBuilder();
6767             stringBuilder.Append(eventMessage, startIndex, count);
6768         }
6769
6770         private static readonly string[] s_escapes = { "&amp;", "&lt;", "&gt;", "&apos;", "&quot;", "%r", "%n", "%t" };
6771         // Manifest messages use %N conventions for their message substitutions.   Translate from
6772         // .NET conventions.   We can't use RegEx for this (we are in mscorlib), so we do it 'by hand' 
6773         private string TranslateToManifestConvention(string eventMessage, string evtName)
6774         {
6775             StringBuilder stringBuilder = null;        // We lazily create this 
6776             int writtenSoFar = 0;
6777             int chIdx = -1;
6778             for (int i = 0; ;)
6779             {
6780                 if (i >= eventMessage.Length)
6781                 {
6782                     if (stringBuilder == null)
6783                         return eventMessage;
6784                     UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar);
6785                     return stringBuilder.ToString();
6786                 }
6787
6788                 if (eventMessage[i] == '%')
6789                 {
6790                     // handle format message escaping character '%' by escaping it
6791                     UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar);
6792                     stringBuilder.Append("%%");
6793                     i++;
6794                     writtenSoFar = i;
6795                 }
6796                 else if (i < eventMessage.Length - 1 &&
6797                     (eventMessage[i] == '{' && eventMessage[i + 1] == '{' || eventMessage[i] == '}' && eventMessage[i + 1] == '}'))
6798                 {
6799                     // handle C# escaped '{" and '}'
6800                     UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar);
6801                     stringBuilder.Append(eventMessage[i]);
6802                     i++; i++;
6803                     writtenSoFar = i;
6804                 }
6805                 else if (eventMessage[i] == '{')
6806                 {
6807                     int leftBracket = i;
6808                     i++;
6809                     int argNum = 0;
6810                     while (i < eventMessage.Length && Char.IsDigit(eventMessage[i]))
6811                     {
6812                         argNum = argNum * 10 + eventMessage[i] - '0';
6813                         i++;
6814                     }
6815                     if (i < eventMessage.Length && eventMessage[i] == '}')
6816                     {
6817                         i++;
6818                         UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, leftBracket - writtenSoFar);
6819                         int manIndex = TranslateIndexToManifestConvention(argNum, evtName);
6820                         stringBuilder.Append('%').Append(manIndex);
6821                         // An '!' after the insert specifier {n} will be interpreted as a literal.
6822                         // We'll escape it so that mc.exe does not attempt to consider it the 
6823                         // beginning of a format string.
6824                         if (i < eventMessage.Length && eventMessage[i] == '!')
6825                         {
6826                             i++;
6827                             stringBuilder.Append("%!");
6828                         }
6829                         writtenSoFar = i;
6830                     }
6831                     else
6832                     {
6833                         ManifestError(Resources.GetResourceString("EventSource_UnsupportedMessageProperty", evtName, eventMessage));
6834                     }
6835                 }
6836                 else if ((chIdx = "&<>'\"\r\n\t".IndexOf(eventMessage[i])) >= 0)
6837                 {
6838                     UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar);
6839                     i++;
6840                     stringBuilder.Append(s_escapes[chIdx]);
6841                     writtenSoFar = i;
6842                 }
6843                 else
6844                     i++;
6845             }
6846         }
6847
6848         private int TranslateIndexToManifestConvention(int idx, string evtName)
6849         {
6850             List<int> byteArrArgIndices;
6851             if (perEventByteArrayArgIndices.TryGetValue(evtName, out byteArrArgIndices))
6852             {
6853                 foreach (var byArrIdx in byteArrArgIndices)
6854                 {
6855                     if (idx >= byArrIdx)
6856                         ++idx;
6857                     else
6858                         break;
6859                 }
6860             }
6861             return idx + 1;
6862         }
6863
6864 #if FEATURE_MANAGED_ETW_CHANNELS
6865         class ChannelInfo
6866         {
6867             public string Name;
6868             public ulong Keywords;
6869             public EventChannelAttribute Attribs;
6870         }
6871 #endif
6872
6873         Dictionary<int, string> opcodeTab;
6874         Dictionary<int, string> taskTab;
6875 #if FEATURE_MANAGED_ETW_CHANNELS
6876         Dictionary<int, ChannelInfo> channelTab;
6877 #endif
6878         Dictionary<ulong, string> keywordTab;
6879         Dictionary<string, Type> mapsTab;
6880
6881         Dictionary<string, string> stringTab;       // Maps unlocalized strings to localized ones  
6882
6883 #if FEATURE_MANAGED_ETW_CHANNELS
6884         // WCF used EventSource to mimic a existing ETW manifest.   To support this
6885         // in just their case, we allowed them to specify the keywords associated 
6886         // with their channels explicitly.   ValidPredefinedChannelKeywords is 
6887         // this set of channel keywords that we allow to be explicitly set.  You
6888         // can ignore these bits otherwise.  
6889         internal const ulong ValidPredefinedChannelKeywords = 0xF000000000000000;
6890         ulong nextChannelKeywordBit = 0x8000000000000000;   // available Keyword bit to be used for next channel definition, grows down
6891         const int MaxCountChannels = 8; // a manifest can defined at most 8 ETW channels
6892 #endif
6893
6894         StringBuilder sb;               // Holds the provider information. 
6895         StringBuilder events;           // Holds the events. 
6896         StringBuilder templates;
6897
6898 #if FEATURE_MANAGED_ETW_CHANNELS
6899         string providerName;
6900 #endif
6901         ResourceManager resources;      // Look up localized strings here.  
6902         EventManifestOptions flags;
6903         IList<string> errors;           // list of currently encountered errors
6904         Dictionary<string, List<int>> perEventByteArrayArgIndices;  // "event_name" -> List_of_Indices_of_Byte[]_Arg
6905
6906         // State we track between StartEvent and EndEvent.  
6907         string eventName;               // Name of the event currently being processed. 
6908         int numParams;                  // keeps track of the number of args the event has. 
6909         List<int> byteArrArgIndices;    // keeps track of the index of each byte[] argument
6910         #endregion
6911     }
6912
6913     /// <summary>
6914     /// Used to send the m_rawManifest into the event dispatcher as a series of events.  
6915     /// </summary>
6916     internal struct ManifestEnvelope
6917     {
6918         public const int MaxChunkSize = 0xFF00;
6919         public enum ManifestFormats : byte
6920         {
6921             SimpleXmlFormat = 1,          // simply dump the XML manifest as UTF8
6922         }
6923
6924 #if FEATURE_MANAGED_ETW
6925         public ManifestFormats Format;
6926         public byte MajorVersion;
6927         public byte MinorVersion;
6928         public byte Magic;
6929         public ushort TotalChunks;
6930         public ushort ChunkNumber;
6931 #endif
6932     };
6933
6934     #endregion
6935 }
6936