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