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