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