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