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