diff options
Diffstat (limited to 'src')
54 files changed, 1875 insertions, 2397 deletions
diff --git a/src/debug/debug-pal/unix/twowaypipe.cpp b/src/debug/debug-pal/unix/twowaypipe.cpp index 18881616f2..41da7ff2a3 100644 --- a/src/debug/debug-pal/unix/twowaypipe.cpp +++ b/src/debug/debug-pal/unix/twowaypipe.cpp @@ -178,13 +178,13 @@ int TwoWayPipe::Write(const void *data, DWORD dataSize) bool TwoWayPipe::Disconnect() { - if (m_outboundPipe != INVALID_PIPE) + if (m_outboundPipe != INVALID_PIPE && m_outboundPipe != 0) { close(m_outboundPipe); m_outboundPipe = INVALID_PIPE; } - if (m_inboundPipe != INVALID_PIPE) + if (m_inboundPipe != INVALID_PIPE && m_inboundPipe != 0) { close(m_inboundPipe); m_inboundPipe = INVALID_PIPE; diff --git a/src/debug/shared/dbgtransportsession.cpp b/src/debug/shared/dbgtransportsession.cpp index 2b17f6d6d8..01f4acbc66 100644 --- a/src/debug/shared/dbgtransportsession.cpp +++ b/src/debug/shared/dbgtransportsession.cpp @@ -57,6 +57,11 @@ HRESULT DbgTransportSession::Init(DebuggerIPCControlBlock *pDCB, AppDomainEnumer // cleanup necessary. memset(this, 0, sizeof(*this)); + // Because of the above memset the embeded classes/structs need to be reinitialized especially + // the two way pipe; it expects the in/out handles to be -1 instead of 0. + m_pipe = TwoWayPipe(); + m_sStateLock = DbgTransportLock(); + // Initialize all per-session state variables. InitSessionState(); diff --git a/src/gc/gc.cpp b/src/gc/gc.cpp index c91d2a6baf..b329f894ed 100644 --- a/src/gc/gc.cpp +++ b/src/gc/gc.cpp @@ -21674,6 +21674,14 @@ void gc_heap::plan_phase (int condemned_gen_number) (size_t)new_address + ps, ps, (is_plug_padded (plug_start) ? 1 : 0))); #endif //SIMPLE_DPRINTF + +#ifdef SHORT_PLUGS + if (is_plug_padded (plug_start)) + { + dprintf (3, ("%Ix was padded", plug_start)); + dd_padding_size (dd_active_old) += Align (min_obj_size); + } +#endif //SHORT_PLUGS } } } diff --git a/src/gc/gc.h b/src/gc/gc.h index 8c8645e089..94d2d5df2d 100644 --- a/src/gc/gc.h +++ b/src/gc/gc.h @@ -204,6 +204,7 @@ struct ScanContext { Thread* thread_under_crawl; int thread_number; + uintptr_t stack_limit; // Lowest point on the thread stack that the scanning logic is permitted to read BOOL promotion; //TRUE: Promotion, FALSE: Relocation. BOOL concurrent; //TRUE: concurrent scanning #if CHECK_APP_DOMAIN_LEAKS || defined (FEATURE_APPDOMAIN_RESOURCE_MONITORING) || defined (DACCESS_COMPILE) @@ -225,6 +226,7 @@ struct ScanContext thread_under_crawl = 0; thread_number = -1; + stack_limit = 0; promotion = FALSE; concurrent = FALSE; #ifdef GC_PROFILING diff --git a/src/ildasm/dasm.cpp b/src/ildasm/dasm.cpp index 8032af63d5..a220fa86bf 100644 --- a/src/ildasm/dasm.cpp +++ b/src/ildasm/dasm.cpp @@ -3447,7 +3447,7 @@ BOOL DumpMethod(mdToken FuncToken, const char *pszClassName, DWORD dwEntryPointT ULONG ulArgs=0; unsigned retParamIx = 0; unsigned uStringLen = SZSTRING_SIZE; - char szArgPrefix[32]; + char szArgPrefix[MAX_PREFIX_SIZE]; char* szptr = NULL; mdToken tkMVarOwner = g_tkMVarOwner; @@ -3627,7 +3627,7 @@ lDone: ; qbMemberSig.Shrink(0); // Get the argument names, if any - strcpy_s(szArgPrefix,32,(g_fThisIsInstanceMethod ? "A1": "A0")); + strcpy_s(szArgPrefix,MAX_PREFIX_SIZE,(g_fThisIsInstanceMethod ? "A1": "A0")); { PCCOR_SIGNATURE typePtr = pComSig; unsigned ulCallConv = CorSigUncompressData(typePtr); // get the calling convention out of the way @@ -3699,11 +3699,7 @@ lDone: ; sprintf_s(pszArgname[j].name,16,"A_%d",g_fThisIsInstanceMethod ? j+1 : j); } }// end for( along the argnames) -#ifdef _WIN64 - sprintf_s(szArgPrefix,32,"@%I64d0",(size_t)pszArgname); -#else - sprintf_s(szArgPrefix,32,"@%d0",(size_t)pszArgname); -#endif //_WIN64 + sprintf_s(szArgPrefix,MAX_PREFIX_SIZE,"@%Id0",(size_t)pszArgname); } //end if (ulArgs) g_pImport->EnumClose(&hArgEnum); } diff --git a/src/ildasm/dasm.rc b/src/ildasm/dasm.rc index 9de2a73b64..cc45a895b6 100644 --- a/src/ildasm/dasm.rc +++ b/src/ildasm/dasm.rc @@ -297,10 +297,11 @@ BEGIN IDS_USAGE_05 L"Options for GUI or file/console output (EXE and DLL files only):\n" #else IDS_USAGE_03 L" /OUT=<file name> Direct output to file rather than to console.\n" + IDS_USAGE_04 L"" IDS_USAGE_04A L" /HTML Output in HTML format (valid with /OUT option only).\n" IDS_USAGE_04B L" /RTF Output in rich text format (valid with /OUT option only).\n" IDS_USAGE_05 L"Options for file/console output:\n" -#endif +#endif // !FEATURE_PAL #ifdef OWNER_OPTION_ENABLED IDS_USAGE_06 L" /OWNER=<owner name> Set owner name to disassemble a protected PE file.\n" #endif @@ -326,7 +327,11 @@ BEGIN IDS_USAGE_16 L" /NOBAR Suppress disassembly progress bar window pop-up.\n\n" IDS_USAGE_17 L"The following options are valid for file/console output only:\n" IDS_USAGE_18 L"Options for EXE and DLL files:\n" -#endif +#else + IDS_USAGE_16 L"" + IDS_USAGE_17 L"" + IDS_USAGE_18 L"" +#endif // !FEATURE_PAL IDS_USAGE_19 L" /UTF8 Use UTF-8 encoding for output (default - ANSI).\n" IDS_USAGE_20 L" /UNICODE Use UNICODE encoding for output.\n" IDS_USAGE_21 L" /NOIL Suppress IL assembler code output.\n" @@ -344,7 +349,9 @@ BEGIN IDS_USAGE_26 L" /ALL Combination of /HEADER,/BYTES,/STATS,/CLASSLIST,/TOKENS\n\n" #ifndef FEATURE_PAL IDS_USAGE_27 L"Options for EXE,DLL,OBJ and LIB files:\n" -#endif +#else + IDS_USAGE_27 L"" +#endif // !FEATURE_PAL IDS_USAGE_28 L" /METADATA[=<specifier>] Show MetaData, where <specifier> is:\n" IDS_USAGE_29 L" MDHEADER Show MetaData header information and sizes.\n" IDS_USAGE_30 L" HEX Show more things in hex as well as words.\n" @@ -352,7 +359,9 @@ BEGIN IDS_USAGE_32 L" UNREX Show unresolved externals.\n" #ifndef FEATURE_PAL IDS_USAGE_33 L" DEBUG Show debug information in addition to other MetaData.\n" -#endif +#else + IDS_USAGE_33 L"" +#endif // !FEATURE_PAL IDS_USAGE_34 L" SCHEMA Show the MetaData header and schema information.\n" IDS_USAGE_35 L" RAW Show the raw MetaData tables.\n" IDS_USAGE_36 L" HEAPS Show the raw heaps.\n" @@ -360,7 +369,10 @@ BEGIN #ifndef FEATURE_PAL IDS_USAGE_38 L"Options for LIB files only:\n" IDS_USAGE_39 L" /OBJECTFILE=<obj_file_name> Show MetaData of a single object file in library\n" -#endif +#else + IDS_USAGE_38 L"" + IDS_USAGE_39 L"" +#endif // !FEATURE_PAL END STRINGTABLE DISCARDABLE diff --git a/src/ildasm/dis.cpp b/src/ildasm/dis.cpp index 796271b356..48f4586ab9 100644 --- a/src/ildasm/dis.cpp +++ b/src/ildasm/dis.cpp @@ -915,7 +915,7 @@ BOOL Disassemble(IMDInternalImport *pImport, BYTE *ILHeader, void *GUICookie, md LineCodeDescr* pLCD = NULL; ParamDescriptor* pszLVname = NULL; ULONG ulVars=0; - char szVarPrefix[64]; + char szVarPrefix[MAX_PREFIX_SIZE]; // scope handling: DynamicArray<LexScope> daScope; ULONG ulScopes=0; @@ -928,7 +928,7 @@ BOOL Disassemble(IMDInternalImport *pImport, BYTE *ILHeader, void *GUICookie, md ULONG32 ulMethodCol[2]; BOOL fHasRangeInfo = FALSE; - strcpy_s(szVarPrefix,64,"V0"); + strcpy_s(szVarPrefix,MAX_PREFIX_SIZE,"V0"); if(g_pSymReader) { g_pSymReader->GetMethod(FuncToken,&pSymMethod); @@ -1048,11 +1048,7 @@ BOOL Disassemble(IMDInternalImport *pImport, BYTE *ILHeader, void *GUICookie, md LoadScope(pRootScope,&daScope,&ulScopes); qsort(&daScope[0],ulScopes,sizeof(LexScope),cmpLexScope); OpenScope(pRootScope,pszLVname,ulVars); -#ifdef _WIN64 - sprintf_s(szVarPrefix,64,"@%I64d0",(size_t)pszLVname); -#else - sprintf_s(szVarPrefix,64,"@%d0",(size_t)pszLVname); -#endif //_WIN64 + sprintf_s(szVarPrefix,MAX_PREFIX_SIZE,"@%Id0",(size_t)pszLVname); #ifndef SHOW_LEXICAL_SCOPES for(unsigned jjj = 0; jjj < ulScopes; jjj++) diff --git a/src/inc/formattype.cpp b/src/inc/formattype.cpp index 923ff3e9a1..b8960f48c6 100644 --- a/src/inc/formattype.cpp +++ b/src/inc/formattype.cpp @@ -206,14 +206,14 @@ const PCCOR_SIGNATURE PrettyPrintSignature( PCCOR_SIGNATURE typeEnd = typePtr + typeLen; unsigned ixArg= 0; //arg index char argname[1024]; - char label[16]; + char label[MAX_PREFIX_SIZE]; const char* openpar = "("; const char* closepar = ")"; ParamDescriptor* pszArgName = NULL; // ptr to array of names (if provided by debug info) if(inlabel && *inlabel) // check for *inlabel is totally unnecessary, added to pacify the PREFIX { - strcpy_s(label,COUNTOF(label),inlabel); + strcpy_s(label,MAX_PREFIX_SIZE,inlabel); ixArg = label[strlen(label)-1] - '0'; label[strlen(label)-1] = 0; if(label[0] == '@') // it's pointer! diff --git a/src/inc/formattype.h b/src/inc/formattype.h index 739bc89dd4..53ba4a115c 100644 --- a/src/inc/formattype.h +++ b/src/inc/formattype.h @@ -16,6 +16,8 @@ #endif #endif +#define MAX_PREFIX_SIZE 32 + struct ParamDescriptor { char* name; diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp index 3dad01a71b..a932594720 100644 --- a/src/jit/lower.cpp +++ b/src/jit/lower.cpp @@ -3343,9 +3343,7 @@ Lowering::LowerArrElem(GenTree **ppTree, Compiler::fgWalkData* data) GenTreePtr arrObjNode = arrElem->gtArrObj; assert(arrObjNode->IsLocal()); - GenTreePtr nextNode = arrElem->gtNext; - // ??? Can we have a top-level GT_ARR_ELEM ??? - noway_assert(nextNode != nullptr); + GenTreePtr nextNode = arrElem; // We need to evaluate the index expressions up-front if they have side effects. for (unsigned char dim = 0; dim < rank; dim++) @@ -3371,7 +3369,6 @@ Lowering::LowerArrElem(GenTree **ppTree, Compiler::fgWalkData* data) GenTree* prevArrOffs = new(comp, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, 0); comp->fgInsertLinearNodeBefore(prevArrOffs, arrObjNode); - comp->fgSnipInnerNode(arrElem); for (unsigned char dim = 0; dim < rank; dim++) { GenTree* currIndexTree = arrElem->gtArrElem.gtArrInds[dim]; @@ -3450,6 +3447,19 @@ Lowering::LowerArrElem(GenTree **ppTree, Compiler::fgWalkData* data) *ppTree = leaNode; + if (arrElem->gtNext != nullptr) + { + comp->fgSnipInnerNode(arrElem); + } + else + { + // We can have a top-level GT_ARR_ELEM. For example, a function call + // with a parameter of GT_ARR_ELEM can end up being simplified by the + // inliner to single GT_ARR_ELEM node if the function has an empty body. + arrElem->gtPrev->gtNext = nullptr; + curStmt->gtStmt.gtStmtExpr = *ppTree; + } + // Update the costs. comp->gtSetStmtInfo(curStmt); diff --git a/src/mscorlib/corefx/System/Globalization/TextInfo.Unix.cs b/src/mscorlib/corefx/System/Globalization/TextInfo.Unix.cs index a60707cb60..84ecfeab17 100644 --- a/src/mscorlib/corefx/System/Globalization/TextInfo.Unix.cs +++ b/src/mscorlib/corefx/System/Globalization/TextInfo.Unix.cs @@ -88,7 +88,8 @@ namespace System.Globalization private bool NeedsTurkishCasing(string localeName) { Contract.Assert(localeName != null); - return CultureInfo.GetCultureInfo(localeName).CompareInfo.Compare("i", "I", CompareOptions.IgnoreCase) != 0; + + return CultureInfo.GetCultureInfo(localeName).CompareInfo.Compare("\u0131", "I", CompareOptions.IgnoreCase) == 0; } private bool IsInvariant { get { return m_cultureName.Length == 0; } } diff --git a/src/mscorlib/model.xml b/src/mscorlib/model.xml index ecaa8f4c02..659d5be6dc 100644 --- a/src/mscorlib/model.xml +++ b/src/mscorlib/model.xml @@ -9762,10 +9762,6 @@ </Type> <Type Status="ImplRoot" Name="System.Diagnostics.StackFrameHelper" /> - <Type Status="ImplRoot" Name="System.Diagnostics.Tracing.EnumHelper<UnderlyingType>"> - <Member Name="Identity(UnderlyingType)" /> - </Type> - <Type Name="System.Diagnostics.Tracing.EventAttribute"> <Member Name="#ctor(System.Int32)" /> <Member Name="get_EventId" /> diff --git a/src/mscorlib/mscorlib.shared.sources.props b/src/mscorlib/mscorlib.shared.sources.props index 33189a138e..e14bdd6d8d 100644 --- a/src/mscorlib/mscorlib.shared.sources.props +++ b/src/mscorlib/mscorlib.shared.sources.props @@ -990,6 +990,7 @@ <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\EventDescriptor.cs" /> <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\EventProvider.cs" /> <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\EventSource.cs" /> + <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\EventSource_CoreCLR.cs" /> <DiagnosticsSources Condition="'$(FeatureXplatEventSource)' == 'true'" Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\XplatEventLogger.cs" /> <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\EventSourceException.cs" /> <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\FrameworkEventSource.cs" /> @@ -1012,7 +1013,7 @@ <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\TraceLogging\FieldMetadata.cs" /> <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\TraceLogging\InvokeTypeInfo.cs" /> <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\TraceLogging\NameInfo.cs" /> - <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\TraceLogging\PropertyAccessor.cs" /> + <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\TraceLogging\PropertyValue.cs" /> <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\TraceLogging\PropertyAnalysis.cs" /> <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\TraceLogging\SimpleEventTypes.cs" /> <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\TraceLogging\SimpleTypeInfos.cs" /> @@ -1024,7 +1025,6 @@ <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\TraceLogging\TraceLoggingEventTypes.cs" /> <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\TraceLogging\TraceLoggingMetadataCollector.cs" /> <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\TraceLogging\TraceLoggingTypeInfo.cs" /> - <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\TraceLogging\TraceLoggingTypeInfo_T.cs" /> <DiagnosticsSources Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\TraceLogging\TypeAnalysis.cs" /> </ItemGroup> <ItemGroup> diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/ActivityTracker.cs b/src/mscorlib/src/System/Diagnostics/Eventing/ActivityTracker.cs index 54f7b47d28..dcd3f70376 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/ActivityTracker.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/ActivityTracker.cs @@ -12,7 +12,7 @@ using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract; #if ES_BUILD_STANDALONE namespace Microsoft.Diagnostics.Tracing -#else +#else using System.Threading.Tasks; namespace System.Diagnostics.Tracing #endif @@ -47,7 +47,7 @@ namespace System.Diagnostics.Tracing /// Called on work item begins. The activity name = providerName + activityName without 'Start' suffix. /// It updates CurrentActivityId to track. /// - /// It returns true if the Start should be logged, otherwise (if it is illegal recurision) it return false. + /// It returns true if the Start should be logged, otherwise (if it is illegal recursion) it return false. /// /// The start event should use as its activity ID the CurrentActivityId AFTER calling this routine and its /// RelatedActivityID the CurrentActivityId BEFORE calling this routine (the creator). @@ -64,12 +64,10 @@ namespace System.Diagnostics.Tracing if (m_checkedForEnable) return; m_checkedForEnable = true; -#if ES_BUILD_STANDALONE - Enable(); // Enable it unconditionally. -#else - if (System.Threading.Tasks.TplEtwProvider.Log.IsEnabled(EventLevel.Informational, System.Threading.Tasks.TplEtwProvider.Keywords.TasksFlowActivityIds)) - Enable(); -#endif + if (TplEtwProvider.Log.IsEnabled(EventLevel.Informational, TplEtwProvider.Keywords.TasksFlowActivityIds)) + Enable(); + if (m_current == null) + return; } @@ -124,7 +122,7 @@ namespace System.Diagnostics.Tracing // Remember the current ID so we can log it activityId = newActivity.ActivityId; - + if (etwLog.Debug) { etwLog.DebugFacilityMessage("OnStartRetActivityState", ActivityInfo.LiveActivities(newActivity)); @@ -144,7 +142,7 @@ namespace System.Diagnostics.Tracing return; var fullActivityName = NormalizeActivityName(providerName, activityName, task); - + var etwLog = TplEtwProvider.Log; if (etwLog.Debug) { @@ -215,7 +213,7 @@ namespace System.Diagnostics.Tracing } return; } - // We failed to stop it. We must have hit a race condition to stop it. Just start over and try again. + // We failed to stop it. We must have hit a race to stop it. Just start over and try again. } } @@ -227,7 +225,17 @@ namespace System.Diagnostics.Tracing { if (m_current == null) { - m_current = new AsyncLocal<ActivityInfo>(ActivityChanging); + // Catch the not Implemented + try + { + m_current = new AsyncLocal<ActivityInfo>(ActivityChanging); + } + catch (NotImplementedException) { +#if (!ES_BUILD_PCL && ! PROJECTN) + // send message to debugger without delay + System.Diagnostics.Debugger.Log(0, null, "Activity Enabled() called but AsyncLocals Not Supported (pre V4.6). Ignoring Enable"); +#endif + } } } @@ -375,10 +383,10 @@ namespace System.Diagnostics.Tracing { // TODO FIXME - differentiate between AD inside PCL int appDomainID = 0; -#if !ES_BUILD_STANDALONE +#if (!ES_BUILD_STANDALONE && !PROJECTN) appDomainID = System.Threading.Thread.GetDomainID(); #endif - // We start with the appdomain number to make this unique among appdomains. + // We start with the appdomain number to make this unique among appdomains. activityPathGuidOffsetStart = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint)appDomainID); } @@ -608,7 +616,7 @@ namespace System.Diagnostics.Tracing #endregion } -#if ES_BUILD_STANDALONE +#if ES_BUILD_STANDALONE || PROJECTN /******************************** SUPPORT *****************************/ /// <summary> /// This is supplied by the framework. It is has the semantics that the value is copied to any new Tasks that is created @@ -617,12 +625,17 @@ namespace System.Diagnostics.Tracing /// only get your thread local copy which means that you never have races. /// </summary> /// - [EventSource(Name="Microsoft.Tasks.Nuget")] +#if ES_BUILD_STANDALONE + [EventSource(Name = "Microsoft.Tasks.Nuget")] +#else + [EventSource(Name = "System.Diagnostics.Tracing.TplEtwProvider")] +#endif internal class TplEtwProvider : EventSource { public class Keywords { - public const EventKeywords Debug = (EventKeywords) 1; + public const EventKeywords TasksFlowActivityIds = (EventKeywords)0x80; + public const EventKeywords Debug = (EventKeywords)0x20000; } public static TplEtwProvider Log = new TplEtwProvider(); @@ -635,13 +648,9 @@ namespace System.Diagnostics.Tracing #endif #if ES_BUILD_AGAINST_DOTNET_V35 || ES_BUILD_PCL || NO_ASYNC_LOCAL - + // In these cases we don't have any Async local support. Do nothing. internal sealed class AsyncLocalValueChangedArgs<T> { - public AsyncLocalValueChangedArgs() - { - } - public T PreviousValue { get { return default(T); } } public T CurrentValue { get { return default(T); } } @@ -649,26 +658,13 @@ namespace System.Diagnostics.Tracing internal sealed class AsyncLocal<T> { - public AsyncLocal() - { - } - - public AsyncLocal(Action<AsyncLocalValueChangedArgs<T>> valueChangedHandler) - { - + public AsyncLocal(Action<AsyncLocalValueChangedArgs<T>> valueChangedHandler) { + throw new NotImplementedException("AsyncLocal only available on V4.6 and above"); } - public T Value { - get - { - object obj = null; // TODO FIX - return (obj == null) ? default(T) : (T)obj; - } - set - { - // TODO FIX - } + get { return default(T); } + set { } } } #endif diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventCounter.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventCounter.cs new file mode 100644 index 0000000000..cad47eeb5b --- /dev/null +++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventCounter.cs @@ -0,0 +1,432 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +#if ES_BUILD_PCL + using System.Threading.Tasks; +#endif + +#if ES_BUILD_STANDALONE +namespace Microsoft.Diagnostics.Tracing +#else +namespace System.Diagnostics.Tracing +#endif +{ + /// <summary> + /// Provides the ability to collect statistics through EventSource + /// </summary> + public class EventCounter + { + /// <summary> + /// Initializes a new instance of the <see cref="EventCounter"/> class. + /// </summary> + /// <param name="name">The name.</param> + /// <param name="eventSource">The event source.</param> + public EventCounter(string name, EventSource eventSource) + { + if (name == null) + { + throw new ArgumentNullException("name"); + } + + if (eventSource == null) + { + throw new ArgumentNullException("eventSource"); + } + + InitializeBuffer(); + _name = name; + EventCounterGroup.AddEventCounter(eventSource, this); + } + + /// <summary> + /// Writes the metric. + /// </summary> + /// <param name="value">The value.</param> + public void WriteMetric(float value) + { + Enqueue(value); + } + + #region private implementation + + private readonly string _name; + + #region Buffer Management + + // Values buffering + private const int BufferedSize = 10; + private const float UnusedBufferSlotValue = float.NegativeInfinity; + private const int UnsetIndex = -1; + private volatile float[] _bufferedValues; + private volatile int _bufferedValuesIndex; + + private void InitializeBuffer() + { + _bufferedValues = new float[BufferedSize]; + for (int i = 0; i < _bufferedValues.Length; i++) + { + _bufferedValues[i] = UnusedBufferSlotValue; + } + } + + private void Enqueue(float value) + { + // It is possible that two threads read the same bufferedValuesIndex, but only one will be able to write the slot, so that is okay. + int i = _bufferedValuesIndex; + while (true) + { + float result = Interlocked.CompareExchange(ref _bufferedValues[i], value, UnusedBufferSlotValue); + i++; + if (_bufferedValues.Length <= i) + { + // It is possible that two threads both think the buffer is full, but only one get to actually flush it, the other + // will eventually enter this code path and potentially calling Flushing on a buffer that is not full, and that's okay too. + lock (_bufferedValues) + { + Flush(); + } + i = 0; + } + + if (result == UnusedBufferSlotValue) + { + // CompareExchange succeeded + _bufferedValuesIndex = i; + return; + } + } + } + + private void Flush() + { + for (int i = 0; i < _bufferedValues.Length; i++) + { + var value = Interlocked.Exchange(ref _bufferedValues[i], UnusedBufferSlotValue); + if (value != UnusedBufferSlotValue) + { + OnMetricWritten(value); + } + } + + _bufferedValuesIndex = 0; + } + + #endregion // Buffer Management + + #region Statistics Calculation + + // Statistics + private int _count; + private float _sum; + private float _sumSquared; + private float _min; + private float _max; + + private void OnMetricWritten(float value) + { + _sum += value; + _sumSquared += value * value; + if (_count == 0 || value > _max) + { + _max = value; + } + + if (_count == 0 || value < _min) + { + _min = value; + } + + _count++; + } + + internal EventCounterPayload GetEventCounterPayload() + { + lock (_bufferedValues) + { + Flush(); + EventCounterPayload result = new EventCounterPayload(); + result.Name = _name; + result.Count = _count; + result.Mean = _sum / _count; + result.StandardDerivation = (float)Math.Sqrt(_sumSquared / _count - _sum * _sum / _count / _count); + result.Min = _min; + result.Max = _max; + ResetStatistics(); + return result; + } + } + + private void ResetStatistics() + { + _count = 0; + _sum = 0; + _sumSquared = 0; + _min = 0; + _max = 0; + } + + #endregion // Statistics Calculation + + #endregion // private implementation + } + + #region internal supporting classes + + [EventData] + internal class EventCounterPayload : IEnumerable<KeyValuePair<string, object>> + { + public string Name { get; set; } + + public float Mean { get; set; } + + public float StandardDerivation { get; set; } + + public int Count { get; set; } + + public float Min { get; set; } + + public float Max { get; set; } + + public float IntervalSec { get; internal set; } + + #region Implementation of the IEnumerable interface + + public IEnumerator<KeyValuePair<string, object>> GetEnumerator() + { + return ForEnumeration.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ForEnumeration.GetEnumerator(); + } + + private IEnumerable<KeyValuePair<string, object>> ForEnumeration + { + get + { + yield return new KeyValuePair<string, object>("Name", Name); + yield return new KeyValuePair<string, object>("Mean", Mean); + yield return new KeyValuePair<string, object>("StandardDerivation", StandardDerivation); + yield return new KeyValuePair<string, object>("Count", Count); + yield return new KeyValuePair<string, object>("Min", Min); + yield return new KeyValuePair<string, object>("Max", Max); + } + } + + #endregion // Implementation of the IEnumerable interface + } + + internal class EventCounterGroup : IDisposable + { + private readonly EventSource _eventSource; + private readonly int _eventSourceIndex; + private readonly List<EventCounter> _eventCounters; + + internal EventCounterGroup(EventSource eventSource, int eventSourceIndex) + { + _eventSource = eventSource; + _eventSourceIndex = eventSourceIndex; + _eventCounters = new List<EventCounter>(); + RegisterCommandCallback(); + } + + private void Add(EventCounter eventCounter) + { + _eventCounters.Add(eventCounter); + } + + #region EventSource Command Processing + + private void RegisterCommandCallback() + { + _eventSource.EventCommandExecuted += OnEventSourceCommand; + } + + private void OnEventSourceCommand(object sender, EventCommandEventArgs e) + { + if (e.Command == EventCommand.Enable || e.Command == EventCommand.Update) + { + string valueStr; + float value; + if (e.Arguments.TryGetValue("EventCounterIntervalSec", out valueStr) && float.TryParse(valueStr, out value)) + { + EnableTimer(value); + } + } + } + + #endregion // EventSource Command Processing + + #region Global EventCounterGroup Array management + + private static EventCounterGroup[] s_eventCounterGroups; + + internal static void AddEventCounter(EventSource eventSource, EventCounter eventCounter) + { + int eventSourceIndex = EventListener.EventSourceIndex(eventSource); + + EventCounterGroup.EnsureEventSourceIndexAvailable(eventSourceIndex); + EventCounterGroup eventCounterGroup = GetEventCounterGroup(eventSource); + eventCounterGroup.Add(eventCounter); + } + + private static void EnsureEventSourceIndexAvailable(int eventSourceIndex) + { + if (EventCounterGroup.s_eventCounterGroups == null) + { + EventCounterGroup.s_eventCounterGroups = new EventCounterGroup[eventSourceIndex + 1]; + } + else if (eventSourceIndex >= EventCounterGroup.s_eventCounterGroups.Length) + { + EventCounterGroup[] newEventCounterGroups = new EventCounterGroup[eventSourceIndex + 1]; + Array.Copy(EventCounterGroup.s_eventCounterGroups, newEventCounterGroups, EventCounterGroup.s_eventCounterGroups.Length); + EventCounterGroup.s_eventCounterGroups = newEventCounterGroups; + } + } + + private static EventCounterGroup GetEventCounterGroup(EventSource eventSource) + { + int eventSourceIndex = EventListener.EventSourceIndex(eventSource); + EventCounterGroup result = EventCounterGroup.s_eventCounterGroups[eventSourceIndex]; + if (result == null) + { + result = new EventCounterGroup(eventSource, eventSourceIndex); + EventCounterGroup.s_eventCounterGroups[eventSourceIndex] = result; + } + + return result; + } + + #endregion // Global EventCounterGroup Array management + + #region Timer Processing + + private DateTime _timeStampSinceCollectionStarted; + private int _pollingIntervalInMilliseconds; + private Timer _pollingTimer; + + private void EnableTimer(float pollingIntervalInSeconds) + { + if (pollingIntervalInSeconds == 0) + { + if (_pollingTimer != null) + { + _pollingTimer.Dispose(); + _pollingTimer = null; + } + + _pollingIntervalInMilliseconds = 0; + } + else if (_pollingIntervalInMilliseconds == 0 || pollingIntervalInSeconds < _pollingIntervalInMilliseconds) + { + _pollingIntervalInMilliseconds = (int)(pollingIntervalInSeconds * 1000); + if (_pollingTimer != null) + { + _pollingTimer.Dispose(); + _pollingTimer = null; + } + + _timeStampSinceCollectionStarted = DateTime.Now; + _pollingTimer = new Timer(OnTimer, null, _pollingIntervalInMilliseconds, _pollingIntervalInMilliseconds); + } + } + + private void OnTimer(object state) + { + if (_eventSource.IsEnabled()) + { + DateTime now = DateTime.Now; + TimeSpan elapsed = now - _timeStampSinceCollectionStarted; + lock (_pollingTimer) + { + foreach (var eventCounter in _eventCounters) + { + EventCounterPayload payload = eventCounter.GetEventCounterPayload(); + payload.IntervalSec = (float)elapsed.TotalSeconds; + _eventSource.Write("EventCounters", new EventSourceOptions() { Level = EventLevel.LogAlways }, new { Payload = payload }); + } + + + _timeStampSinceCollectionStarted = now; + } + } + else + { + _pollingTimer.Dispose(); + _pollingTimer = null; + EventCounterGroup.s_eventCounterGroups[_eventSourceIndex] = null; + } + } + + #region PCL timer hack + +#if ES_BUILD_PCL + internal delegate void TimerCallback(object state); + + internal sealed class Timer : CancellationTokenSource, IDisposable + { + private int _period; + private TimerCallback _callback; + private object _state; + + internal Timer(TimerCallback callback, object state, int dueTime, int period) + { + _callback = callback; + _state = state; + _period = period; + Schedule(dueTime); + } + + private void Schedule(int dueTime) + { + Task.Delay(dueTime, Token).ContinueWith(OnTimer, null, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default); + } + + private void OnTimer(Task t, object s) + { + Schedule(_period); + _callback(_state); + } + + public new void Dispose() { base.Cancel(); } + } +#endif + #endregion // PCL timer hack + + #endregion // Timer Processing + + #region Implementation of the IDisposable interface + + private bool _disposed = false; + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + if (disposing) + { + if (_pollingTimer != null) + { + _pollingTimer.Dispose(); + _pollingTimer = null; + } + } + + _disposed = true; + } + + #endregion // Implementation of the IDisposable interface + } + + #endregion // internal supporting classes +} diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventDescriptor.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventDescriptor.cs index 643bc88623..7df8150e2e 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/EventDescriptor.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventDescriptor.cs @@ -72,12 +72,12 @@ namespace System.Diagnostics.Tracing { if (id < 0) { - throw new ArgumentOutOfRangeException("id", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException("id", Resources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } if (id > ushort.MaxValue) { - throw new ArgumentOutOfRangeException("id", Environment.GetResourceString("ArgumentOutOfRange_NeedValidId", 1, ushort.MaxValue)); + throw new ArgumentOutOfRangeException("id", Resources.GetResourceString("ArgumentOutOfRange_NeedValidId", 1, ushort.MaxValue)); } m_traceloggingId = 0; @@ -90,19 +90,21 @@ namespace System.Diagnostics.Tracing if (task < 0) { - throw new ArgumentOutOfRangeException("task", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException("task", Resources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } if (task > ushort.MaxValue) { - throw new ArgumentOutOfRangeException("task", Environment.GetResourceString("ArgumentOutOfRange_NeedValidId", 1, ushort.MaxValue)); + throw new ArgumentOutOfRangeException("task", Resources.GetResourceString("ArgumentOutOfRange_NeedValidId", 1, ushort.MaxValue)); } m_task = (ushort)task; } - public int EventId { - get { + public int EventId + { + get + { return m_id; } } @@ -159,7 +161,7 @@ namespace System.Diagnostics.Tracing public override int GetHashCode() { - return m_id ^ m_version ^ m_channel ^ m_level ^ m_opcode ^ m_task ^ (int)m_keywords; + return m_id ^ m_version ^ m_channel ^ m_level ^ m_opcode ^ m_task ^ (int)m_keywords; } public bool Equals(EventDescriptor other) @@ -185,6 +187,6 @@ namespace System.Diagnostics.Tracing public static bool operator !=(EventDescriptor event1, EventDescriptor event2) { return !event1.Equals(event2); - } + } } } diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventProvider.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventProvider.cs index cd5b35ed06..4ffeed3099 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/EventProvider.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventProvider.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.Win32; + using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -18,6 +19,12 @@ using Contract = System.Diagnostics.Contracts.Contract; using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract; #endif +#if ES_BUILD_STANDALONE +using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment; +using EventDescriptor = Microsoft.Diagnostics.Tracing.EventDescriptor; +#endif + + #if ES_BUILD_AGAINST_DOTNET_V35 using Microsoft.Internal; // for Tuple (can't define alias for open generic types so we "use" the whole namespace) #endif @@ -44,7 +51,7 @@ namespace System.Diagnostics.Tracing /// controller callback) /// </summary> [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] - internal class EventProvider : IDisposable + internal partial class EventProvider : IDisposable { // This is the windows EVENT_DATA_DESCRIPTOR structure. We expose it because this is what // subclasses of EventProvider use when creating efficient (but unsafe) version of @@ -80,7 +87,9 @@ namespace System.Diagnostics.Tracing private byte m_level; // Tracing Level private long m_anyKeywordMask; // Trace Enable Flags private long m_allKeywordMask; // Match all keyword +#if ES_SESSION_INFO || FEATURE_ACTIVITYSAMPLING private List<SessionInfo> m_liveSessions; // current live sessions (Tuple<sessionIdBit, etwSessionId>) +#endif private bool m_enabled; // Enabled flag from Trace callback private Guid m_providerId; // Control Guid internal bool m_disposed; // when true provider has unregistered @@ -104,12 +113,12 @@ namespace System.Diagnostics.Tracing EventTooBig = 2, NullInput = 3, TooManyArgs = 4, - Other = 5, + Other = 5, }; // Because callbacks happen on registration, and we need the callbacks for those setup // we can't call Register in the constructor. - // + // // Note that EventProvider should ONLY be used by EventSource. In particular because // it registers a callback from native code you MUST dispose it BEFORE shutdown, otherwise // you may get native callbacks during shutdown when we have destroyed the delegate. @@ -135,40 +144,13 @@ namespace System.Diagnostics.Tracing uint status; m_etwCallback = new UnsafeNativeMethods.ManifestEtw.EtwEnableCallback(EtwEnableCallBack); - status = EventRegister(ref m_providerId, m_etwCallback); + status = EventRegister(ref m_providerId, m_etwCallback); if (status != 0) { throw new ArgumentException(Win32Native.GetMessage(unchecked((int)status))); } } - [System.Security.SecurityCritical] - internal unsafe int SetInformation( - UnsafeNativeMethods.ManifestEtw.EVENT_INFO_CLASS eventInfoClass, - void* data, - int dataSize) - { - int status = UnsafeNativeMethods.ManifestEtw.ERROR_NOT_SUPPORTED; - - if (!m_setInformationMissing) - { - try - { - status = UnsafeNativeMethods.ManifestEtw.EventSetInformation( - m_regHandle, - eventInfoClass, - data, - dataSize); - } - catch (TypeLoadException) - { - m_setInformationMissing = true; - } - } - - return status; - } - // // implement Dispose Pattern to early deregister from ETW insted of waiting for // the finalizer to call deregistration. @@ -249,20 +231,16 @@ namespace System.Diagnostics.Tracing m_regHandle = 0; } } - - // <SecurityKernel Critical="True" Ring="0"> - // <UsesUnsafeCode Name="Parameter filterData of type: Void*" /> - // <UsesUnsafeCode Name="Parameter callbackContext of type: Void*" /> - // </SecurityKernel> + [System.Security.SecurityCritical] unsafe void EtwEnableCallBack( - [In] ref System.Guid sourceId, - [In] int controlCode, - [In] byte setLevel, - [In] long anyKeyword, - [In] long allKeyword, - [In] UnsafeNativeMethods.ManifestEtw.EVENT_FILTER_DESCRIPTOR* filterData, - [In] void* callbackContext + ref System.Guid sourceId, + int controlCode, + byte setLevel, + long anyKeyword, + long allKeyword, + UnsafeNativeMethods.ManifestEtw.EVENT_FILTER_DESCRIPTOR* filterData, + void* callbackContext ) { // This is an optional callback API. We will therefore ignore any failures that happen as a @@ -273,6 +251,7 @@ namespace System.Diagnostics.Tracing ControllerCommand command = ControllerCommand.Update; IDictionary<string, string> args = null; bool skipFinalOnControllerCommand = false; + if (controlCode == UnsafeNativeMethods.ManifestEtw.EVENT_CONTROL_CODE_ENABLE_PROVIDER) { m_enabled = true; @@ -285,7 +264,7 @@ namespace System.Diagnostics.Tracing // today we use FEATURE_ACTIVITYSAMPLING to determine if this code is there or not. // However we put it in the #if so that we don't lose the fact that this feature // switch is at least partially independent of FEATURE_ACTIVITYSAMPLING - +#if ES_SESSION_INFO || FEATURE_ACTIVITYSAMPLING List<Tuple<SessionInfo, bool>> sessionsChanged = GetSessions(); foreach (var session in sessionsChanged) { @@ -326,6 +305,7 @@ namespace System.Diagnostics.Tracing // execute OnControllerCommand once for every session that has changed. OnControllerCommand(command, args, (bEnabling ? sessionChanged : -sessionChanged), etwSessionId); } +#endif } else if (controlCode == UnsafeNativeMethods.ManifestEtw.EVENT_CONTROL_CODE_DISABLE_PROVIDER) { @@ -333,7 +313,9 @@ namespace System.Diagnostics.Tracing m_level = 0; m_anyKeywordMask = 0; m_allKeywordMask = 0; +#if ES_SESSION_INFO || FEATURE_ACTIVITYSAMPLING m_liveSessions = null; +#endif } else if (controlCode == UnsafeNativeMethods.ManifestEtw.EVENT_CONTROL_CODE_CAPTURE_STATE) { @@ -365,6 +347,7 @@ namespace System.Diagnostics.Tracing return idx; } +#if ES_SESSION_INFO || FEATURE_ACTIVITYSAMPLING /// <summary> /// Determines the ETW sessions that have been added and/or removed to the set of /// sessions interested in the current provider. It does so by (1) enumerating over all @@ -563,6 +546,7 @@ namespace System.Diagnostics.Tracing return -1; } +#endif /// <summary> /// Gets any data to be passed from the controller to the provider. It starts with what is passed @@ -573,14 +557,15 @@ namespace System.Diagnostics.Tracing /// starts, and the command being issued associated with that data. /// </summary> [System.Security.SecurityCritical] - private unsafe bool GetDataFromController(int etwSessionId, - UnsafeNativeMethods.ManifestEtw.EVENT_FILTER_DESCRIPTOR* filterData, out ControllerCommand command, out byte[] data, out int dataStart) + private unsafe bool GetDataFromController(int etwSessionId, + UnsafeNativeMethods.ManifestEtw.EVENT_FILTER_DESCRIPTOR* filterData, + out ControllerCommand command, out byte[] data, out int dataStart) { data = null; dataStart = 0; if (filterData == null) { -#if !ES_BUILD_PCL && !FEATURE_PAL +#if (!ES_BUILD_PCL && !PROJECTN && !FEATURE_PAL) string regKey = @"\Microsoft\Windows\CurrentVersion\Winevt\Publishers\{" + m_providerId + "}"; if (System.Runtime.InteropServices.Marshal.SizeOf(typeof(IntPtr)) == 8) regKey = @"HKEY_LOCAL_MACHINE\Software" + @"\Wow6432Node" + regKey; @@ -729,7 +714,7 @@ namespace System.Diagnostics.Tracing --*/ { - Again: + Again: dataDescriptor->Reserved = 0; string sRet = data as string; @@ -1042,7 +1027,7 @@ namespace System.Diagnostics.Tracing dataRefObj.Add(null); ++refObjIndex; } - + // // now fix any string arguments and set the pointer on the data descriptor // @@ -1162,7 +1147,7 @@ namespace System.Diagnostics.Tracing (EventOpcode)eventDescriptor.Opcode == EventOpcode.Start || (EventOpcode)eventDescriptor.Opcode == EventOpcode.Stop); } - + int status = UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, activityID, childActivityID, dataCount, (EventData*)data); if (status != 0) @@ -1182,9 +1167,7 @@ namespace System.Diagnostics.Tracing int dataCount, IntPtr data) { - int status; - - status = UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper( + int status = UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper( m_regHandle, ref eventDescriptor, activityID, @@ -1200,7 +1183,6 @@ namespace System.Diagnostics.Tracing return true; } - // These are look-alikes to the Manifest based ETW OS APIs that have been shimmed to work // either with Manifest ETW or Classic ETW (if Manifest based ETW is not available). [SecurityCritical] @@ -1210,7 +1192,7 @@ namespace System.Diagnostics.Tracing m_etwCallback = enableCallback; return UnsafeNativeMethods.ManifestEtw.EventRegister(ref providerId, enableCallback, null, ref m_regHandle); } - + [SecurityCritical] private uint EventUnregister() { diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventSource.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventSource.cs index f6fe526ea5..54bdc41715 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/EventSource.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventSource.cs @@ -187,16 +187,15 @@ using System.Reflection; using System.Resources; using System.Security; using System.Security.Permissions; + using System.Text; using System.Threading; using Microsoft.Win32; #if ES_BUILD_STANDALONE -using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment; using EventDescriptor = Microsoft.Diagnostics.Tracing.EventDescriptor; #else using System.Threading.Tasks; -using EventDescriptor = System.Diagnostics.Tracing.EventDescriptor; #endif using Microsoft.Reflection; @@ -428,8 +427,9 @@ namespace System.Diagnostics.Tracing } if (name == null) - throw new ArgumentException(Environment.GetResourceString("Argument_InvalidTypeName"), "eventSourceType"); - + { + throw new ArgumentException(Resources.GetResourceString("Argument_InvalidTypeName"), "eventSourceType"); + } return GenerateGuidFromName(name.ToUpperInvariant()); // Make it case insensitive. } /// <summary> @@ -514,115 +514,11 @@ namespace System.Diagnostics.Tracing // User-defined EventCommands should not conflict with the reserved commands. if ((int)command <= (int)EventCommand.Update && (int)command != (int)EventCommand.SendManifest) - throw new ArgumentException(Environment.GetResourceString("EventSource_InvalidCommand"), "command"); - - eventSource.SendCommand(null, 0, 0, command, true, EventLevel.LogAlways, EventKeywords.None, commandArguments); - } - - // ActivityID support (see also WriteEventWithRelatedActivityIdCore) - /// <summary> - /// When a thread starts work that is on behalf of 'something else' (typically another - /// thread or network request) it should mark the thread as working on that other work. - /// This API marks the current thread as working on activity 'activityID'. This API - /// should be used when the caller knows the thread's current activity (the one being - /// overwritten) has completed. Otherwise, callers should prefer the overload that - /// return the oldActivityThatWillContinue (below). - /// - /// All events created with the EventSource on this thread are also tagged with the - /// activity ID of the thread. - /// - /// It is common, and good practice after setting the thread to an activity to log an event - /// with a 'start' opcode to indicate that precise time/thread where the new activity - /// started. - /// </summary> - /// <param name="activityId">A Guid that represents the new activity with which to mark - /// the current thread</param> - [System.Security.SecuritySafeCritical] - public static void SetCurrentThreadActivityId(Guid activityId) - { -#if FEATURE_MANAGED_ETW -#if FEATURE_ACTIVITYSAMPLING - Guid newId = activityId; -#endif // FEATURE_ACTIVITYSAMPLING - // We ignore errors to keep with the convention that EventSources do not throw errors. - // Note we can't access m_throwOnWrites because this is a static method. - if (UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( - UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID, - ref activityId) == 0) { -#if FEATURE_ACTIVITYSAMPLING - var activityDying = s_activityDying; - if (activityDying != null && newId != activityId) - { - if (activityId == Guid.Empty) - { - activityId = FallbackActivityId; - } - // OutputDebugString(string.Format("Activity dying: {0} -> {1}", activityId, newId)); - activityDying(activityId); // This is actually the OLD activity ID. - } -#endif // FEATURE_ACTIVITYSAMPLING + throw new ArgumentException(Resources.GetResourceString("EventSource_InvalidCommand"), "command"); } -#endif // FEATURE_MANAGED_ETW - if (TplEtwProvider.Log != null) - TplEtwProvider.Log.SetActivityId(activityId); - } - - /// <summary> - /// When a thread starts work that is on behalf of 'something else' (typically another - /// thread or network request) it should mark the thread as working on that other work. - /// This API marks the current thread as working on activity 'activityID'. It returns - /// whatever activity the thread was previously marked with. There is a convention that - /// callers can assume that callees restore this activity mark before the callee returns. - /// To encourage this this API returns the old activity, so that it can be restored later. - /// - /// All events created with the EventSource on this thread are also tagged with the - /// activity ID of the thread. - /// - /// It is common, and good practice after setting the thread to an activity to log an event - /// with a 'start' opcode to indicate that precise time/thread where the new activity - /// started. - /// </summary> - /// <param name="activityId">A Guid that represents the new activity with which to mark - /// the current thread</param> - /// <param name="oldActivityThatWillContinue">The Guid that represents the current activity - /// which will continue at some point in the future, on the current thread</param> - [System.Security.SecuritySafeCritical] - public static void SetCurrentThreadActivityId(Guid activityId, out Guid oldActivityThatWillContinue) - { - oldActivityThatWillContinue = activityId; -#if FEATURE_MANAGED_ETW - // We ignore errors to keep with the convention that EventSources do not throw errors. - // Note we can't access m_throwOnWrites because this is a static method. - UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( - UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID, - ref oldActivityThatWillContinue); -#endif // FEATURE_MANAGED_ETW - - // We don't call the activityDying callback here because the caller has declared that - // it is not dying. - if (TplEtwProvider.Log != null) - TplEtwProvider.Log.SetActivityId(activityId); - } - /// <summary> - /// Retrieves the ETW activity ID associated with the current thread. - /// </summary> - public static Guid CurrentThreadActivityId - { - [System.Security.SecuritySafeCritical] - get - { - // We ignore errors to keep with the convention that EventSources do not throw - // errors. Note we can't access m_throwOnWrites because this is a static method. - Guid retVal = new Guid(); -#if FEATURE_MANAGED_ETW - UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( - UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_ID, - ref retVal); -#endif // FEATURE_MANAGED_ETW - return retVal; - } + eventSource.SendCommand(null, 0, 0, command, true, EventLevel.LogAlways, EventKeywords.None, commandArguments); } #if !ES_BUILD_STANDALONE @@ -650,9 +546,11 @@ namespace System.Diagnostics.Tracing get { #pragma warning disable 612, 618 + int threadID = AppDomain.GetCurrentThreadId(); + // Managed thread IDs are more aggressively re-used than native thread IDs, // so we'll use the latter... - return new Guid(unchecked((uint)AppDomain.GetCurrentThreadId()), + return new Guid(unchecked((uint)threadID), unchecked((ushort)s_currentPid), unchecked((ushort)(s_currentPid >> 16)), 0x94, 0x1b, 0x87, 0xd5, 0xa6, 0x5c, 0x36, 0x64); #pragma warning restore 612, 618 @@ -696,7 +594,10 @@ namespace System.Diagnostics.Tracing /// <summary> /// Displays the name and GUID for the eventSource for debugging purposes. /// </summary> - public override string ToString() { return Environment.GetResourceString("EventSource_ToString", Name, Guid); } + public override string ToString() + { + return Resources.GetResourceString("EventSource_ToString", Name, Guid); + } /// <summary> /// Fires when a Command (e.g. Enable) comes from a an EventListener. @@ -705,11 +606,8 @@ namespace System.Diagnostics.Tracing { add { - lock (this) - { - m_eventCommandExecuted += value; - } - + m_eventCommandExecuted += value; + // If we have an EventHandler<EventCommandEventArgs> attached to the EventSource before the first command arrives // It should get a chance to handle the deferred commands. EventCommandEventArgs deferredCommands = m_deferredCommands; @@ -721,10 +619,7 @@ namespace System.Diagnostics.Tracing } remove { - lock (this) - { - m_eventCommandExecuted -= value; - } + m_eventCommandExecuted -= value; } } @@ -774,10 +669,43 @@ namespace System.Diagnostics.Tracing protected EventSource(EventSourceSettings settings, params string[] traits) { m_config = ValidateSettings(settings); - var myType = this.GetType(); - Initialize(GetGuid(myType), GetName(myType), traits); + + Guid eventSourceGuid; + string eventSourceName; + + EventMetadata[] eventDescriptors; + byte[] manifest; + GetMetadata(out eventSourceGuid, out eventSourceName, out eventDescriptors, out manifest); + + if (eventSourceGuid.Equals(Guid.Empty) || eventSourceName == null) + { + var myType = this.GetType(); + eventSourceGuid = GetGuid(myType); + eventSourceName = GetName(myType); + } + + Initialize(eventSourceGuid, eventSourceName, traits); } + internal virtual void GetMetadata(out Guid eventSourceGuid, out string eventSourceName, out EventMetadata[] eventData, out byte[] manifestBytes) + { + // + // In ProjectN subclasses need to override this method, and return the data from their EventSourceAttribute and EventAttribute annotations. + // On other architectures it is a no-op. + // + // eventDescriptors needs to contain one EventDescriptor for each event; the event's ID should be the same as its index in this array. + // manifestBytes is a UTF-8 encoding of the ETW manifest for the type. + // + // This will be implemented by an IL rewriter, so we can't make this method abstract or the initial build of the subclass would fail. + // + eventSourceGuid = Guid.Empty; + eventSourceName = null; + eventData = null; + manifestBytes = null; + + return; + } + /// <summary> /// This method is called when the eventSource is updated by the controller. /// </summary> @@ -1222,7 +1150,7 @@ namespace System.Diagnostics.Tracing { Contract.Assert(m_eventData != null); // You must have initialized this if you enabled the source. if (relatedActivityId != null) - ValidateEventOpcodeForTransfer(ref m_eventData[eventId]); + ValidateEventOpcodeForTransfer(ref m_eventData[eventId], m_eventData[eventId].Name); #if FEATURE_MANAGED_ETW if (m_eventData[eventId].EnabledForETW) @@ -1272,7 +1200,7 @@ namespace System.Diagnostics.Tracing // mask set to 0x0f so, when all ETW sessions want the event we don't need to // synthesize a new one if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data)) - ThrowEventSourceException(); + ThrowEventSourceException(m_eventData[eventId].Name); } else { @@ -1292,7 +1220,7 @@ namespace System.Diagnostics.Tracing unchecked((long)etwSessions.ToEventKeywords() | origKwd)); if (!m_provider.WriteEvent(ref desc, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data)) - ThrowEventSourceException(); + ThrowEventSourceException(m_eventData[eventId].Name); } } else @@ -1322,7 +1250,7 @@ namespace System.Diagnostics.Tracing if (!SelfDescribingEvents) { if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data)) - ThrowEventSourceException(); + ThrowEventSourceException(m_eventData[eventId].Name); } else { @@ -1356,7 +1284,7 @@ namespace System.Diagnostics.Tracing if (ex is EventSourceException) throw; else - ThrowEventSourceException(ex); + ThrowEventSourceException(m_eventData[eventId].Name, ex); } } } @@ -1471,8 +1399,10 @@ namespace System.Diagnostics.Tracing } } #endif + [SecurityCritical] private unsafe void WriteEventRaw( + string eventName, ref EventDescriptor eventDescriptor, Guid* activityID, Guid* relatedActivityID, @@ -1482,12 +1412,12 @@ namespace System.Diagnostics.Tracing #if FEATURE_MANAGED_ETW if (m_provider == null) { - ThrowEventSourceException(); + ThrowEventSourceException(eventName); } else { if (!m_provider.WriteEventRaw(ref eventDescriptor, activityID, relatedActivityID, dataCount, data)) - ThrowEventSourceException(); + ThrowEventSourceException(eventName); } #endif // FEATURE_MANAGED_ETW } @@ -1519,13 +1449,19 @@ namespace System.Diagnostics.Tracing { m_traits = traits; if (m_traits != null && m_traits.Length % 2 != 0) - throw new ArgumentException(Environment.GetResourceString("TraitEven"), "traits"); + { + throw new ArgumentException(Resources.GetResourceString("TraitEven"), "traits"); + } if (eventSourceGuid == Guid.Empty) - throw new ArgumentException(Environment.GetResourceString("EventSource_NeedGuid")); + { + throw new ArgumentException(Resources.GetResourceString("EventSource_NeedGuid")); + } if (eventSourceName == null) - throw new ArgumentException(Environment.GetResourceString("EventSource_NeedName")); + { + throw new ArgumentException(Resources.GetResourceString("EventSource_NeedName")); + } m_name = eventSourceName; m_guid = eventSourceGuid; @@ -1555,7 +1491,7 @@ namespace System.Diagnostics.Tracing // Set m_provider, which allows this. m_provider = provider; -#if !ES_BUILD_STANDALONE +#if (!ES_BUILD_STANDALONE && !PROJECTN) // API available on OS >= Win 8 and patched Win 7. // Disable only for FrameworkEventSource to avoid recursion inside exception handling. var osVer = Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor; @@ -1563,13 +1499,16 @@ namespace System.Diagnostics.Tracing #endif { int setInformationResult; - fixed (void* providerMetadata = this.providerMetadata) - { - setInformationResult = m_provider.SetInformation( - UnsafeNativeMethods.ManifestEtw.EVENT_INFO_CLASS.SetTraits, - providerMetadata, - this.providerMetadata.Length); - } + System.Runtime.InteropServices.GCHandle metadataHandle = + System.Runtime.InteropServices.GCHandle.Alloc(this.providerMetadata, System.Runtime.InteropServices.GCHandleType.Pinned); + IntPtr providerMetadata = metadataHandle.AddrOfPinnedObject(); + + setInformationResult = m_provider.SetInformation( + UnsafeNativeMethods.ManifestEtw.EVENT_INFO_CLASS.SetTraits, + providerMetadata, + (uint)this.providerMetadata.Length); + + metadataHandle.Free(); } #endif // FEATURE_MANAGED_ETW @@ -1812,7 +1751,7 @@ namespace System.Diagnostics.Tracing // advance to next EventData in array ++data; - Type dataType = m_eventData[eventId].Parameters[parameterId].ParameterType; + Type dataType = GetDataType(m_eventData[eventId], parameterId); Again: if (dataType == typeof(IntPtr)) @@ -1906,19 +1845,32 @@ namespace System.Diagnostics.Tracing } else { - if (dataType.IsEnum()) + if (m_EventSourcePreventRecursion && m_EventSourceInDecodeObject) { - dataType = Enum.GetUnderlyingType(dataType); - goto Again; + return null; } - // TODO FIX NOW Assuming that it is a string at this point is really likely to be fragile - // We should do something better. + try + { + m_EventSourceInDecodeObject = true; - // Everything else is marshaled as a string. - // ETW strings are NULL-terminated, so marshal everything up to the first - // null in the string. - return System.Runtime.InteropServices.Marshal.PtrToStringUni(dataPointer); + if (dataType.IsEnum()) + { + dataType = Enum.GetUnderlyingType(dataType); + goto Again; + } + + + // Everything else is marshaled as a string. + // ETW strings are NULL-terminated, so marshal everything up to the first + // null in the string. + return System.Runtime.InteropServices.Marshal.PtrToStringUni(dataPointer); + + } + finally + { + m_EventSourceInDecodeObject = false; + } } } @@ -1946,7 +1898,7 @@ namespace System.Diagnostics.Tracing Contract.Assert(m_eventData != null); // You must have initialized this if you enabled the source. if (childActivityID != null) { - ValidateEventOpcodeForTransfer(ref m_eventData[eventId]); + ValidateEventOpcodeForTransfer(ref m_eventData[eventId], m_eventData[eventId].Name); // If you use WriteEventWithRelatedActivityID you MUST declare the first argument to be a GUID // with the name 'relatedActivityID, and NOT pass this argument to the WriteEvent method. @@ -1958,7 +1910,7 @@ namespace System.Diagnostics.Tracing // which would cause a cryptic IndexOutOfRangeException later if we don't catch it here. if (!m_eventData[eventId].HasRelatedActivityID) { - throw new ArgumentException(Environment.GetResourceString("EventSource_NoRelatedActivityId")); + throw new ArgumentException(Resources.GetResourceString("EventSource_NoRelatedActivityId")); } } @@ -2007,7 +1959,7 @@ namespace System.Diagnostics.Tracing // mask set to 0x0f so, when all ETW sessions want the event we don't need to // synthesize a new one if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, childActivityID, args)) - ThrowEventSourceException(); + ThrowEventSourceException(m_eventData[eventId].Name); } else { @@ -2024,7 +1976,7 @@ namespace System.Diagnostics.Tracing unchecked((long)(ulong)etwSessions | origKwd)); if (!m_provider.WriteEvent(ref desc, pActivityId, childActivityID, args)) - ThrowEventSourceException(); + ThrowEventSourceException(m_eventData[eventId].Name); } } else @@ -2054,7 +2006,7 @@ namespace System.Diagnostics.Tracing if (!SelfDescribingEvents) { if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, childActivityID, args)) - ThrowEventSourceException(); + ThrowEventSourceException(m_eventData[eventId].Name); } else { @@ -2082,7 +2034,7 @@ namespace System.Diagnostics.Tracing #endif // FEATURE_MANAGED_ETW if (m_Dispatchers != null && m_eventData[eventId].EnabledForAnyListener) { -#if !ES_BUILD_STANDALONE +#if (!ES_BUILD_STANDALONE && !PROJECTN) // Maintain old behavior - object identity is preserved if (AppContextSwitches.PreserveEventListnerObjectIdentity) { @@ -2101,7 +2053,7 @@ namespace System.Diagnostics.Tracing if (ex is EventSourceException) throw; else - ThrowEventSourceException(ex); + ThrowEventSourceException(m_eventData[eventId].Name, ex); } } } @@ -2133,7 +2085,7 @@ namespace System.Diagnostics.Tracing /// <param name="args"></param> private void LogEventArgsMismatches(ParameterInfo[] infos, object[] args) { -#if !ES_BUILD_PCL +#if (!ES_BUILD_PCL && !PROJECTN) // It would be nice to have this on PCL builds, but it would be pointless since there isn't support for // writing to the debugger log on PCL. bool typesMatch = args.Length == infos.Length; @@ -2159,7 +2111,7 @@ namespace System.Diagnostics.Tracing if (!typesMatch) { - System.Diagnostics.Debugger.Log(0, null, Environment.GetResourceString("EventSource_VarArgsParameterMismatch") + "\r\n"); + System.Diagnostics.Debugger.Log(0, null, Resources.GetResourceString("EventSource_VarArgsParameterMismatch") + "\r\n"); } #endif //!ES_BUILD_PCL } @@ -2167,10 +2119,11 @@ namespace System.Diagnostics.Tracing [SecurityCritical] unsafe private void WriteToAllListeners(int eventId, Guid* childActivityID, int eventDataCount, EventSource.EventData* data) { - int paramCount = m_eventData[eventId].Parameters.Length; + int paramCount = GetParameterCount(m_eventData[eventId]); + if (eventDataCount != paramCount) { - ReportOutOfBandMessage(Environment.GetResourceString("EventSource_EventParametersMismatch", eventId, eventDataCount, paramCount), true); + ReportOutOfBandMessage(Resources.GetResourceString("EventSource_EventParametersMismatch", eventId, eventDataCount, paramCount), true); paramCount = Math.Min(paramCount, eventDataCount); } @@ -2238,7 +2191,7 @@ namespace System.Diagnostics.Tracing throw new EventSourceException(lastThrownException); } } - + [SecuritySafeCritical] [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] private unsafe void WriteEventString(EventLevel level, long keywords, string msgString) @@ -2443,7 +2396,7 @@ namespace System.Diagnostics.Tracing } [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] - private void ThrowEventSourceException(Exception innerEx = null) + private void ThrowEventSourceException(string eventName, Exception innerEx = null) { // If we fail during out of band logging we may end up trying // to throw another EventSourceException, thus hitting a StackOverflowException. @@ -2453,31 +2406,37 @@ namespace System.Diagnostics.Tracing try { m_EventSourceExceptionRecurenceCount++; + + string errorPrefix = "EventSourceException"; + if(eventName != null) + { + errorPrefix += " while processing event \"" + eventName + "\""; + } // TODO Create variations of EventSourceException that indicate more information using the error code. switch (EventProvider.GetLastWriteEventError()) { case EventProvider.WriteEventErrorCode.EventTooBig: - ReportOutOfBandMessage("EventSourceException: " + Environment.GetResourceString("EventSource_EventTooBig"), true); - if (ThrowOnEventWriteErrors) throw new EventSourceException(Environment.GetResourceString("EventSource_EventTooBig"), innerEx); + ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_EventTooBig"), true); + if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_EventTooBig"), innerEx); break; case EventProvider.WriteEventErrorCode.NoFreeBuffers: - ReportOutOfBandMessage("EventSourceException: " + Environment.GetResourceString("EventSource_NoFreeBuffers"), true); - if (ThrowOnEventWriteErrors) throw new EventSourceException(Environment.GetResourceString("EventSource_NoFreeBuffers"), innerEx); + ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_NoFreeBuffers"), true); + if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_NoFreeBuffers"), innerEx); break; case EventProvider.WriteEventErrorCode.NullInput: - ReportOutOfBandMessage("EventSourceException: " + Environment.GetResourceString("EventSource_NullInput"), true); - if (ThrowOnEventWriteErrors) throw new EventSourceException(Environment.GetResourceString("EventSource_NullInput"), innerEx); + ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_NullInput"), true); + if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_NullInput"), innerEx); break; case EventProvider.WriteEventErrorCode.TooManyArgs: - ReportOutOfBandMessage("EventSourceException: " + Environment.GetResourceString("EventSource_TooManyArgs"), true); - if (ThrowOnEventWriteErrors) throw new EventSourceException(Environment.GetResourceString("EventSource_TooManyArgs"), innerEx); + ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_TooManyArgs"), true); + if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_TooManyArgs"), innerEx); break; default: if (innerEx != null) - ReportOutOfBandMessage("EventSourceException: " + innerEx.GetType() + ":" + innerEx.Message, true); + ReportOutOfBandMessage(errorPrefix + ": " + innerEx.GetType() + ":" + innerEx.Message, true); else - ReportOutOfBandMessage("EventSourceException", true); + ReportOutOfBandMessage(errorPrefix, true); if (ThrowOnEventWriteErrors) throw new EventSourceException(innerEx); break; } @@ -2488,13 +2447,13 @@ namespace System.Diagnostics.Tracing } } - private void ValidateEventOpcodeForTransfer(ref EventMetadata eventData) + private void ValidateEventOpcodeForTransfer(ref EventMetadata eventData, string eventName) { if ((EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Send && (EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Receive && (EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Start) { - ThrowEventSourceException(); + ThrowEventSourceException(eventName); } } @@ -2502,11 +2461,11 @@ namespace System.Diagnostics.Tracing { if (opcode == EventOpcode.Info && eventName != null) { - if (eventName.EndsWith(s_ActivityStartSuffix)) + if (eventName.EndsWith(s_ActivityStartSuffix, StringComparison.Ordinal)) { return EventOpcode.Start; } - else if (eventName.EndsWith(s_ActivityStopSuffix)) + else if (eventName.EndsWith(s_ActivityStopSuffix, StringComparison.Ordinal)) { return EventOpcode.Stop; } @@ -2542,7 +2501,7 @@ namespace System.Diagnostics.Tracing /// descriptor as well as some stuff we added specifically for EventSource. see the /// code:m_eventData for where we use this. /// </summary> - internal struct EventMetadata + internal partial struct EventMetadata { public EventDescriptor Descriptor; public EventTags Tags; @@ -2563,6 +2522,10 @@ namespace System.Diagnostics.Tracing public TraceLoggingEventTypes TraceLoggingEventTypes; public EventActivityOptions ActivityOptions; + +#if PROJECTN + public EventParameterType[] ParameterTypes; +#endif }; // This is the internal entry point that code:EventListeners call when wanting to send a command to a @@ -2642,7 +2605,9 @@ namespace System.Diagnostics.Tracing // Find the per-EventSource dispatcher corresponding to registered dispatcher commandArgs.dispatcher = GetDispatcher(commandArgs.listener); if (commandArgs.dispatcher == null && commandArgs.listener != null) // dispatcher == null means ETW dispatcher - throw new ArgumentException(Environment.GetResourceString("EventSource_ListenerNotFound")); + { + throw new ArgumentException(Resources.GetResourceString("EventSource_ListenerNotFound")); + } if (commandArgs.Arguments == null) commandArgs.Arguments = new Dictionary<string, string>(); @@ -2720,7 +2685,7 @@ namespace System.Diagnostics.Tracing if (commandArgs.listener == null && commandArgs.Arguments.Count > 0 && commandArgs.perEventSourceSessionId != sessionIdBit) { - throw new ArgumentException(Environment.GetResourceString("EventSource_SessionIdError", + throw new ArgumentException(Resources.GetResourceString("EventSource_SessionIdError", commandArgs.perEventSourceSessionId + SessionMask.SHIFT_SESSION_TO_KEYWORD, sessionIdBit + SessionMask.SHIFT_SESSION_TO_KEYWORD)); } @@ -3042,10 +3007,31 @@ namespace System.Diagnostics.Tracing #endif if (m_eventData == null) { - Contract.Assert(m_rawManifest == null); - m_rawManifest = CreateManifestAndDescriptors(this.GetType(), Name, this); - Contract.Assert(m_eventData != null); + Guid eventSourceGuid = Guid.Empty; + string eventSourceName = null; + EventMetadata[] eventData = null; + byte[] manifest = null; + + // Try the GetMetadata provided by the ILTransform in ProjectN. The default sets all to null, and in that case we fall back + // to the reflection approach. + GetMetadata(out eventSourceGuid, out eventSourceName, out eventData, out manifest); + if (eventSourceGuid.Equals(Guid.Empty) || eventSourceName == null || eventData == null || manifest == null) + { + // GetMetadata failed, so we have to set it via reflection. + Contract.Assert(m_rawManifest == null); + m_rawManifest = CreateManifestAndDescriptors(this.GetType(), Name, this); + Contract.Assert(m_eventData != null); + + } + else + { + // GetMetadata worked, so set the fields as appropriate. + m_name = eventSourceName; + m_guid = eventSourceGuid; + m_eventData = eventData; + m_rawManifest = manifest; + } // TODO Enforce singleton pattern foreach (WeakReference eventSourceRef in EventListener.s_EventSources) { @@ -3053,7 +3039,9 @@ namespace System.Diagnostics.Tracing if (eventSource != null && eventSource.Guid == m_guid && !eventSource.IsDisposed) { if (eventSource != this) - throw new ArgumentException(Environment.GetResourceString("EventSource_EventSourceGuidInUse", m_guid)); + { + throw new ArgumentException(Resources.GetResourceString("EventSource_EventSourceGuidInUse", m_guid)); + } } } @@ -3104,6 +3092,7 @@ namespace System.Diagnostics.Tracing envelope.ChunkNumber = 0; EventProvider.EventData* dataDescrs = stackalloc EventProvider.EventData[2]; + dataDescrs[0].Ptr = (ulong)&envelope; dataDescrs[0].Size = (uint)sizeof(ManifestEnvelope); dataDescrs[0].Reserved = 0; @@ -3134,7 +3123,7 @@ namespace System.Diagnostics.Tracing } success = false; if (ThrowOnEventWriteErrors) - ThrowEventSourceException(); + ThrowEventSourceException("SendManifest"); break; } } @@ -3147,7 +3136,7 @@ namespace System.Diagnostics.Tracing return success; } -#if ES_BUILD_PCL +#if (ES_BUILD_PCL || PROJECTN) internal static Attribute GetCustomAttributeHelper(Type type, Type attributeType, EventManifestOptions flags = EventManifestOptions.None) { return GetCustomAttributeHelper(type.GetTypeInfo(), attributeType, flags); @@ -3170,7 +3159,7 @@ namespace System.Diagnostics.Tracing return firstAttribute; } -#if !ES_BUILD_PCL +#if (!ES_BUILD_PCL && !PROJECTN) // In the reflection only context, we have to do things by hand. string fullTypeNameToFind = attributeType.FullName; @@ -3218,8 +3207,8 @@ namespace System.Diagnostics.Tracing } return null; -#else // ES_BUILD_PCL - throw new ArgumentException(Environment.GetResourceString("EventSource", "EventSource_PCLPlatformNotSupportedReflection")); +#else // ES_BUILD_PCL && PROJECTN + throw new ArgumentException(Resources.GetResourceString("EventSource", "EventSource_PCLPlatformNotSupportedReflection")); #endif } @@ -3335,9 +3324,13 @@ namespace System.Diagnostics.Tracing bool typeMatch = GetEventSourceBaseType(eventSourceType, (flags & EventManifestOptions.AllowEventSourceOverride) != 0, eventSourceType.Assembly().ReflectionOnly()) != null; if (!typeMatch) - manifest.ManifestError(Environment.GetResourceString("EventSource_TypeMustDeriveFromEventSource")); + { + manifest.ManifestError(Resources.GetResourceString("EventSource_TypeMustDeriveFromEventSource")); + } if (!eventSourceType.IsAbstract() && !eventSourceType.IsSealed()) - manifest.ManifestError(Environment.GetResourceString("EventSource_TypeMustBeSealedOrAbstract")); + { + manifest.ManifestError(Resources.GetResourceString("EventSource_TypeMustBeSealedOrAbstract")); + } } // Collect task, opcode, keyword and channel information @@ -3352,7 +3345,7 @@ namespace System.Diagnostics.Tracing { if (eventSourceType.IsAbstract()) { - manifest.ManifestError(Environment.GetResourceString("EventSource_AbstractMustNotDeclareKTOC", nestedType.Name)); + manifest.ManifestError(Resources.GetResourceString("EventSource_AbstractMustNotDeclareKTOC", nestedType.Name)); } else { @@ -3394,7 +3387,9 @@ namespace System.Diagnostics.Tracing if (eventSourceType.IsAbstract()) { if (eventAttribute != null) - manifest.ManifestError(Environment.GetResourceString("EventSource_AbstractMustNotDeclareEventMethods", method.Name, eventAttribute.EventId)); + { + manifest.ManifestError(Resources.GetResourceString("EventSource_AbstractMustNotDeclareEventMethods", method.Name, eventAttribute.EventId)); + } continue; } else if (eventAttribute == null) @@ -3422,11 +3417,13 @@ namespace System.Diagnostics.Tracing } else if (eventAttribute.EventId <= 0) { - manifest.ManifestError(Environment.GetResourceString("EventSource_NeedPositiveId", method.Name), true); + manifest.ManifestError(Resources.GetResourceString("EventSource_NeedPositiveId", method.Name), true); continue; // don't validate anything else for this event } if (method.Name.LastIndexOf('.') >= 0) - manifest.ManifestError(Environment.GetResourceString("EventSource_EventMustNotBeExplicitImplementation", method.Name, eventAttribute.EventId)); + { + manifest.ManifestError(Resources.GetResourceString("EventSource_EventMustNotBeExplicitImplementation", method.Name, eventAttribute.EventId)); + } eventId++; string eventName = method.Name; @@ -3480,7 +3477,9 @@ namespace System.Diagnostics.Tracing } } if (noTask && (flags & EventManifestOptions.Strict) != 0) // Throw an error if we can compatibly. - throw new ArgumentException(Environment.GetResourceString("EventSource_StopsFollowStarts")); + { + throw new ArgumentException(Resources.GetResourceString("EventSource_StopsFollowStarts")); + } } } } @@ -3632,7 +3631,7 @@ namespace System.Diagnostics.Tracing #endif return; Error: - manifest.ManifestError(Environment.GetResourceString("EventSource_EnumKindMismatch", staticField.Name, staticField.FieldType.Name, providerEnumKind)); + manifest.ManifestError(Resources.GetResourceString("EventSource_EnumKindMismatch", staticField.Name, staticField.FieldType.Name, providerEnumKind)); } // Helper used by code:CreateManifestAndDescriptors to add a code:EventData descriptor for a method @@ -3655,9 +3654,9 @@ namespace System.Diagnostics.Tracing #if FEATURE_MANAGED_ETW_CHANNELS (byte)eventAttribute.Channel, #else - (byte)0, + (byte)0, #endif - (byte)eventAttribute.Level, + (byte)eventAttribute.Level, (byte)eventAttribute.Opcode, (int)eventAttribute.Task, unchecked((long)((ulong)eventAttribute.Keywords | SessionMask.All.ToEventKeywords()))); @@ -3688,7 +3687,7 @@ namespace System.Diagnostics.Tracing eventData = newValues; } } - + // Helper used by code:EventListener.AddEventSource and code:EventListener.EventListener // when a listener gets attached to a eventSource internal void AddListener(EventListener listener) @@ -3714,12 +3713,12 @@ namespace System.Diagnostics.Tracing int eventArg = GetHelperCallFirstArg(method); if (eventArg >= 0 && evtId != eventArg) { - manifest.ManifestError(Environment.GetResourceString("EventSource_MismatchIdToWriteEvent", evtName, evtId, eventArg), true); + manifest.ManifestError(Resources.GetResourceString("EventSource_MismatchIdToWriteEvent", evtName, evtId, eventArg), true); } if (evtId < eventData.Length && eventData[evtId].Descriptor.EventId != 0) { - manifest.ManifestError(Environment.GetResourceString("EventSource_EventIdReused", evtName, evtId, eventData[evtId].Name), true); + manifest.ManifestError(Resources.GetResourceString("EventSource_EventIdReused", evtName, evtId, eventData[evtId].Name), true); } // We give a task to things if they don't have one. @@ -3733,9 +3732,8 @@ namespace System.Diagnostics.Tracing if (eventData[idx].Descriptor.Task == (int)eventAttribute.Task && eventData[idx].Descriptor.Opcode == (int)eventAttribute.Opcode) { - manifest.ManifestError(Environment.GetResourceString("EventSource_TaskOpcodePairReused", + manifest.ManifestError(Resources.GetResourceString("EventSource_TaskOpcodePairReused", evtName, evtId, eventData[idx].Name, idx)); - // If we are not strict stop on first error. We have had problems with really large providers taking forever. because of many errors. if ((options & EventManifestOptions.Strict) == 0) break; @@ -3758,7 +3756,9 @@ namespace System.Diagnostics.Tracing failure = true; } if (failure) - manifest.ManifestError(Environment.GetResourceString("EventSource_EventMustHaveTaskIfNonDefaultOpcode", evtName, evtId)); + { + manifest.ManifestError(Resources.GetResourceString("EventSource_EventMustHaveTaskIfNonDefaultOpcode", evtName, evtId)); + } } // If we ever want to enforce the rule: MethodName = TaskName + OpcodeName here's how: @@ -3767,14 +3767,16 @@ namespace System.Diagnostics.Tracing // taskName & opcodeName could be passed in by the caller which has opTab & taskTab handy // if (!(((int)eventAttribute.Opcode == 0 && evtName == taskName) || (evtName == taskName+opcodeName))) // { - // throw new WarningException(Environment.GetResourceString("EventSource_EventNameDoesNotEqualTaskPlusOpcode")); + // throw new WarningException(Resources.GetResourceString("EventSource_EventNameDoesNotEqualTaskPlusOpcode")); // } if (eventsByName == null) eventsByName = new Dictionary<string, string>(); if (eventsByName.ContainsKey(evtName)) - manifest.ManifestError(Environment.GetResourceString("EventSource_EventNameReused", evtName), true); + { + manifest.ManifestError(Resources.GetResourceString("EventSource_EventNameReused", evtName), true); + } eventsByName[evtName] = evtName; } @@ -3795,7 +3797,7 @@ namespace System.Diagnostics.Tracing [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Switch statement is clearer than alternatives")] static private int GetHelperCallFirstArg(MethodInfo method) { -#if !ES_BUILD_PCL +#if (!ES_BUILD_PCL && !PROJECTN) // Currently searches for the following pattern // // ... // CAN ONLY BE THE INSTRUCTIONS BELOW @@ -3936,9 +3938,9 @@ namespace System.Diagnostics.Tracing { try { -#if !ES_BUILD_PCL +#if (!ES_BUILD_PCL && !PROJECTN) // send message to debugger without delay - System.Diagnostics.Debugger.Log(0, null, msg + "\r\n"); + System.Diagnostics.Debugger.Log(0, null, String.Format("EventSource Error: {0}{1}", msg , Environment.NewLine)); #endif // Send it to all listeners. @@ -3963,7 +3965,9 @@ namespace System.Diagnostics.Tracing var evtFormatMask = EventSourceSettings.EtwManifestEventFormat | EventSourceSettings.EtwSelfDescribingEventFormat; if ((settings & evtFormatMask) == evtFormatMask) - throw new ArgumentException(Environment.GetResourceString("EventSource_InvalidEventFormat"), "settings"); + { + throw new ArgumentException(Resources.GetResourceString("EventSource_InvalidEventFormat"), "settings"); + } // If you did not explicitly ask for manifest, you get self-describing. if ((settings & evtFormatMask) == 0) @@ -4080,6 +4084,9 @@ namespace System.Diagnostics.Tracing [ThreadStatic] private static byte m_EventSourceExceptionRecurenceCount = 0; // current recursion count inside ThrowEventSourceException + [ThreadStatic] + private static bool m_EventSourceInDecodeObject = false; + #if FEATURE_MANAGED_ETW_CHANNELS internal volatile ulong[] m_channelData; #endif @@ -4177,7 +4184,7 @@ namespace System.Diagnostics.Tracing /// created. /// </para> /// </summary> - public abstract class EventListener : IDisposable + public class EventListener : IDisposable { private event EventHandler<EventSourceCreatedEventArgs> _EventSourceCreated; @@ -4217,7 +4224,7 @@ namespace System.Diagnostics.Tracing /// Create a new EventListener in which all events start off turned off (use EnableEvents to turn /// them on). /// </summary> - protected EventListener() + public EventListener() { // This will cause the OnEventSourceCreated callback to fire. CallBackForExistingEventSources(true, (obj, args) => args.EventSource.AddListener(this) ); @@ -4409,7 +4416,7 @@ namespace System.Diagnostics.Tracing if (!s_EventSourceShutdownRegistered) { s_EventSourceShutdownRegistered = true; -#if !ES_BUILD_PCL && !FEATURE_CORECLR +#if (!ES_BUILD_PCL && !FEATURE_CORECLR && !PROJECTN) AppDomain.CurrentDomain.ProcessExit += DisposeOnShutdown; AppDomain.CurrentDomain.DomainUnload += DisposeOnShutdown; #endif @@ -4585,7 +4592,9 @@ namespace System.Diagnostics.Tracing { // Disallow creating EventListener reentrancy. if (s_CreatingListener) - throw new InvalidOperationException(Environment.GetResourceString("EventSource_ListenerCreatedInsideCallback")); + { + throw new InvalidOperationException(Resources.GetResourceString("EventSource_ListenerCreatedInsideCallback")); + } try { @@ -5931,8 +5940,8 @@ namespace System.Diagnostics.Tracing private uint m_mask; internal const int SHIFT_SESSION_TO_KEYWORD = 44; // bits 44-47 inclusive are reserved - internal const uint MASK = 0x0fU; // the mask of 4 reserved bits - internal const uint MAX = 4; // maximum number of simultaneous ETW sessions supported + internal const uint MASK = 0x0fU; // the mask of 4 reserved bits + internal const uint MAX = 4; // maximum number of simultaneous ETW sessions supported } /// <summary> @@ -6004,7 +6013,7 @@ namespace System.Diagnostics.Tracing /// ManifestBuilder is designed to isolate the details of the message of the event from the /// rest of EventSource. This one happens to create XML. /// </summary> - internal class ManifestBuilder + internal partial class ManifestBuilder { /// <summary> /// Build a manifest for 'providerName' with the given GUID, which will be packaged into 'dllName'. @@ -6045,10 +6054,14 @@ namespace System.Diagnostics.Tracing if ((flags & EventManifestOptions.Strict) != 0) { if (value <= 10 || value >= 239) - ManifestError(Environment.GetResourceString("EventSource_IllegalOpcodeValue", name, value)); + { + ManifestError(Resources.GetResourceString("EventSource_IllegalOpcodeValue", name, value)); + } string prevName; if (opcodeTab.TryGetValue(value, out prevName) && !name.Equals(prevName, StringComparison.Ordinal)) - ManifestError(Environment.GetResourceString("EventSource_OpcodeCollision", name, prevName, value)); + { + ManifestError(Resources.GetResourceString("EventSource_OpcodeCollision", name, prevName, value)); + } } opcodeTab[value] = name; } @@ -6057,10 +6070,14 @@ namespace System.Diagnostics.Tracing if ((flags & EventManifestOptions.Strict) != 0) { if (value <= 0 || value >= 65535) - ManifestError(Environment.GetResourceString("EventSource_IllegalTaskValue", name, value)); + { + ManifestError(Resources.GetResourceString("EventSource_IllegalTaskValue", name, value)); + } string prevName; if (taskTab != null && taskTab.TryGetValue(value, out prevName) && !name.Equals(prevName, StringComparison.Ordinal)) - ManifestError(Environment.GetResourceString("EventSource_TaskCollision", name, prevName, value)); + { + ManifestError(Resources.GetResourceString("EventSource_TaskCollision", name, prevName, value)); + } } if (taskTab == null) taskTab = new Dictionary<int, string>(); @@ -6069,14 +6086,20 @@ namespace System.Diagnostics.Tracing public void AddKeyword(string name, ulong value) { if ((value & (value - 1)) != 0) // Is it a power of 2? - ManifestError(Environment.GetResourceString("EventSource_KeywordNeedPowerOfTwo", "0x" + value.ToString("x", CultureInfo.CurrentCulture), name), true); + { + ManifestError(Resources.GetResourceString("EventSource_KeywordNeedPowerOfTwo", "0x" + value.ToString("x", CultureInfo.CurrentCulture), name), true); + } if ((flags & EventManifestOptions.Strict) != 0) { if (value >= 0x0000100000000000UL && !name.StartsWith("Session", StringComparison.Ordinal)) - ManifestError(Environment.GetResourceString("EventSource_IllegalKeywordsValue", name, "0x" + value.ToString("x", CultureInfo.CurrentCulture))); + { + ManifestError(Resources.GetResourceString("EventSource_IllegalKeywordsValue", name, "0x" + value.ToString("x", CultureInfo.CurrentCulture))); + } string prevName; if (keywordTab != null && keywordTab.TryGetValue(value, out prevName) && !name.Equals(prevName, StringComparison.Ordinal)) - ManifestError(Environment.GetResourceString("EventSource_KeywordCollision", name, prevName, "0x" + value.ToString("x", CultureInfo.CurrentCulture))); + { + ManifestError(Resources.GetResourceString("EventSource_KeywordCollision", name, prevName, "0x" + value.ToString("x", CultureInfo.CurrentCulture))); + } } if (keywordTab == null) keywordTab = new Dictionary<ulong, string>(); @@ -6091,13 +6114,13 @@ namespace System.Diagnostics.Tracing { EventChannel chValue = (EventChannel)value; if (value < (int)EventChannel.Admin || value > 255) - ManifestError(Environment.GetResourceString("EventSource_EventChannelOutOfRange", name, value)); + ManifestError(Resources.GetResourceString("EventSource_EventChannelOutOfRange", name, value)); else if (chValue >= EventChannel.Admin && chValue <= EventChannel.Debug && channelAttribute != null && EventChannelToChannelType(chValue) != channelAttribute.EventChannelType) { // we want to ensure developers do not define EventChannels that conflict with the builtin ones, // but we want to allow them to override the default ones... - ManifestError(Environment.GetResourceString("EventSource_ChannelTypeDoesNotMatchEventChannelValue", + ManifestError(Resources.GetResourceString("EventSource_ChannelTypeDoesNotMatchEventChannelValue", name, ((EventChannel)value).ToString())); } @@ -6264,7 +6287,7 @@ namespace System.Diagnostics.Tracing } if (channelTab.Count == MaxCountChannels) - ManifestError(Environment.GetResourceString("EventSource_MaxChannelExceeded")); + ManifestError(Resources.GetResourceString("EventSource_MaxChannelExceeded")); ulong channelKeyword; ChannelInfo info; @@ -6489,7 +6512,7 @@ namespace System.Diagnostics.Tracing cultures = new List<CultureInfo>(); cultures.Add(CultureInfo.CurrentUICulture); } -#if ES_BUILD_STANDALONE +#if ES_BUILD_STANDALONE || PROJECTN var sortedStrings = new List<string>(stringTab.Keys); sortedStrings.Sort(); #else @@ -6544,7 +6567,7 @@ namespace System.Diagnostics.Tracing string prevValue; if (stringTab.TryGetValue(key, out prevValue) && !prevValue.Equals(value)) { - ManifestError(Environment.GetResourceString("EventSource_DuplicateStringKey", key), true); + ManifestError(Resources.GetResourceString("EventSource_DuplicateStringKey", key), true); return; } @@ -6582,7 +6605,7 @@ namespace System.Diagnostics.Tracing private static List<CultureInfo> GetSupportedCultures(ResourceManager resources) { var cultures = new List<CultureInfo>(); -#if !ES_BUILD_PCL && !FEATURE_CORECLR +#if !ES_BUILD_PCL && !FEATURE_CORECLR && !PROJECTN foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.SpecificCultures /*| CultureTypes.NeutralCultures*/)) { if (resources.GetResourceSet(ci, true, false) != null) @@ -6606,26 +6629,26 @@ namespace System.Diagnostics.Tracing if (channelTab == null || !channelTab.TryGetValue((int)channel, out info)) { if (channel < EventChannel.Admin) // || channel > EventChannel.Debug) - ManifestError(Environment.GetResourceString("EventSource_UndefinedChannel", channel, eventName)); + ManifestError(Resources.GetResourceString("EventSource_UndefinedChannel", channel, eventName)); // allow channels to be auto-defined. The well known ones get their well known names, and the // rest get names Channel<N>. This allows users to modify the Manifest if they want more advanced features. if (channelTab == null) channelTab = new Dictionary<int, ChannelInfo>(4); - + string channelName = channel.ToString(); // For well know channels this is a nice name, otherwise a number if (EventChannel.Debug < channel) channelName = "Channel" + channelName; // Add a 'Channel' prefix for numbers. AddChannel(channelName, (int)channel, GetDefaultChannelAttribute(channel)); if (!channelTab.TryGetValue((int)channel, out info)) - ManifestError(Environment.GetResourceString("EventSource_UndefinedChannel", channel, eventName)); + ManifestError(Resources.GetResourceString("EventSource_UndefinedChannel", channel, eventName)); } // events that specify admin channels *must* have non-null "Message" attributes if (resources != null && eventMessage == null) eventMessage = resources.GetString("event_" + eventName, CultureInfo.InvariantCulture); if (info.Attribs.EventChannelType == EventChannelType.Admin && eventMessage == null) - ManifestError(Environment.GetResourceString("EventSource_EventWithAdminChannelMustHaveMessage", eventName, info.Name)); + ManifestError(Resources.GetResourceString("EventSource_EventWithAdminChannelMustHaveMessage", eventName, info.Name)); return info.Name; } #endif @@ -6641,6 +6664,7 @@ namespace System.Diagnostics.Tracing ret = taskTab[(int)task] = eventName; return ret; } + private string GetOpcodeName(EventOpcode opcode, string eventName) { switch (opcode) @@ -6672,11 +6696,12 @@ namespace System.Diagnostics.Tracing string ret; if (opcodeTab == null || !opcodeTab.TryGetValue((int)opcode, out ret)) { - ManifestError(Environment.GetResourceString("EventSource_UndefinedOpcode", opcode, eventName), true); + ManifestError(Resources.GetResourceString("EventSource_UndefinedOpcode", opcode, eventName), true); ret = null; } return ret; } + private string GetKeywords(ulong keywords, string eventName) { string ret = ""; @@ -6694,7 +6719,7 @@ namespace System.Diagnostics.Tracing } if (keyword == null) { - ManifestError(Environment.GetResourceString("EventSource_UndefinedKeyword", "0x" + bit.ToString("x", CultureInfo.CurrentCulture), eventName), true); + ManifestError(Resources.GetResourceString("EventSource_UndefinedKeyword", "0x" + bit.ToString("x", CultureInfo.CurrentCulture), eventName), true); keyword = string.Empty; } if (ret.Length != 0 && keyword.Length != 0) @@ -6704,6 +6729,7 @@ namespace System.Diagnostics.Tracing } return ret; } + private string GetTypeName(Type type) { if (type.IsEnum()) @@ -6712,45 +6738,8 @@ namespace System.Diagnostics.Tracing var typeName = GetTypeName(fields[0].FieldType); return typeName.Replace("win:Int", "win:UInt"); // ETW requires enums to be unsigned. } - switch (type.GetTypeCode()) - { - case TypeCode.Boolean: - return "win:Boolean"; - case TypeCode.Byte: - return "win:UInt8"; - case TypeCode.Char: - case TypeCode.UInt16: - return "win:UInt16"; - case TypeCode.UInt32: - return "win:UInt32"; - case TypeCode.UInt64: - return "win:UInt64"; - case TypeCode.SByte: - return "win:Int8"; - case TypeCode.Int16: - return "win:Int16"; - case TypeCode.Int32: - return "win:Int32"; - case TypeCode.Int64: - return "win:Int64"; - case TypeCode.String: - return "win:UnicodeString"; - case TypeCode.Single: - return "win:Float"; - case TypeCode.Double: - return "win:Double"; - case TypeCode.DateTime: - return "win:FILETIME"; - default: - if (type == typeof(Guid)) - return "win:GUID"; - else if (type == typeof(IntPtr)) - return "win:Pointer"; - else if ((type.IsArray || type.IsPointer) && type.GetElementType() == typeof(byte)) - return "win:Binary"; - ManifestError(Environment.GetResourceString("EventSource_UnsupportedEventTypeInManifest", type.Name), true); - return string.Empty; - } + + return GetTypeNameHelper(type); } private static void UpdateStringBuilder(ref StringBuilder stringBuilder, string eventMessage, int startIndex, int count) @@ -6822,7 +6811,7 @@ namespace System.Diagnostics.Tracing } else { - ManifestError(Environment.GetResourceString("EventSource_UnsupportedMessageProperty", evtName, eventMessage)); + ManifestError(Resources.GetResourceString("EventSource_UnsupportedMessageProperty", evtName, eventMessage)); } } else if ((chIdx = "&<>'\"\r\n\t".IndexOf(eventMessage[i])) >= 0) diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventSourceException.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventSourceException.cs index f950c6f702..4e11c802ee 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/EventSourceException.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventSourceException.cs @@ -17,7 +17,7 @@ namespace System.Diagnostics.Tracing /// <summary> /// Exception that is thrown when an error occurs during EventSource operation. /// </summary> -#if !ES_BUILD_PCL +#if (!ES_BUILD_PCL && !PROJECTN) [Serializable] #endif public class EventSourceException : Exception @@ -25,7 +25,8 @@ namespace System.Diagnostics.Tracing /// <summary> /// Initializes a new instance of the EventSourceException class. /// </summary> - public EventSourceException() : base(Environment.GetResourceString("EventSource_ListenerWriteFailure")) { } + public EventSourceException() : + base(Resources.GetResourceString("EventSource_ListenerWriteFailure")) { } /// <summary> /// Initializes a new instance of the EventSourceException class with a specified error message. @@ -38,13 +39,14 @@ namespace System.Diagnostics.Tracing /// </summary> public EventSourceException(string message, Exception innerException) : base(message, innerException) { } -#if !ES_BUILD_PCL +#if (!ES_BUILD_PCL && !PROJECTN) /// <summary> /// Initializes a new instance of the EventSourceException class with serialized data. /// </summary> protected EventSourceException(SerializationInfo info, StreamingContext context) : base(info, context) { } #endif - internal EventSourceException(Exception innerException) : base(Environment.GetResourceString("EventSource_ListenerWriteFailure"), innerException) { } + internal EventSourceException(Exception innerException) : + base(Resources.GetResourceString("EventSource_ListenerWriteFailure"), innerException) { } } } diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventSource_CoreCLR.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventSource_CoreCLR.cs new file mode 100644 index 0000000000..43c87529d2 --- /dev/null +++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventSource_CoreCLR.cs @@ -0,0 +1,223 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using Microsoft.Reflection; +using Microsoft.Win32; + +namespace System.Diagnostics.Tracing +{ + public partial class EventSource + { + // ActivityID support (see also WriteEventWithRelatedActivityIdCore) + /// <summary> + /// When a thread starts work that is on behalf of 'something else' (typically another + /// thread or network request) it should mark the thread as working on that other work. + /// This API marks the current thread as working on activity 'activityID'. This API + /// should be used when the caller knows the thread's current activity (the one being + /// overwritten) has completed. Otherwise, callers should prefer the overload that + /// return the oldActivityThatWillContinue (below). + /// + /// All events created with the EventSource on this thread are also tagged with the + /// activity ID of the thread. + /// + /// It is common, and good practice after setting the thread to an activity to log an event + /// with a 'start' opcode to indicate that precise time/thread where the new activity + /// started. + /// </summary> + /// <param name="activityId">A Guid that represents the new activity with which to mark + /// the current thread</param> + [System.Security.SecuritySafeCritical] + public static void SetCurrentThreadActivityId(Guid activityId) + { + if (TplEtwProvider.Log != null) + TplEtwProvider.Log.SetActivityId(activityId); +#if FEATURE_MANAGED_ETW +#if FEATURE_ACTIVITYSAMPLING + Guid newId = activityId; +#endif // FEATURE_ACTIVITYSAMPLING + // We ignore errors to keep with the convention that EventSources do not throw errors. + // Note we can't access m_throwOnWrites because this is a static method. + + if (UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( + UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID, + ref activityId) == 0) + { +#if FEATURE_ACTIVITYSAMPLING + var activityDying = s_activityDying; + if (activityDying != null && newId != activityId) + { + if (activityId == Guid.Empty) + { + activityId = FallbackActivityId; + } + // OutputDebugString(string.Format("Activity dying: {0} -> {1}", activityId, newId)); + activityDying(activityId); // This is actually the OLD activity ID. + } +#endif // FEATURE_ACTIVITYSAMPLING + } +#endif // FEATURE_MANAGED_ETW + } + + /// <summary> + /// When a thread starts work that is on behalf of 'something else' (typically another + /// thread or network request) it should mark the thread as working on that other work. + /// This API marks the current thread as working on activity 'activityID'. It returns + /// whatever activity the thread was previously marked with. There is a convention that + /// callers can assume that callees restore this activity mark before the callee returns. + /// To encourage this this API returns the old activity, so that it can be restored later. + /// + /// All events created with the EventSource on this thread are also tagged with the + /// activity ID of the thread. + /// + /// It is common, and good practice after setting the thread to an activity to log an event + /// with a 'start' opcode to indicate that precise time/thread where the new activity + /// started. + /// </summary> + /// <param name="activityId">A Guid that represents the new activity with which to mark + /// the current thread</param> + /// <param name="oldActivityThatWillContinue">The Guid that represents the current activity + /// which will continue at some point in the future, on the current thread</param> + [System.Security.SecuritySafeCritical] + public static void SetCurrentThreadActivityId(Guid activityId, out Guid oldActivityThatWillContinue) + { + oldActivityThatWillContinue = activityId; +#if FEATURE_MANAGED_ETW + // We ignore errors to keep with the convention that EventSources do not throw errors. + // Note we can't access m_throwOnWrites because this is a static method. + + UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( + UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID, + ref oldActivityThatWillContinue); +#endif // FEATURE_MANAGED_ETW + + // We don't call the activityDying callback here because the caller has declared that + // it is not dying. + if (TplEtwProvider.Log != null) + TplEtwProvider.Log.SetActivityId(activityId); + } + + /// <summary> + /// Retrieves the ETW activity ID associated with the current thread. + /// </summary> + public static Guid CurrentThreadActivityId + { + [System.Security.SecuritySafeCritical] + get + { + // We ignore errors to keep with the convention that EventSources do not throw + // errors. Note we can't access m_throwOnWrites because this is a static method. + Guid retVal = new Guid(); +#if FEATURE_MANAGED_ETW + UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( + UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_ID, + ref retVal); +#endif // FEATURE_MANAGED_ETW + return retVal; + } + } + + private int GetParameterCount(EventMetadata eventData) + { + return eventData.Parameters.Length; + } + + private Type GetDataType(EventMetadata eventData, int parameterId) + { + return eventData.Parameters[parameterId].ParameterType; + } + + private static string GetResourceString(string key, params object[] args) + { + return Environment.GetResourceString(key, args); + } + + private static readonly bool m_EventSourcePreventRecursion = false; + } + + internal partial class ManifestBuilder + { + private string GetTypeNameHelper(Type type) + { + switch (type.GetTypeCode()) + { + case TypeCode.Boolean: + return "win:Boolean"; + case TypeCode.Byte: + return "win:UInt8"; + case TypeCode.Char: + case TypeCode.UInt16: + return "win:UInt16"; + case TypeCode.UInt32: + return "win:UInt32"; + case TypeCode.UInt64: + return "win:UInt64"; + case TypeCode.SByte: + return "win:Int8"; + case TypeCode.Int16: + return "win:Int16"; + case TypeCode.Int32: + return "win:Int32"; + case TypeCode.Int64: + return "win:Int64"; + case TypeCode.String: + return "win:UnicodeString"; + case TypeCode.Single: + return "win:Float"; + case TypeCode.Double: + return "win:Double"; + case TypeCode.DateTime: + return "win:FILETIME"; + default: + if (type == typeof(Guid)) + return "win:GUID"; + else if (type == typeof(IntPtr)) + return "win:Pointer"; + else if ((type.IsArray || type.IsPointer) && type.GetElementType() == typeof(byte)) + return "win:Binary"; + + ManifestError(Environment.GetResourceString("EventSource_UnsupportedEventTypeInManifest", type.Name), true); + return string.Empty; + } + } + } + + internal partial class EventProvider + { + [System.Security.SecurityCritical] + internal unsafe int SetInformation( + UnsafeNativeMethods.ManifestEtw.EVENT_INFO_CLASS eventInfoClass, + IntPtr data, + uint dataSize) + { + int status = UnsafeNativeMethods.ManifestEtw.ERROR_NOT_SUPPORTED; + + if (!m_setInformationMissing) + { + try + { + status = UnsafeNativeMethods.ManifestEtw.EventSetInformation( + m_regHandle, + eventInfoClass, + (void *)data, + (int)dataSize); + } + catch (TypeLoadException) + { + m_setInformationMissing = true; + } + } + + return status; + } + } + + internal static class Resources + { + internal static string GetResourceString(string key, params object[] args) + { + return Environment.GetResourceString(key, args); + } + } +} diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/StubEnvironment.cs b/src/mscorlib/src/System/Diagnostics/Eventing/StubEnvironment.cs index a6d10506e7..4768baa744 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/StubEnvironment.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/StubEnvironment.cs @@ -36,7 +36,7 @@ namespace System.Diagnostics.Tracing.Internal sargs += ", "; sargs += arg.ToString(); } - + return key + " (" + sargs + ")"; } @@ -163,7 +163,7 @@ namespace Microsoft.Reflection { using System.Reflection; -#if ES_BUILD_PCL +#if (ES_BUILD_PCL || PROJECTN) [Flags] public enum BindingFlags { @@ -197,14 +197,16 @@ namespace Microsoft.Reflection #endif static class ReflectionExtensions { -#if !ES_BUILD_PCL - +#if (!ES_BUILD_PCL && !PROJECTN) + // // Type extension methods // public static bool IsEnum(this Type type) { return type.IsEnum; } public static bool IsAbstract(this Type type) { return type.IsAbstract; } public static bool IsSealed(this Type type) { return type.IsSealed; } + public static bool IsValueType(this Type type) { return type.IsValueType; } + public static bool IsGenericType(this Type type) { return type.IsGenericType; } public static Type BaseType(this Type type) { return type.BaseType; } public static Assembly Assembly(this Type type) { return type.Assembly; } public static TypeCode GetTypeCode(this Type type) { return Type.GetTypeCode(type); } @@ -219,9 +221,14 @@ namespace Microsoft.Reflection public static bool IsEnum(this Type type) { return type.GetTypeInfo().IsEnum; } public static bool IsAbstract(this Type type) { return type.GetTypeInfo().IsAbstract; } public static bool IsSealed(this Type type) { return type.GetTypeInfo().IsSealed; } + public static bool IsValueType(this Type type) { return type.GetTypeInfo().IsValueType; } + public static bool IsGenericType(this Type type) { return type.IsConstructedGenericType; } public static Type BaseType(this Type type) { return type.GetTypeInfo().BaseType; } public static Assembly Assembly(this Type type) { return type.GetTypeInfo().Assembly; } - + public static IEnumerable<PropertyInfo> GetProperties(this Type type) { return type.GetTypeInfo().DeclaredProperties; } + public static MethodInfo GetGetMethod(this PropertyInfo propInfo) { return propInfo.GetMethod; } + public static Type[] GetGenericArguments(this Type type) { return type.GenericTypeArguments; } + public static MethodInfo[] GetMethods(this Type type, BindingFlags flags) { // Minimal implementation to cover only the cases we need @@ -333,7 +340,7 @@ namespace Microsoft.Reflection } // Defining some no-ops in PCL builds -#if ES_BUILD_PCL +#if ES_BUILD_PCL || PROJECTN namespace System.Security { class SuppressUnmanagedCodeSecurityAttribute : Attribute { } @@ -349,4 +356,17 @@ namespace System.Security.Permissions public bool Unrestricted { get; set; } } } -#endif
\ No newline at end of file +#endif + +#if PROJECTN +namespace System +{ + public static class AppDomain + { + public static int GetCurrentThreadId() + { + return (int)Interop.mincore.GetCurrentThreadId(); + } + } +} +#endif diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ArrayTypeInfo.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ArrayTypeInfo.cs index ce98e38bf2..88d04e360e 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ArrayTypeInfo.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ArrayTypeInfo.cs @@ -10,12 +10,12 @@ namespace Microsoft.Diagnostics.Tracing namespace System.Diagnostics.Tracing #endif { - internal sealed class ArrayTypeInfo<ElementType> - : TraceLoggingTypeInfo<ElementType[]> + internal sealed class ArrayTypeInfo : TraceLoggingTypeInfo { - private readonly TraceLoggingTypeInfo<ElementType> elementInfo; + private readonly TraceLoggingTypeInfo elementInfo; - public ArrayTypeInfo(TraceLoggingTypeInfo<ElementType> elementInfo) + public ArrayTypeInfo(Type type, TraceLoggingTypeInfo elementInfo) + : base(type) { this.elementInfo = elementInfo; } @@ -30,19 +30,18 @@ namespace System.Diagnostics.Tracing collector.EndBufferedArray(); } - public override void WriteData( - TraceLoggingDataCollector collector, - ref ElementType[] value) + public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value) { var bookmark = collector.BeginBufferedArray(); var count = 0; - if (value != null) + Array array = (Array)value.ReferenceValue; + if (array != null) { - count = value.Length; - for (int i = 0; i < value.Length; i++) + count = array.Length; + for (int i = 0; i < array.Length; i++) { - this.elementInfo.WriteData(collector, ref value[i]); + this.elementInfo.WriteData(collector, elementInfo.PropertyValueFactory(array.GetValue(i))); } } @@ -51,11 +50,11 @@ namespace System.Diagnostics.Tracing public override object GetData(object value) { - var array = (ElementType[])value; + var array = (Array)value; var serializedArray = new object[array.Length]; for (int i = 0; i < array.Length; i++) { - serializedArray[i] = this.elementInfo.GetData(array[i]); + serializedArray[i] = this.elementInfo.GetData(array.GetValue(i)); } return serializedArray; } diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/DataCollector.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/DataCollector.cs index 238a0d8293..1cbc942cd8 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/DataCollector.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/DataCollector.cs @@ -85,7 +85,7 @@ namespace System.Diagnostics.Tracing var scratchNew = scratchOld + size; if (this.scratchEnd < scratchNew) { - throw new IndexOutOfRangeException(Environment.GetResourceString("EventSource_AddScalarOutOfRange")); + throw new IndexOutOfRangeException(Resources.GetResourceString("EventSource_AddScalarOutOfRange")); } this.ScalarsBegin(); @@ -272,13 +272,13 @@ namespace System.Diagnostics.Tracing var pinsTemp = this.pins; if (this.pinsEnd <= pinsTemp) { - throw new IndexOutOfRangeException(Environment.GetResourceString("EventSource_PinArrayOutOfRange")); + throw new IndexOutOfRangeException(Resources.GetResourceString("EventSource_PinArrayOutOfRange")); } var datasTemp = this.datas; if (this.datasEnd <= datasTemp) { - throw new IndexOutOfRangeException(Environment.GetResourceString("EventSource_DataDescriptorsOutOfRange")); + throw new IndexOutOfRangeException(Resources.GetResourceString("EventSource_DataDescriptorsOutOfRange")); } this.pins = pinsTemp + 1; @@ -296,7 +296,7 @@ namespace System.Diagnostics.Tracing var datasTemp = this.datas; if (this.datasEnd <= datasTemp) { - throw new IndexOutOfRangeException(Environment.GetResourceString("EventSource_DataDescriptorsOutOfRange")); + throw new IndexOutOfRangeException(Resources.GetResourceString("EventSource_DataDescriptorsOutOfRange")); } datasTemp->m_Ptr = (long)(ulong)(UIntPtr)this.scratch; diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumHelper.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumHelper.cs index 12e05845e0..095a0cd287 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumHelper.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumHelper.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; +#if EVENTSOURCE_GENERICS +?using System; using System.Reflection; #if ES_BUILD_STANDALONE @@ -19,27 +19,11 @@ namespace System.Diagnostics.Tracing /// </typeparam> internal static class EnumHelper<UnderlyingType> { - private delegate UnderlyingType Transformer<ValueType>(ValueType value); - - private static readonly MethodInfo IdentityInfo = - Statics.GetDeclaredStaticMethod(typeof(EnumHelper<UnderlyingType>), "Identity"); - public static UnderlyingType Cast<ValueType>(ValueType value) { - return Caster<ValueType>.Instance(value); - } - - internal static UnderlyingType Identity(UnderlyingType value) - { - return value; - } - - private static class Caster<ValueType> - { - public static readonly Transformer<ValueType> Instance = - (Transformer<ValueType>)Statics.CreateDelegate( - typeof(Transformer<ValueType>), - IdentityInfo); + return (UnderlyingType)(object)value; } } + } +#endif diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumerableTypeInfo.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumerableTypeInfo.cs index af5e60baaf..8f3605eeac 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumerableTypeInfo.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumerableTypeInfo.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Collections; using System.Collections.Generic; #if ES_BUILD_STANDALONE @@ -10,13 +11,12 @@ namespace Microsoft.Diagnostics.Tracing namespace System.Diagnostics.Tracing #endif { - internal sealed class EnumerableTypeInfo<IterableType, ElementType> - : TraceLoggingTypeInfo<IterableType> - where IterableType : IEnumerable<ElementType> + internal sealed class EnumerableTypeInfo : TraceLoggingTypeInfo { - private readonly TraceLoggingTypeInfo<ElementType> elementInfo; + private readonly TraceLoggingTypeInfo elementInfo; - public EnumerableTypeInfo(TraceLoggingTypeInfo<ElementType> elementInfo) + public EnumerableTypeInfo(Type type, TraceLoggingTypeInfo elementInfo) + : base(type) { this.elementInfo = elementInfo; } @@ -31,19 +31,17 @@ namespace System.Diagnostics.Tracing collector.EndBufferedArray(); } - public override void WriteData( - TraceLoggingDataCollector collector, - ref IterableType value) + public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value) { var bookmark = collector.BeginBufferedArray(); var count = 0; - if (value != null) + IEnumerable enumerable = (IEnumerable)value.ReferenceValue; + if (enumerable != null) { - foreach (var element in value) + foreach (var element in enumerable) { - var el = element; - this.elementInfo.WriteData(collector, ref el); + this.elementInfo.WriteData(collector, elementInfo.PropertyValueFactory(element)); count++; } } @@ -53,7 +51,7 @@ namespace System.Diagnostics.Tracing public override object GetData(object value) { - var iterType = (IterableType)value; + var iterType = (IEnumerable)value; List<object> serializedEnumerable = new List<object>(); foreach (var element in iterType) { diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventFieldFormat.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventFieldFormat.cs index 409535287e..7e6ed763a7 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventFieldFormat.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventFieldFormat.cs @@ -24,7 +24,7 @@ namespace System.Diagnostics.Tracing /// Field should not be displayed. /// </summary> NoPrint = 1, -#endif +#endif /// <summary> /// Field should be formatted as character or string data. /// Typically applied to 8-bit or 16-bit integers. @@ -77,7 +77,7 @@ namespace System.Diagnostics.Tracing /// Field should be formatted as a SOCKADDR. Typically applied to byte[] types. /// </summary> SocketAddress = 10, -#endif +#endif /// <summary> /// Field should be formatted as XML string data. Typically applied to /// strings or arrays of 8-bit or 16-bit integers. diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventSourceActivity.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventSourceActivity.cs index 3279a76642..dcaa9fd266 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventSourceActivity.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventSourceActivity.cs @@ -256,7 +256,7 @@ namespace System.Diagnostics.Tracing newActivity.startStopOptions.Opcode = EventOpcode.Start; this.eventSource.Write(eventName, ref newActivity.startStopOptions, ref newActivity.activityId, ref relatedActivityId, ref data); } - else + else { // If we are not active, we don't set the eventName, which basically also turns off the Stop event as well. newActivity.activityId = this.Id; @@ -305,11 +305,11 @@ namespace System.Diagnostics.Tracing /// <summary> /// If eventName is non-null then we logged a start event /// </summary> - private bool StartEventWasFired { get { return eventName != null; }} + private bool StartEventWasFired { get { return eventName != null; } } private readonly EventSource eventSource; private EventSourceOptions startStopOptions; - internal Guid activityId; + internal Guid activityId; // internal Guid relatedActivityId; private State state; private string eventName; diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/FieldMetadata.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/FieldMetadata.cs index b64940ac7a..404b0a7c46 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/FieldMetadata.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/FieldMetadata.cs @@ -127,17 +127,17 @@ namespace System.Diagnostics.Tracing { if (coreType == (int)TraceLoggingDataType.Nil) { - throw new NotSupportedException(Environment.GetResourceString("EventSource_NotSupportedArrayOfNil")); + throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedArrayOfNil")); } if (coreType == (int)TraceLoggingDataType.Binary) { - throw new NotSupportedException(Environment.GetResourceString("EventSource_NotSupportedArrayOfBinary")); + throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedArrayOfBinary")); } #if !BROKEN_UNTIL_M3 if (coreType == (int)TraceLoggingDataType.Utf16String || coreType == (int)TraceLoggingDataType.MbcsString) { - throw new NotSupportedException(Environment.GetResourceString("EventSource_NotSupportedArrayOfNullTerminatedString")); + throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedArrayOfNullTerminatedString")); } #endif } @@ -159,7 +159,7 @@ namespace System.Diagnostics.Tracing this.outType++; if ((this.outType & Statics.OutTypeMask) == 0) { - throw new NotSupportedException(Environment.GetResourceString("EventSource_TooManyFields")); + throw new NotSupportedException(Resources.GetResourceString("EventSource_TooManyFields")); } } diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/InvokeTypeInfo.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/InvokeTypeInfo.cs index 903114f10d..653f605a17 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/InvokeTypeInfo.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/InvokeTypeInfo.cs @@ -13,20 +13,20 @@ namespace System.Diagnostics.Tracing /// <summary> /// TraceLogging: An implementation of TraceLoggingTypeInfo that works /// for arbitrary types. It writes all public instance properties of - /// the type. Implemented using Delegate.CreateDelegate(property.Getter). + /// the type. /// </summary> /// <typeparam name="ContainerType"> /// Type from which to read values. /// </typeparam> - internal sealed class InvokeTypeInfo<ContainerType> - : TraceLoggingTypeInfo<ContainerType> + internal sealed class InvokeTypeInfo : TraceLoggingTypeInfo { private readonly PropertyAnalysis[] properties; - private readonly PropertyAccessor<ContainerType>[] accessors; public InvokeTypeInfo( + Type type, TypeAnalysis typeAnalysis) : base( + type, typeAnalysis.name, typeAnalysis.level, typeAnalysis.opcode, @@ -34,14 +34,7 @@ namespace System.Diagnostics.Tracing typeAnalysis.tags) { if (typeAnalysis.properties.Length != 0) - { this.properties = typeAnalysis.properties; - this.accessors = new PropertyAccessor<ContainerType>[this.properties.Length]; - for (int i = 0; i < this.accessors.Length; i++) - { - this.accessors[i] = PropertyAccessor<ContainerType>.Create(this.properties[i]); - } - } } public override void WriteMetadata( @@ -70,15 +63,13 @@ namespace System.Diagnostics.Tracing } } - public override void WriteData( - TraceLoggingDataCollector collector, - ref ContainerType value) + public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value) { - if (this.accessors != null) + if (this.properties != null) { - foreach (var accessor in this.accessors) + foreach (var property in this.properties) { - accessor.Write(collector, ref value); + property.typeInfo.WriteData(collector, property.getter(value)); } } } @@ -91,7 +82,7 @@ namespace System.Diagnostics.Tracing var memebersValues = new List<object>(); for (int i = 0; i < this.properties.Length; i++) { - var propertyValue = accessors[i].GetData((ContainerType)value); + var propertyValue = properties[i].propertyInfo.GetValue(value); membersNames.Add(properties[i].name); memebersValues.Add(properties[i].typeInfo.GetData(propertyValue)); } @@ -100,18 +91,5 @@ namespace System.Diagnostics.Tracing return null; } - - public override void WriteObjectData( - TraceLoggingDataCollector collector, - object valueObj) - { - if (this.accessors != null) - { - var value = valueObj == null - ? default(ContainerType) - : (ContainerType)valueObj; - this.WriteData(collector, ref value); - } - } } } diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/NameInfo.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/NameInfo.cs index acc76078ff..1a428e5d03 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/NameInfo.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/NameInfo.cs @@ -26,14 +26,14 @@ namespace System.Diagnostics.Tracing { for(;;) { - int snapshot =lastIdentity; + int snapshot = lastIdentity; int newIdentity = (lastIdentity & ~0xFFFFFF) + eventId; newIdentity = Math.Max(newIdentity, snapshot); // Should be redundant. as we only create descriptors once. if (Interlocked.CompareExchange(ref lastIdentity, newIdentity, snapshot) == snapshot) break; } } - + private static int lastIdentity = Statics.TraceLoggingChannel << 24; internal readonly string name; internal readonly EventTags tags; diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyAccessor.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyAccessor.cs deleted file mode 100644 index 388e0b61c0..0000000000 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyAccessor.cs +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Reflection; - -#if ES_BUILD_STANDALONE -namespace Microsoft.Diagnostics.Tracing -#else -namespace System.Diagnostics.Tracing -#endif -{ - /// <summary> - /// TraceLogging: Each PropertyAccessor instance encapsulates the information - /// needed to read a particular property from an instance of ContainerType - /// and write the value to a DataCollector. Used by InvokeTypeInfo. - /// </summary> - /// <typeparam name="ContainerType"> - /// The type of the object from which properties are read. - /// </typeparam> - internal abstract class PropertyAccessor<ContainerType> - { - public abstract void Write(TraceLoggingDataCollector collector, ref ContainerType value); - public abstract object GetData(ContainerType value); - - public static PropertyAccessor<ContainerType> Create(PropertyAnalysis property) - { - // Due to current Project N limitations on handling generic instantiations with - // 2 generic parameters we have to explicitly create the instantiations that we consider - // important to EventSource performance (we have considered int, long, string for the moment). - // Everything else is handled by NonGenericPropertyWriter that ends up boxing the container object. - var retType = property.getterInfo.ReturnType; - if (!Statics.IsValueType(typeof(ContainerType))) - { - if (retType == typeof(int)) - return new ClassPropertyWriter<ContainerType, int>(property); - else if (retType == typeof(long)) - return new ClassPropertyWriter<ContainerType, long>(property); - else if (retType == typeof(string)) - return new ClassPropertyWriter<ContainerType, string>(property); - } - else - { - // Handle the case if it is a struct (DD 1027919) - } - - // Otherwise use the boxing one. - return new NonGenericProperytWriter<ContainerType>(property); - } - } - - /// <summary> - /// The type specific version of the property writers uses generics in a way - /// that Project N can't handle at the moment. To avoid this we simply - /// use reflection completely. - /// </summary> - internal class NonGenericProperytWriter<ContainerType> : PropertyAccessor<ContainerType> - { - public NonGenericProperytWriter(PropertyAnalysis property) - { - getterInfo = property.getterInfo; - typeInfo = property.typeInfo; - } - - public override void Write(TraceLoggingDataCollector collector, ref ContainerType container) - { - object value = container == null - ? null - : getterInfo.Invoke((object)container, null); - this.typeInfo.WriteObjectData(collector, value); - } - - public override object GetData(ContainerType container) - { - return container == null - ? default(ValueType) - : getterInfo.Invoke((object)container, null); - } - - private readonly TraceLoggingTypeInfo typeInfo; - private readonly MethodInfo getterInfo; - } - - /// <summary> - /// Implementation of PropertyAccessor for use when ContainerType is a - /// value type. - /// </summary> - /// <typeparam name="ContainerType">The type of the object from which properties are read.</typeparam> - /// <typeparam name="ValueType">Type of the property being read.</typeparam> - internal class StructPropertyWriter<ContainerType, ValueType> - : PropertyAccessor<ContainerType> - { - private delegate ValueType Getter(ref ContainerType container); - private readonly TraceLoggingTypeInfo<ValueType> valueTypeInfo; - private readonly Getter getter; - - public StructPropertyWriter(PropertyAnalysis property) - { - this.valueTypeInfo = (TraceLoggingTypeInfo<ValueType>)property.typeInfo; - this.getter = (Getter)Statics.CreateDelegate( - typeof(Getter), - property.getterInfo); - } - - public override void Write(TraceLoggingDataCollector collector, ref ContainerType container) - { - var value = container == null - ? default(ValueType) - : getter(ref container); - this.valueTypeInfo.WriteData(collector, ref value); - } - - public override object GetData(ContainerType container) - { - return container == null - ? default(ValueType) - : getter(ref container); - } - } - - /// <summary> - /// Implementation of PropertyAccessor for use when ContainerType is a - /// reference type. - /// </summary> - /// <typeparam name="ContainerType">The type of the object from which properties are read.</typeparam> - /// <typeparam name="ValueType">Type of the property being read.</typeparam> - internal class ClassPropertyWriter<ContainerType, ValueType> - : PropertyAccessor<ContainerType> - { - private delegate ValueType Getter(ContainerType container); - private readonly TraceLoggingTypeInfo<ValueType> valueTypeInfo; - private readonly Getter getter; - - public ClassPropertyWriter(PropertyAnalysis property) - { - this.valueTypeInfo = (TraceLoggingTypeInfo<ValueType>)property.typeInfo; - this.getter = (Getter)Statics.CreateDelegate( - typeof(Getter), - property.getterInfo); - } - - public override void Write(TraceLoggingDataCollector collector, ref ContainerType container) - { - var value = container == null - ? default(ValueType) - : getter(container); - this.valueTypeInfo.WriteData(collector, ref value); - } - - public override object GetData(ContainerType container) - { - return container == null - ? default(ValueType) - : getter(container); - } - } -} diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyAnalysis.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyAnalysis.cs index 64972d1bfb..4688a9241e 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyAnalysis.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyAnalysis.cs @@ -17,18 +17,20 @@ namespace System.Diagnostics.Tracing internal sealed class PropertyAnalysis { internal readonly string name; - internal readonly MethodInfo getterInfo; + internal readonly PropertyInfo propertyInfo; + internal readonly Func<PropertyValue, PropertyValue> getter; internal readonly TraceLoggingTypeInfo typeInfo; internal readonly EventFieldAttribute fieldAttribute; public PropertyAnalysis( string name, - MethodInfo getterInfo, + PropertyInfo propertyInfo, TraceLoggingTypeInfo typeInfo, EventFieldAttribute fieldAttribute) { this.name = name; - this.getterInfo = getterInfo; + this.propertyInfo = propertyInfo; + this.getter = PropertyValue.GetPropertyGetter(propertyInfo); this.typeInfo = typeInfo; this.fieldAttribute = fieldAttribute; } diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyValue.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyValue.cs new file mode 100644 index 0000000000..0f34d95648 --- /dev/null +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyValue.cs @@ -0,0 +1,251 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +#if !ES_BUILD_AGAINST_DOTNET_V35 +using Contract = System.Diagnostics.Contracts.Contract; +#else +using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract; +#endif + +namespace System.Diagnostics.Tracing +{ + /// <summary> + /// Holds property values of any type. For common value types, we have inline storage so that we don't need + /// to box the values. For all other types, we store the value in a single object reference field. + /// + /// To get the value of a property quickly, use a delegate produced by <see cref="PropertyValue.GetPropertyGetter(PropertyInfo)"/>. + /// </summary> + internal unsafe struct PropertyValue + { + /// <summary> + /// Union of well-known value types, to avoid boxing those types. + /// </summary> + [StructLayout(LayoutKind.Explicit)] + public struct Scalar + { + [FieldOffset(0)] + public Boolean AsBoolean; + [FieldOffset(0)] + public Byte AsByte; + [FieldOffset(0)] + public SByte AsSByte; + [FieldOffset(0)] + public Char AsChar; + [FieldOffset(0)] + public Int16 AsInt16; + [FieldOffset(0)] + public UInt16 AsUInt16; + [FieldOffset(0)] + public Int32 AsInt32; + [FieldOffset(0)] + public UInt32 AsUInt32; + [FieldOffset(0)] + public Int64 AsInt64; + [FieldOffset(0)] + public UInt64 AsUInt64; + [FieldOffset(0)] + public IntPtr AsIntPtr; + [FieldOffset(0)] + public UIntPtr AsUIntPtr; + [FieldOffset(0)] + public Single AsSingle; + [FieldOffset(0)] + public Double AsDouble; + [FieldOffset(0)] + public Guid AsGuid; + [FieldOffset(0)] + public DateTime AsDateTime; + [FieldOffset(0)] + public DateTimeOffset AsDateTimeOffset; + [FieldOffset(0)] + public TimeSpan AsTimeSpan; + [FieldOffset(0)] + public Decimal AsDecimal; + } + + // Anything not covered by the Scalar union gets stored in this reference. + readonly object _reference; + readonly Scalar _scalar; + readonly int _scalarLength; + + private PropertyValue(object value) + { + _reference = value; + _scalar = default(Scalar); + _scalarLength = 0; + } + + private PropertyValue(Scalar scalar, int scalarLength) + { + _reference = null; + _scalar = scalar; + _scalarLength = scalarLength; + } + + private PropertyValue(Boolean value) : this(new Scalar() { AsBoolean = value }, sizeof(Boolean)) { } + private PropertyValue(Byte value) : this(new Scalar() { AsByte = value }, sizeof(Byte)) { } + private PropertyValue(SByte value) : this(new Scalar() { AsSByte = value }, sizeof(SByte)) { } + private PropertyValue(Char value) : this(new Scalar() { AsChar = value }, sizeof(Char)) { } + private PropertyValue(Int16 value) : this(new Scalar() { AsInt16 = value }, sizeof(Int16)) { } + private PropertyValue(UInt16 value) : this(new Scalar() { AsUInt16 = value }, sizeof(UInt16)) { } + private PropertyValue(Int32 value) : this(new Scalar() { AsInt32 = value }, sizeof(Int32)) { } + private PropertyValue(UInt32 value) : this(new Scalar() { AsUInt32 = value }, sizeof(UInt32)) { } + private PropertyValue(Int64 value) : this(new Scalar() { AsInt64 = value }, sizeof(Int64)) { } + private PropertyValue(UInt64 value) : this(new Scalar() { AsUInt64 = value }, sizeof(UInt64)) { } + private PropertyValue(IntPtr value) : this(new Scalar() { AsIntPtr = value }, sizeof(IntPtr)) { } + private PropertyValue(UIntPtr value) : this(new Scalar() { AsUIntPtr = value }, sizeof(UIntPtr)) { } + private PropertyValue(Single value) : this(new Scalar() { AsSingle = value }, sizeof(Single)) { } + private PropertyValue(Double value) : this(new Scalar() { AsDouble = value }, sizeof(Double)) { } + private PropertyValue(Guid value) : this(new Scalar() { AsGuid = value }, sizeof(Guid)) { } + private PropertyValue(DateTime value) : this(new Scalar() { AsDateTime = value }, sizeof(DateTime)) { } + private PropertyValue(DateTimeOffset value) : this(new Scalar() { AsDateTimeOffset = value }, sizeof(DateTimeOffset)) { } + private PropertyValue(TimeSpan value) : this(new Scalar() { AsTimeSpan = value }, sizeof(TimeSpan)) { } + private PropertyValue(Decimal value) : this(new Scalar() { AsDecimal = value }, sizeof(Decimal)) { } + + public static Func<object, PropertyValue> GetFactory(Type type) + { + if (type == typeof(Boolean)) return value => new PropertyValue((Boolean)value); + if (type == typeof(Byte)) return value => new PropertyValue((Byte)value); + if (type == typeof(SByte)) return value => new PropertyValue((SByte)value); + if (type == typeof(Char)) return value => new PropertyValue((Char)value); + if (type == typeof(Int16)) return value => new PropertyValue((Int16)value); + if (type == typeof(UInt16)) return value => new PropertyValue((UInt16)value); + if (type == typeof(Int32)) return value => new PropertyValue((Int32)value); + if (type == typeof(UInt32)) return value => new PropertyValue((UInt32)value); + if (type == typeof(Int64)) return value => new PropertyValue((Int64)value); + if (type == typeof(UInt64)) return value => new PropertyValue((UInt64)value); + if (type == typeof(IntPtr)) return value => new PropertyValue((IntPtr)value); + if (type == typeof(UIntPtr)) return value => new PropertyValue((UIntPtr)value); + if (type == typeof(Single)) return value => new PropertyValue((Single)value); + if (type == typeof(Double)) return value => new PropertyValue((Double)value); + if (type == typeof(Guid)) return value => new PropertyValue((Guid)value); + if (type == typeof(DateTime)) return value => new PropertyValue((DateTime)value); + if (type == typeof(DateTimeOffset)) return value => new PropertyValue((DateTimeOffset)value); + if (type == typeof(TimeSpan)) return value => new PropertyValue((TimeSpan)value); + if (type == typeof(Decimal)) return value => new PropertyValue((Decimal)value); + + return value => new PropertyValue(value); + } + + + public object ReferenceValue + { + get + { + Contract.Assert(_scalarLength == 0, "This ReflectedValue refers to an unboxed value type, not a reference type or boxed value type."); + return _reference; + } + } + + public Scalar ScalarValue + { + get + { + Contract.Assert(_scalarLength > 0, "This ReflectedValue refers to a reference type or boxed value type, not an unboxed value type"); + return _scalar; + } + } + + public int ScalarLength + { + get + { + Contract.Assert(_scalarLength > 0, "This ReflectedValue refers to a reference type or boxed value type, not an unboxed value type"); + return _scalarLength; + } + } + + /// <summary> + /// Gets a delegate that gets the value of a given property. + /// </summary> + public static Func<PropertyValue, PropertyValue> GetPropertyGetter(PropertyInfo property) + { + if (property.DeclaringType.GetTypeInfo().IsValueType) + return GetBoxedValueTypePropertyGetter(property); + else + return GetReferenceTypePropertyGetter(property); + } + + /// <summary> + /// Gets a delegate that gets the value of a property of a value type. We unfortunately cannot avoid boxing the value type, + /// without making this generic over the value type. That would result in a large number of generic instantiations, and furthermore + /// does not work correctly on .Net Native (we cannot express the needed instantiations in an rd.xml file). We expect that user-defined + /// value types will be rare, and in any case the boxing only happens for events that are actually enabled. + /// </summary> + private static Func<PropertyValue, PropertyValue> GetBoxedValueTypePropertyGetter(PropertyInfo property) + { + var type = property.PropertyType; + + if (type.GetTypeInfo().IsEnum) + type = Enum.GetUnderlyingType(type); + + var factory = GetFactory(type); + + return container => factory(property.GetValue(container.ReferenceValue)); + } + + /// <summary> + /// For properties of reference types, we use a generic helper class to get the value. This enables us to use MethodInfo.CreateDelegate + /// to build a fast getter. We can get away with this on .Net Native, because we really only need one runtime instantiation of the + /// generic type, since it's only instantiated over reference types (and thus all instances are shared). + /// </summary> + /// <param name="property"></param> + /// <returns></returns> + private static Func<PropertyValue, PropertyValue> GetReferenceTypePropertyGetter(PropertyInfo property) + { + var helper = (TypeHelper)Activator.CreateInstance(typeof(ReferenceTypeHelper<>).MakeGenericType(property.DeclaringType)); + return helper.GetPropertyGetter(property); + } + + private abstract class TypeHelper + { + public abstract Func<PropertyValue, PropertyValue> GetPropertyGetter(PropertyInfo property); + + protected Delegate GetGetMethod(PropertyInfo property, Type propertyType) + { + return property.GetMethod.CreateDelegate(typeof(Func<,>).MakeGenericType(property.DeclaringType, propertyType)); + } + } + + private sealed class ReferenceTypeHelper<TContainer> : TypeHelper where TContainer : class + { + public override Func<PropertyValue, PropertyValue> GetPropertyGetter(PropertyInfo property) + { + var type = property.PropertyType; + + if (!Statics.IsValueType(type)) + { + var getter = (Func<TContainer, object>)GetGetMethod(property, type); + return container => new PropertyValue(getter((TContainer)container.ReferenceValue)); + } + else + { + if (type.GetTypeInfo().IsEnum) + type = Enum.GetUnderlyingType(type); + + if (type == typeof(Boolean)) { var f = (Func<TContainer, Boolean>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(Byte)) { var f = (Func<TContainer, Byte>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(SByte)) { var f = (Func<TContainer, SByte>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(Char)) { var f = (Func<TContainer, Char>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(Int16)) { var f = (Func<TContainer, Int16>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(UInt16)) { var f = (Func<TContainer, UInt16>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(Int32)) { var f = (Func<TContainer, Int32>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(UInt32)) { var f = (Func<TContainer, UInt32>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(Int64)) { var f = (Func<TContainer, Int64>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(UInt64)) { var f = (Func<TContainer, UInt64>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(IntPtr)) { var f = (Func<TContainer, IntPtr>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(UIntPtr)) { var f = (Func<TContainer, UIntPtr>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(Single)) { var f = (Func<TContainer, Single>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(Double)) { var f = (Func<TContainer, Double>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(Guid)) { var f = (Func<TContainer, Guid>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(DateTime)) { var f = (Func<TContainer, DateTime>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(DateTimeOffset)) { var f = (Func<TContainer, DateTimeOffset>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(TimeSpan)) { var f = (Func<TContainer, TimeSpan>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + if (type == typeof(Decimal)) { var f = (Func<TContainer, Decimal>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue)); } + + return container => new PropertyValue(property.GetValue(container.ReferenceValue)); + } + } + } + } +} diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleEventTypes.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleEventTypes.cs index 7a613f4293..19e922205e 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleEventTypes.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleEventTypes.cs @@ -18,30 +18,19 @@ namespace System.Diagnostics.Tracing /// Type of the top-level payload object. Should be EmptyStruct if the /// event has no payload. /// </typeparam> - internal class SimpleEventTypes<T> - : TraceLoggingEventTypes + internal static class SimpleEventTypes<T> { - private static SimpleEventTypes<T> instance; + private static TraceLoggingEventTypes instance; - internal readonly TraceLoggingTypeInfo<T> typeInfo; - - private SimpleEventTypes(TraceLoggingTypeInfo<T> typeInfo) - : base( - typeInfo.Name, - typeInfo.Tags, - new TraceLoggingTypeInfo[] { typeInfo }) - { - this.typeInfo = typeInfo; - } - - public static SimpleEventTypes<T> Instance + public static TraceLoggingEventTypes Instance { get { return instance ?? InitInstance(); } } - private static SimpleEventTypes<T> InitInstance() + private static TraceLoggingEventTypes InitInstance() { - var newInstance = new SimpleEventTypes<T>(TraceLoggingTypeInfo<T>.Instance); + var info = TraceLoggingTypeInfo.GetInstance(typeof(T), null); + var newInstance = new TraceLoggingEventTypes(info.Name, info.Tags, new TraceLoggingTypeInfo[] { info }); Interlocked.CompareExchange(ref instance, newInstance, null); return instance; } diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleTypeInfos.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleTypeInfos.cs index d262bdba2e..f6b621e960 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleTypeInfos.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleTypeInfos.cs @@ -3,6 +3,13 @@ using System; using System.Collections.Generic; +using System.Reflection; + +#if !ES_BUILD_AGAINST_DOTNET_V35 +using Contract = System.Diagnostics.Contracts.Contract; +#else +using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract; +#endif #if ES_BUILD_STANDALONE namespace Microsoft.Diagnostics.Tracing @@ -10,15 +17,13 @@ namespace Microsoft.Diagnostics.Tracing namespace System.Diagnostics.Tracing #endif { - #region NullTypeInfo - /// <summary> /// TraceLogging: Type handler for empty or unsupported types. /// </summary> - /// <typeparam name="DataType">The type to handle.</typeparam> - internal sealed class NullTypeInfo<DataType> - : TraceLoggingTypeInfo<DataType> + internal sealed class NullTypeInfo : TraceLoggingTypeInfo { + public NullTypeInfo() : base(typeof(EmptyStruct)) { } + public override void WriteMetadata( TraceLoggingMetadataCollector collector, string name, @@ -27,7 +32,7 @@ namespace System.Diagnostics.Tracing collector.AddGroup(name); } - public override void WriteData(TraceLoggingDataCollector collector, ref DataType value) + public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value) { return; } @@ -38,792 +43,107 @@ namespace System.Diagnostics.Tracing } } - #endregion - - #region Primitive scalars - - /// <summary> - /// TraceLogging: Type handler for Boolean. - /// </summary> - internal sealed class BooleanTypeInfo - : TraceLoggingTypeInfo<Boolean> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format8(format, TraceLoggingDataType.Boolean8)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref Boolean value) - { - collector.AddScalar(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for Byte. - /// </summary> - internal sealed class ByteTypeInfo - : TraceLoggingTypeInfo<Byte> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format8(format, TraceLoggingDataType.UInt8)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref Byte value) - { - collector.AddScalar(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for SByte. - /// </summary> - internal sealed class SByteTypeInfo - : TraceLoggingTypeInfo<SByte> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format8(format, TraceLoggingDataType.Int8)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref SByte value) - { - collector.AddScalar(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for Int16. - /// </summary> - internal sealed class Int16TypeInfo - : TraceLoggingTypeInfo<Int16> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format16(format, TraceLoggingDataType.Int16)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref Int16 value) - { - collector.AddScalar(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for UInt16. - /// </summary> - internal sealed class UInt16TypeInfo - : TraceLoggingTypeInfo<UInt16> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format16(format, TraceLoggingDataType.UInt16)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref UInt16 value) - { - collector.AddScalar(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for Int32. - /// </summary> - internal sealed class Int32TypeInfo - : TraceLoggingTypeInfo<Int32> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format32(format, TraceLoggingDataType.Int32)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref Int32 value) - { - collector.AddScalar(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for UInt32. - /// </summary> - internal sealed class UInt32TypeInfo - : TraceLoggingTypeInfo<UInt32> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format32(format, TraceLoggingDataType.UInt32)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref UInt32 value) - { - collector.AddScalar(value); - } - } - /// <summary> - /// TraceLogging: Type handler for Int64. + /// Type handler for simple scalar types. /// </summary> - internal sealed class Int64TypeInfo - : TraceLoggingTypeInfo<Int64> + sealed class ScalarTypeInfo : TraceLoggingTypeInfo { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format64(format, TraceLoggingDataType.Int64)); - } + Func<EventFieldFormat, TraceLoggingDataType, TraceLoggingDataType> formatFunc; + TraceLoggingDataType nativeFormat; - public override void WriteData(TraceLoggingDataCollector collector, ref Int64 value) - { - collector.AddScalar(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for UInt64. - /// </summary> - internal sealed class UInt64TypeInfo - : TraceLoggingTypeInfo<UInt64> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) + private ScalarTypeInfo( + Type type, + Func<EventFieldFormat, TraceLoggingDataType, TraceLoggingDataType> formatFunc, + TraceLoggingDataType nativeFormat) + : base(type) { - collector.AddScalar(name, Statics.Format64(format, TraceLoggingDataType.UInt64)); + this.formatFunc = formatFunc; + this.nativeFormat = nativeFormat; } - public override void WriteData(TraceLoggingDataCollector collector, ref UInt64 value) - { - collector.AddScalar(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for IntPtr. - /// </summary> - internal sealed class IntPtrTypeInfo - : TraceLoggingTypeInfo<IntPtr> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.FormatPtr(format, Statics.IntPtrType)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref IntPtr value) - { - collector.AddScalar(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for UIntPtr. - /// </summary> - internal sealed class UIntPtrTypeInfo - : TraceLoggingTypeInfo<UIntPtr> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.FormatPtr(format, Statics.UIntPtrType)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref UIntPtr value) - { - collector.AddScalar(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for Double. - /// </summary> - internal sealed class DoubleTypeInfo - : TraceLoggingTypeInfo<Double> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format64(format, TraceLoggingDataType.Double)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref Double value) - { - collector.AddScalar(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for Single. - /// </summary> - internal sealed class SingleTypeInfo - : TraceLoggingTypeInfo<Single> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format32(format, TraceLoggingDataType.Float)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref Single value) - { - collector.AddScalar(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for Char. - /// </summary> - internal sealed class CharTypeInfo - : TraceLoggingTypeInfo<Char> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) + public override void WriteMetadata(TraceLoggingMetadataCollector collector, string name, EventFieldFormat format) { - collector.AddScalar(name, Statics.Format16(format, TraceLoggingDataType.Char16)); + collector.AddScalar(name, formatFunc(format, nativeFormat)); } - public override void WriteData(TraceLoggingDataCollector collector, ref Char value) + public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value) { collector.AddScalar(value); } - } - - #endregion - - #region Primitive arrays - - /// <summary> - /// TraceLogging: Type handler for Boolean[]. - /// </summary> - internal sealed class BooleanArrayTypeInfo - : TraceLoggingTypeInfo<Boolean[]> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddArray(name, Statics.Format8(format, TraceLoggingDataType.Boolean8)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref Boolean[] value) - { - collector.AddArray(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for Byte[]. - /// </summary> - internal sealed class ByteArrayTypeInfo - : TraceLoggingTypeInfo<Byte[]> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - switch (format) - { - default: - collector.AddBinary(name, Statics.MakeDataType(TraceLoggingDataType.Binary, format)); - break; - case EventFieldFormat.String: - collector.AddBinary(name, TraceLoggingDataType.CountedMbcsString); - break; - case EventFieldFormat.Xml: - collector.AddBinary(name, TraceLoggingDataType.CountedMbcsXml); - break; - case EventFieldFormat.Json: - collector.AddBinary(name, TraceLoggingDataType.CountedMbcsJson); - break; - case EventFieldFormat.Boolean: - collector.AddArray(name, TraceLoggingDataType.Boolean8); - break; - case EventFieldFormat.Hexadecimal: - collector.AddArray(name, TraceLoggingDataType.HexInt8); - break; -#if false - case EventSourceFieldFormat.Signed: - collector.AddArray(name, TraceLoggingDataType.Int8); - break; - case EventSourceFieldFormat.Unsigned: - collector.AddArray(name, TraceLoggingDataType.UInt8); - break; -#endif - } - } - - public override void WriteData(TraceLoggingDataCollector collector, ref Byte[] value) - { - collector.AddBinary(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for SByte[]. - /// </summary> - internal sealed class SByteArrayTypeInfo - : TraceLoggingTypeInfo<SByte[]> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddArray(name, Statics.Format8(format, TraceLoggingDataType.Int8)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref SByte[] value) - { - collector.AddArray(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for Int16[]. - /// </summary> - internal sealed class Int16ArrayTypeInfo - : TraceLoggingTypeInfo<Int16[]> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddArray(name, Statics.Format16(format, TraceLoggingDataType.Int16)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref Int16[] value) - { - collector.AddArray(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for UInt16[]. - /// </summary> - internal sealed class UInt16ArrayTypeInfo - : TraceLoggingTypeInfo<UInt16[]> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddArray(name, Statics.Format16(format, TraceLoggingDataType.UInt16)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref UInt16[] value) - { - collector.AddArray(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for Int32[]. - /// </summary> - internal sealed class Int32ArrayTypeInfo - : TraceLoggingTypeInfo<Int32[]> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddArray(name, Statics.Format32(format, TraceLoggingDataType.Int32)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref Int32[] value) - { - collector.AddArray(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for UInt32[]. - /// </summary> - internal sealed class UInt32ArrayTypeInfo - : TraceLoggingTypeInfo<UInt32[]> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddArray(name, Statics.Format32(format, TraceLoggingDataType.UInt32)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref UInt32[] value) - { - collector.AddArray(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for Int64[]. - /// </summary> - internal sealed class Int64ArrayTypeInfo - : TraceLoggingTypeInfo<Int64[]> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddArray(name, Statics.Format64(format, TraceLoggingDataType.Int64)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref Int64[] value) - { - collector.AddArray(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for UInt64[]. - /// </summary> - internal sealed class UInt64ArrayTypeInfo - : TraceLoggingTypeInfo<UInt64[]> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddArray(name, Statics.Format64(format, TraceLoggingDataType.UInt64)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref UInt64[] value) - { - collector.AddArray(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for IntPtr[]. - /// </summary> - internal sealed class IntPtrArrayTypeInfo - : TraceLoggingTypeInfo<IntPtr[]> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddArray(name, Statics.FormatPtr(format, Statics.IntPtrType)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref IntPtr[] value) - { - collector.AddArray(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for UIntPtr[]. - /// </summary> - internal sealed class UIntPtrArrayTypeInfo - : TraceLoggingTypeInfo<UIntPtr[]> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddArray(name, Statics.FormatPtr(format, Statics.UIntPtrType)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref UIntPtr[] value) - { - collector.AddArray(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for Char[]. - /// </summary> - internal sealed class CharArrayTypeInfo - : TraceLoggingTypeInfo<Char[]> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddArray(name, Statics.Format16(format, TraceLoggingDataType.Char16)); - } - public override void WriteData(TraceLoggingDataCollector collector, ref Char[] value) - { - collector.AddArray(value); - } + public static TraceLoggingTypeInfo Boolean() { return new ScalarTypeInfo(typeof(Boolean), Statics.Format8, TraceLoggingDataType.Boolean8); } + public static TraceLoggingTypeInfo Byte() { return new ScalarTypeInfo(typeof(Byte), Statics.Format8, TraceLoggingDataType.UInt8); } + public static TraceLoggingTypeInfo SByte() { return new ScalarTypeInfo(typeof(SByte), Statics.Format8, TraceLoggingDataType.Int8); } + public static TraceLoggingTypeInfo Char() { return new ScalarTypeInfo(typeof(Char), Statics.Format16, TraceLoggingDataType.Char16); } + public static TraceLoggingTypeInfo Int16() { return new ScalarTypeInfo(typeof(Int16), Statics.Format16, TraceLoggingDataType.Int16); } + public static TraceLoggingTypeInfo UInt16() { return new ScalarTypeInfo(typeof(UInt16), Statics.Format16, TraceLoggingDataType.UInt16); } + public static TraceLoggingTypeInfo Int32() { return new ScalarTypeInfo(typeof(Int32), Statics.Format32, TraceLoggingDataType.Int32); } + public static TraceLoggingTypeInfo UInt32() { return new ScalarTypeInfo(typeof(UInt32), Statics.Format32, TraceLoggingDataType.UInt32); } + public static TraceLoggingTypeInfo Int64() { return new ScalarTypeInfo(typeof(Int64), Statics.Format64, TraceLoggingDataType.Int64); } + public static TraceLoggingTypeInfo UInt64() { return new ScalarTypeInfo(typeof(UInt64), Statics.Format64, TraceLoggingDataType.UInt64); } + public static TraceLoggingTypeInfo IntPtr() { return new ScalarTypeInfo(typeof(IntPtr), Statics.FormatPtr, Statics.IntPtrType); } + public static TraceLoggingTypeInfo UIntPtr() { return new ScalarTypeInfo(typeof(UIntPtr), Statics.FormatPtr, Statics.UIntPtrType); } + public static TraceLoggingTypeInfo Single() { return new ScalarTypeInfo(typeof(Single), Statics.Format32, TraceLoggingDataType.Float); } + public static TraceLoggingTypeInfo Double() { return new ScalarTypeInfo(typeof(Double), Statics.Format64, TraceLoggingDataType.Double); } + public static TraceLoggingTypeInfo Guid() { return new ScalarTypeInfo(typeof(Guid), (f, t) => Statics.MakeDataType(TraceLoggingDataType.Guid, f), TraceLoggingDataType.Guid); } } - /// <summary> - /// TraceLogging: Type handler for Double[]. - /// </summary> - internal sealed class DoubleArrayTypeInfo - : TraceLoggingTypeInfo<Double[]> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddArray(name, Statics.Format64(format, TraceLoggingDataType.Double)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref Double[] value) - { - collector.AddArray(value); - } - } /// <summary> - /// TraceLogging: Type handler for Single[]. + /// Type handler for arrays of scalars /// </summary> - internal sealed class SingleArrayTypeInfo - : TraceLoggingTypeInfo<Single[]> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddArray(name, Statics.Format32(format, TraceLoggingDataType.Float)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref Single[] value) - { - collector.AddArray(value); - } - } - - #endregion - - #region Enum scalars - - internal sealed class EnumByteTypeInfo<EnumType> - : TraceLoggingTypeInfo<EnumType> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format8(format, TraceLoggingDataType.UInt8)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value) - { - collector.AddScalar(EnumHelper<Byte>.Cast(value)); - } - - public override object GetData(object value) - { - return value; - } - } - - internal sealed class EnumSByteTypeInfo<EnumType> - : TraceLoggingTypeInfo<EnumType> + internal sealed class ScalarArrayTypeInfo : TraceLoggingTypeInfo { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format8(format, TraceLoggingDataType.Int8)); - } + Func<EventFieldFormat, TraceLoggingDataType, TraceLoggingDataType> formatFunc; + TraceLoggingDataType nativeFormat; + int elementSize; - public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value) + private ScalarArrayTypeInfo( + Type type, + Func<EventFieldFormat, TraceLoggingDataType, TraceLoggingDataType> formatFunc, + TraceLoggingDataType nativeFormat, + int elementSize) + : base(type) { - collector.AddScalar(EnumHelper<SByte>.Cast(value)); + this.formatFunc = formatFunc; + this.nativeFormat = nativeFormat; + this.elementSize = elementSize; } - public override object GetData(object value) - { - return value; - } - } - - internal sealed class EnumInt16TypeInfo<EnumType> - : TraceLoggingTypeInfo<EnumType> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format16(format, TraceLoggingDataType.Int16)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value) - { - collector.AddScalar(EnumHelper<Int16>.Cast(value)); - } - - public override object GetData(object value) - { - return value; - } - } - - internal sealed class EnumUInt16TypeInfo<EnumType> - : TraceLoggingTypeInfo<EnumType> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format16(format, TraceLoggingDataType.UInt16)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value) - { - collector.AddScalar(EnumHelper<UInt16>.Cast(value)); - } - - public override object GetData(object value) - { - return value; - } - } - - internal sealed class EnumInt32TypeInfo<EnumType> - : TraceLoggingTypeInfo<EnumType> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format32(format, TraceLoggingDataType.Int32)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value) - { - collector.AddScalar(EnumHelper<Int32>.Cast(value)); - } - - public override object GetData(object value) - { - return value; - } - } - - internal sealed class EnumUInt32TypeInfo<EnumType> - : TraceLoggingTypeInfo<EnumType> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format32(format, TraceLoggingDataType.UInt32)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value) - { - collector.AddScalar(EnumHelper<UInt32>.Cast(value)); - } - - public override object GetData(object value) - { - return value; - } - } - - internal sealed class EnumInt64TypeInfo<EnumType> - : TraceLoggingTypeInfo<EnumType> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.Format64(format, TraceLoggingDataType.Int64)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value) - { - collector.AddScalar(EnumHelper<Int64>.Cast(value)); - } - - public override object GetData(object value) - { - return value; - } - } - - internal sealed class EnumUInt64TypeInfo<EnumType> - : TraceLoggingTypeInfo<EnumType> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) + public override void WriteMetadata(TraceLoggingMetadataCollector collector, string name, EventFieldFormat format) { - collector.AddScalar(name, Statics.Format64(format, TraceLoggingDataType.UInt64)); + collector.AddArray(name, formatFunc(format, nativeFormat)); } - public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value) + public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value) { - collector.AddScalar(EnumHelper<UInt64>.Cast(value)); + collector.AddArray(value, elementSize); } - public override object GetData(object value) - { - return value; - } + public static TraceLoggingTypeInfo Boolean() { return new ScalarArrayTypeInfo(typeof(Boolean[]), Statics.Format8, TraceLoggingDataType.Boolean8, sizeof(Boolean)); } + public static TraceLoggingTypeInfo Byte() { return new ScalarArrayTypeInfo(typeof(Byte[]), Statics.Format8, TraceLoggingDataType.UInt8, sizeof(Byte)); } + public static TraceLoggingTypeInfo SByte() { return new ScalarArrayTypeInfo(typeof(SByte[]), Statics.Format8, TraceLoggingDataType.Int8, sizeof(SByte)); } + public static TraceLoggingTypeInfo Char() { return new ScalarArrayTypeInfo(typeof(Char[]), Statics.Format16, TraceLoggingDataType.Char16, sizeof(Char)); } + public static TraceLoggingTypeInfo Int16() { return new ScalarArrayTypeInfo(typeof(Int16[]), Statics.Format16, TraceLoggingDataType.Int16, sizeof(Int16)); } + public static TraceLoggingTypeInfo UInt16() { return new ScalarArrayTypeInfo(typeof(UInt16[]), Statics.Format16, TraceLoggingDataType.UInt16, sizeof(UInt16)); } + public static TraceLoggingTypeInfo Int32() { return new ScalarArrayTypeInfo(typeof(Int32[]), Statics.Format32, TraceLoggingDataType.Int32, sizeof(Int32)); } + public static TraceLoggingTypeInfo UInt32() { return new ScalarArrayTypeInfo(typeof(UInt32[]), Statics.Format32, TraceLoggingDataType.UInt32, sizeof(UInt32)); } + public static TraceLoggingTypeInfo Int64() { return new ScalarArrayTypeInfo(typeof(Int64[]), Statics.Format64, TraceLoggingDataType.Int64, sizeof(Int64)); } + public static TraceLoggingTypeInfo UInt64() { return new ScalarArrayTypeInfo(typeof(UInt64[]), Statics.Format64, TraceLoggingDataType.UInt64, sizeof(UInt64)); } + public static TraceLoggingTypeInfo IntPtr() { return new ScalarArrayTypeInfo(typeof(IntPtr[]), Statics.FormatPtr, Statics.IntPtrType, System.IntPtr.Size); } + public static TraceLoggingTypeInfo UIntPtr() { return new ScalarArrayTypeInfo(typeof(UIntPtr[]), Statics.FormatPtr, Statics.UIntPtrType, System.IntPtr.Size); } + public static TraceLoggingTypeInfo Single() { return new ScalarArrayTypeInfo(typeof(Single[]), Statics.Format32, TraceLoggingDataType.Float, sizeof(Single)); } + public static TraceLoggingTypeInfo Double() { return new ScalarArrayTypeInfo(typeof(Double[]), Statics.Format64, TraceLoggingDataType.Double, sizeof(Double)); } + public unsafe static TraceLoggingTypeInfo Guid() { return new ScalarArrayTypeInfo(typeof(Guid), (f, t) => Statics.MakeDataType(TraceLoggingDataType.Guid, f), TraceLoggingDataType.Guid, sizeof(Guid)); } } - #endregion - - #region Other built-in types - /// <summary> /// TraceLogging: Type handler for String. /// </summary> - internal sealed class StringTypeInfo - : TraceLoggingTypeInfo<String> + internal sealed class StringTypeInfo : TraceLoggingTypeInfo { + public StringTypeInfo() : base(typeof(string)) { } + public override void WriteMetadata( TraceLoggingMetadataCollector collector, string name, @@ -832,67 +152,29 @@ namespace System.Diagnostics.Tracing collector.AddBinary(name, Statics.MakeDataType(TraceLoggingDataType.CountedUtf16String, format)); } - public override void WriteData(TraceLoggingDataCollector collector, ref String value) + public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value) { - collector.AddBinary(value); + collector.AddBinary((string)value.ReferenceValue); } public override object GetData(object value) { - object val = base.GetData(value); - if (null == val) - val = ""; - - return val; - } - } - - /// <summary> - /// TraceLogging: Type handler for Guid. - /// </summary> - internal sealed class GuidTypeInfo - : TraceLoggingTypeInfo<Guid> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.MakeDataType(TraceLoggingDataType.Guid, format)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref Guid value) - { - collector.AddScalar(value); - } - } - - /// <summary> - /// TraceLogging: Type handler for Guid[]. - /// </summary> - internal sealed class GuidArrayTypeInfo - : TraceLoggingTypeInfo<Guid[]> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddArray(name, Statics.MakeDataType(TraceLoggingDataType.Guid, format)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref Guid[] value) - { - collector.AddArray(value); + if(value == null) + { + return ""; + } + + return value; } } /// <summary> /// TraceLogging: Type handler for DateTime. /// </summary> - internal sealed class DateTimeTypeInfo - : TraceLoggingTypeInfo<DateTime> + internal sealed class DateTimeTypeInfo : TraceLoggingTypeInfo { + public DateTimeTypeInfo() : base(typeof(DateTime)) { } + public override void WriteMetadata( TraceLoggingMetadataCollector collector, string name, @@ -901,9 +183,9 @@ namespace System.Diagnostics.Tracing collector.AddScalar(name, Statics.MakeDataType(TraceLoggingDataType.FileTime, format)); } - public override void WriteData(TraceLoggingDataCollector collector, ref DateTime value) + public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value) { - var ticks = value.Ticks; + var ticks = value.ScalarValue.AsDateTime.Ticks; collector.AddScalar(ticks < 504911232000000000 ? 0 : ticks - 504911232000000000); } } @@ -911,9 +193,10 @@ namespace System.Diagnostics.Tracing /// <summary> /// TraceLogging: Type handler for DateTimeOffset. /// </summary> - internal sealed class DateTimeOffsetTypeInfo - : TraceLoggingTypeInfo<DateTimeOffset> + internal sealed class DateTimeOffsetTypeInfo : TraceLoggingTypeInfo { + public DateTimeOffsetTypeInfo() : base(typeof(DateTimeOffset)) { } + public override void WriteMetadata(TraceLoggingMetadataCollector collector, string name, EventFieldFormat format) { var group = collector.AddGroup(name); @@ -921,20 +204,22 @@ namespace System.Diagnostics.Tracing group.AddScalar("Offset", TraceLoggingDataType.Int64); } - public override void WriteData(TraceLoggingDataCollector collector, ref DateTimeOffset value) + public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value) { - var ticks = value.Ticks; + var dateTimeOffset = value.ScalarValue.AsDateTimeOffset; + var ticks = dateTimeOffset.Ticks; collector.AddScalar(ticks < 504911232000000000 ? 0 : ticks - 504911232000000000); - collector.AddScalar(value.Offset.Ticks); + collector.AddScalar(dateTimeOffset.Offset.Ticks); } } /// <summary> /// TraceLogging: Type handler for TimeSpan. /// </summary> - internal sealed class TimeSpanTypeInfo - : TraceLoggingTypeInfo<TimeSpan> + internal sealed class TimeSpanTypeInfo : TraceLoggingTypeInfo { + public TimeSpanTypeInfo() : base(typeof(TimeSpan)) { } + public override void WriteMetadata( TraceLoggingMetadataCollector collector, string name, @@ -943,92 +228,50 @@ namespace System.Diagnostics.Tracing collector.AddScalar(name, Statics.MakeDataType(TraceLoggingDataType.Int64, format)); } - public override void WriteData(TraceLoggingDataCollector collector, ref TimeSpan value) + public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value) { - collector.AddScalar(value.Ticks); + collector.AddScalar(value.ScalarValue.AsTimeSpan.Ticks); } } /// <summary> /// TraceLogging: Type handler for Decimal. (Note: not full-fidelity, exposed as Double.) /// </summary> - internal sealed class DecimalTypeInfo - : TraceLoggingTypeInfo<Decimal> - { - public override void WriteMetadata( - TraceLoggingMetadataCollector collector, - string name, - EventFieldFormat format) - { - collector.AddScalar(name, Statics.MakeDataType(TraceLoggingDataType.Double, format)); - } - - public override void WriteData(TraceLoggingDataCollector collector, ref decimal value) - { - collector.AddScalar((double)value); - } - } - - /// <summary> - /// TraceLogging: Type handler for KeyValuePair. - /// </summary> - /// <typeparam name="K">Type of the KeyValuePair's Key property.</typeparam> - /// <typeparam name="V">Type of the KeyValuePair's Value property.</typeparam> - internal sealed class KeyValuePairTypeInfo<K, V> - : TraceLoggingTypeInfo<KeyValuePair<K, V>> + internal sealed class DecimalTypeInfo : TraceLoggingTypeInfo { - private readonly TraceLoggingTypeInfo<K> keyInfo; - private readonly TraceLoggingTypeInfo<V> valueInfo; - - public KeyValuePairTypeInfo(List<Type> recursionCheck) - { - this.keyInfo = TraceLoggingTypeInfo<K>.GetInstance(recursionCheck); - this.valueInfo = TraceLoggingTypeInfo<V>.GetInstance(recursionCheck); - } + public DecimalTypeInfo() : base(typeof(Decimal)) { } public override void WriteMetadata( TraceLoggingMetadataCollector collector, string name, EventFieldFormat format) { - var group = collector.AddGroup(name); - this.keyInfo.WriteMetadata(group, "Key", EventFieldFormat.Default); - this.valueInfo.WriteMetadata(group, "Value", format); - } - - public override void WriteData( - TraceLoggingDataCollector collector, - ref KeyValuePair<K, V> value) - { - var key = value.Key; - var val = value.Value; - this.keyInfo.WriteData(collector, ref key); - this.valueInfo.WriteData(collector, ref val); + collector.AddScalar(name, Statics.MakeDataType(TraceLoggingDataType.Double, format)); } - public override object GetData(object value) + public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value) { - var serializedType = new Dictionary<string, object>(); - var keyValuePair = (KeyValuePair<K, V>) value; - serializedType.Add("Key", this.keyInfo.GetData(keyValuePair.Key)); - serializedType.Add("Value", this.valueInfo.GetData(keyValuePair.Value)); - return serializedType; + collector.AddScalar((double)value.ScalarValue.AsDecimal); } } /// <summary> /// TraceLogging: Type handler for Nullable. /// </summary> - /// <typeparam name="T">Type of the Nullable's Value property.</typeparam> - internal sealed class NullableTypeInfo<T> - : TraceLoggingTypeInfo<Nullable<T>> - where T : struct + internal sealed class NullableTypeInfo : TraceLoggingTypeInfo { - private readonly TraceLoggingTypeInfo<T> valueInfo; + private readonly TraceLoggingTypeInfo valueInfo; + private readonly Func<PropertyValue, PropertyValue> hasValueGetter; + private readonly Func<PropertyValue, PropertyValue> valueGetter; - public NullableTypeInfo(List<Type> recursionCheck) + public NullableTypeInfo(Type type, List<Type> recursionCheck) + : base(type) { - this.valueInfo = TraceLoggingTypeInfo<T>.GetInstance(recursionCheck); + var typeArgs = type.GenericTypeArguments; + Contract.Assert(typeArgs.Length == 1); + this.valueInfo = TraceLoggingTypeInfo.GetInstance(typeArgs[0], recursionCheck); + this.hasValueGetter = PropertyValue.GetPropertyGetter(type.GetTypeInfo().GetDeclaredProperty("HasValue")); + this.valueGetter = PropertyValue.GetPropertyGetter(type.GetTypeInfo().GetDeclaredProperty("Value")); } public override void WriteMetadata( @@ -1041,16 +284,12 @@ namespace System.Diagnostics.Tracing this.valueInfo.WriteMetadata(group, "Value", format); } - public override void WriteData( - TraceLoggingDataCollector collector, - ref Nullable<T> value) + public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value) { - var hasValue = value.HasValue; + var hasValue = hasValueGetter(value); collector.AddScalar(hasValue); - var val = hasValue ? value.Value : default(T); - this.valueInfo.WriteData(collector, ref val); + var val = hasValue.ScalarValue.AsBoolean ? valueGetter(value) : valueInfo.PropertyValueFactory(Activator.CreateInstance(valueInfo.DataType)); + this.valueInfo.WriteData(collector, val); } } - - #endregion } diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/Statics.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/Statics.cs index 8897ae2219..af6a43f811 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/Statics.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/Statics.cs @@ -7,6 +7,8 @@ using System.Reflection; using System.Runtime.CompilerServices; using Encoding = System.Text.Encoding; +using Microsoft.Reflection; + #if ES_BUILD_STANDALONE using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment; namespace Microsoft.Diagnostics.Tracing @@ -213,7 +215,7 @@ namespace System.Diagnostics.Tracing return TraceLoggingDataType.Int8; case EventSourceFieldFormat.Unsigned: return TraceLoggingDataType.UInt8; -#endif +#endif default: return MakeDataType(native, format); } @@ -343,7 +345,7 @@ namespace System.Diagnostics.Tracing return IntPtrType; case EventSourceFieldFormat.Unsigned: return UIntPtrType; -#endif +#endif default: return MakeDataType(native, format); } @@ -366,52 +368,32 @@ namespace System.Diagnostics.Tracing public static bool IsValueType(Type type) { - bool result; -#if ES_BUILD_PCL - result = type.GetTypeInfo().IsValueType; -#else - result = type.IsValueType; -#endif + bool result = type.IsValueType(); return result; } public static bool IsEnum(Type type) { - bool result; -#if ES_BUILD_PCL - result = type.GetTypeInfo().IsEnum; -#else - result = type.IsEnum; -#endif + bool result = type.IsEnum(); return result; } public static IEnumerable<PropertyInfo> GetProperties(Type type) { - IEnumerable<PropertyInfo> result; -#if ES_BUILD_PCL - result = type.GetRuntimeProperties(); -#else - result = type.GetProperties(); -#endif + IEnumerable<PropertyInfo> result = type.GetProperties(); return result; } public static MethodInfo GetGetMethod(PropertyInfo propInfo) { - MethodInfo result; -#if ES_BUILD_PCL - result = propInfo.GetMethod; -#else - result = propInfo.GetGetMethod(); -#endif + MethodInfo result = propInfo.GetGetMethod(); return result; } public static MethodInfo GetDeclaredStaticMethod(Type declaringType, string name) { MethodInfo result; -#if ES_BUILD_PCL +#if (ES_BUILD_PCL || PROJECTN) result = declaringType.GetTypeInfo().GetDeclaredMethod(name); #else result = declaringType.GetMethod( @@ -426,7 +408,7 @@ namespace System.Diagnostics.Tracing Type attributeType) { bool result; -#if ES_BUILD_PCL +#if (ES_BUILD_PCL || PROJECTN) result = propInfo.IsDefined(attributeType); #else var attributes = propInfo.GetCustomAttributes( @@ -441,7 +423,7 @@ namespace System.Diagnostics.Tracing where AttributeType : Attribute { AttributeType result = null; -#if ES_BUILD_PCL +#if (ES_BUILD_PCL || PROJECTN) foreach (var attrib in propInfo.GetCustomAttributes<AttributeType>(false)) { result = attrib; @@ -461,7 +443,7 @@ namespace System.Diagnostics.Tracing where AttributeType : Attribute { AttributeType result = null; -#if ES_BUILD_PCL +#if (ES_BUILD_PCL || PROJECTN) foreach (var attrib in type.GetTypeInfo().GetCustomAttributes<AttributeType>(false)) { result = attrib; @@ -479,11 +461,7 @@ namespace System.Diagnostics.Tracing public static Type[] GetGenericArguments(Type type) { -#if ES_BUILD_PCL - return type.GenericTypeArguments; -#else return type.GetGenericArguments(); -#endif } public static Type FindEnumerableElementType(Type type) @@ -496,19 +474,19 @@ namespace System.Diagnostics.Tracing } else { -#if ES_BUILD_PCL - var ifaceTypes = type.GetTypeInfo().ImplementedInterfaces; +#if (ES_BUILD_PCL || PROJECTN) + var ifaceTypes = type.GetTypeInfo().ImplementedInterfaces; #else var ifaceTypes = type.FindInterfaces(IsGenericMatch, typeof(IEnumerable<>)); #endif foreach (var ifaceType in ifaceTypes) { -#if ES_BUILD_PCL - if (!IsGenericMatch(ifaceType, typeof(IEnumerable<>))) - { - continue; - } +#if (ES_BUILD_PCL || PROJECTN) + if (!IsGenericMatch(ifaceType, typeof(IEnumerable<>))) + { + continue; + } #endif if (elementType != null) @@ -527,19 +505,13 @@ namespace System.Diagnostics.Tracing public static bool IsGenericMatch(Type type, object openType) { - bool isGeneric; -#if ES_BUILD_PCL - isGeneric = type.IsConstructedGenericType; -#else - isGeneric = type.IsGenericType; -#endif - return isGeneric && type.GetGenericTypeDefinition() == (Type)openType; + return type.IsGenericType() && type.GetGenericTypeDefinition() == (Type)openType; } public static Delegate CreateDelegate(Type delegateType, MethodInfo methodInfo) { Delegate result; -#if ES_BUILD_PCL +#if (ES_BUILD_PCL || PROJECTN) result = methodInfo.CreateDelegate( delegateType); #else @@ -550,279 +522,203 @@ namespace System.Diagnostics.Tracing return result; } - public static TraceLoggingTypeInfo GetTypeInfoInstance(Type dataType, List<Type> recursionCheck) - { - TraceLoggingTypeInfo result; - - if (dataType == typeof(Int32)) - { - result = TraceLoggingTypeInfo<Int32>.Instance; - } - else if (dataType == typeof(Int64)) - { - result = TraceLoggingTypeInfo<Int64>.Instance; - } - else if (dataType == typeof(String)) - { - result = TraceLoggingTypeInfo<String>.Instance; - } - else - { - var getInstanceInfo = Statics.GetDeclaredStaticMethod( - typeof(TraceLoggingTypeInfo<>).MakeGenericType(dataType), - "GetInstance"); - var typeInfoObj = getInstanceInfo.Invoke(null, new object[] { recursionCheck }); - result = (TraceLoggingTypeInfo)typeInfoObj; - } - - return result; - } - - public static TraceLoggingTypeInfo<DataType> CreateDefaultTypeInfo<DataType>( + public static TraceLoggingTypeInfo CreateDefaultTypeInfo( + Type dataType, List<Type> recursionCheck) { TraceLoggingTypeInfo result; - var dataType = typeof(DataType); if (recursionCheck.Contains(dataType)) { - throw new NotSupportedException(Environment.GetResourceString("EventSource_RecursiveTypeDefinition")); + throw new NotSupportedException(Resources.GetResourceString("EventSource_RecursiveTypeDefinition")); } recursionCheck.Add(dataType); var eventAttrib = Statics.GetCustomAttribute<EventDataAttribute>(dataType); if (eventAttrib != null || - Statics.GetCustomAttribute<CompilerGeneratedAttribute>(dataType) != null) + Statics.GetCustomAttribute<CompilerGeneratedAttribute>(dataType) != null || + IsGenericMatch(dataType, typeof(KeyValuePair<,>))) { var analysis = new TypeAnalysis(dataType, eventAttrib, recursionCheck); - result = new InvokeTypeInfo<DataType>(analysis); + result = new InvokeTypeInfo(dataType, analysis); } else if (dataType.IsArray) { var elementType = dataType.GetElementType(); if (elementType == typeof(Boolean)) { - result = new BooleanArrayTypeInfo(); + result = ScalarArrayTypeInfo.Boolean(); } else if (elementType == typeof(Byte)) { - result = new ByteArrayTypeInfo(); + result = ScalarArrayTypeInfo.Byte(); } else if (elementType == typeof(SByte)) { - result = new SByteArrayTypeInfo(); + result = ScalarArrayTypeInfo.SByte(); } else if (elementType == typeof(Int16)) { - result = new Int16ArrayTypeInfo(); + result = ScalarArrayTypeInfo.Int16(); } else if (elementType == typeof(UInt16)) { - result = new UInt16ArrayTypeInfo(); + result = ScalarArrayTypeInfo.UInt16(); } else if (elementType == typeof(Int32)) { - result = new Int32ArrayTypeInfo(); + result = ScalarArrayTypeInfo.Int32(); } else if (elementType == typeof(UInt32)) { - result = new UInt32ArrayTypeInfo(); + result = ScalarArrayTypeInfo.UInt32(); } else if (elementType == typeof(Int64)) { - result = new Int64ArrayTypeInfo(); + result = ScalarArrayTypeInfo.Int64(); } else if (elementType == typeof(UInt64)) { - result = new UInt64ArrayTypeInfo(); + result = ScalarArrayTypeInfo.UInt64(); } else if (elementType == typeof(Char)) { - result = new CharArrayTypeInfo(); + result = ScalarArrayTypeInfo.Char(); } else if (elementType == typeof(Double)) { - result = new DoubleArrayTypeInfo(); + result = ScalarArrayTypeInfo.Double(); } else if (elementType == typeof(Single)) { - result = new SingleArrayTypeInfo(); + result = ScalarArrayTypeInfo.Single(); } else if (elementType == typeof(IntPtr)) { - result = new IntPtrArrayTypeInfo(); + result = ScalarArrayTypeInfo.IntPtr(); } else if (elementType == typeof(UIntPtr)) { - result = new UIntPtrArrayTypeInfo(); + result = ScalarArrayTypeInfo.UIntPtr(); } else if (elementType == typeof(Guid)) { - result = new GuidArrayTypeInfo(); + result = ScalarArrayTypeInfo.Guid(); } else { - result = (TraceLoggingTypeInfo<DataType>)CreateInstance( - typeof(ArrayTypeInfo<>).MakeGenericType(elementType), - GetTypeInfoInstance(elementType, recursionCheck)); + result = new ArrayTypeInfo(dataType, TraceLoggingTypeInfo.GetInstance(elementType, recursionCheck)); } } - else if (Statics.IsEnum(dataType)) + else { - var underlyingType = Enum.GetUnderlyingType(dataType); - if (underlyingType == typeof(Int32)) + if (Statics.IsEnum(dataType)) + dataType = Enum.GetUnderlyingType(dataType); + + if (dataType == typeof(String)) { - result = new EnumInt32TypeInfo<DataType>(); + result = new StringTypeInfo(); } - else if (underlyingType == typeof(UInt32)) + else if (dataType == typeof(Boolean)) { - result = new EnumUInt32TypeInfo<DataType>(); + result = ScalarTypeInfo.Boolean(); } - else if (underlyingType == typeof(Byte)) + else if (dataType == typeof(Byte)) { - result = new EnumByteTypeInfo<DataType>(); + result = ScalarTypeInfo.Byte(); } - else if (underlyingType == typeof(SByte)) + else if (dataType == typeof(SByte)) { - result = new EnumSByteTypeInfo<DataType>(); + result = ScalarTypeInfo.SByte(); } - else if (underlyingType == typeof(Int16)) + else if (dataType == typeof(Int16)) { - result = new EnumInt16TypeInfo<DataType>(); + result = ScalarTypeInfo.Int16(); } - else if (underlyingType == typeof(UInt16)) + else if (dataType == typeof(UInt16)) { - result = new EnumUInt16TypeInfo<DataType>(); + result = ScalarTypeInfo.UInt16(); } - else if (underlyingType == typeof(Int64)) + else if (dataType == typeof(Int32)) { - result = new EnumInt64TypeInfo<DataType>(); + result = ScalarTypeInfo.Int32(); } - else if (underlyingType == typeof(UInt64)) + else if (dataType == typeof(UInt32)) { - result = new EnumUInt64TypeInfo<DataType>(); + result = ScalarTypeInfo.UInt32(); } - else + else if (dataType == typeof(Int64)) { - // Unexpected - throw new NotSupportedException(Environment.GetResourceString("EventSource_NotSupportedEnumType", dataType.Name, underlyingType.Name)); + result = ScalarTypeInfo.Int64(); } - } - else if (dataType == typeof(String)) - { - result = new StringTypeInfo(); - } - else if (dataType == typeof(Boolean)) - { - result = new BooleanTypeInfo(); - } - else if (dataType == typeof(Byte)) - { - result = new ByteTypeInfo(); - } - else if (dataType == typeof(SByte)) - { - result = new SByteTypeInfo(); - } - else if (dataType == typeof(Int16)) - { - result = new Int16TypeInfo(); - } - else if (dataType == typeof(UInt16)) - { - result = new UInt16TypeInfo(); - } - else if (dataType == typeof(Int32)) - { - result = new Int32TypeInfo(); - } - else if (dataType == typeof(UInt32)) - { - result = new UInt32TypeInfo(); - } - else if (dataType == typeof(Int64)) - { - result = new Int64TypeInfo(); - } - else if (dataType == typeof(UInt64)) - { - result = new UInt64TypeInfo(); - } - else if (dataType == typeof(Char)) - { - result = new CharTypeInfo(); - } - else if (dataType == typeof(Double)) - { - result = new DoubleTypeInfo(); - } - else if (dataType == typeof(Single)) - { - result = new SingleTypeInfo(); - } - else if (dataType == typeof(DateTime)) - { - result = new DateTimeTypeInfo(); - } - else if (dataType == typeof(Decimal)) - { - result = new DecimalTypeInfo(); - } - else if (dataType == typeof(IntPtr)) - { - result = new IntPtrTypeInfo(); - } - else if (dataType == typeof(UIntPtr)) - { - result = new UIntPtrTypeInfo(); - } - else if (dataType == typeof(Guid)) - { - result = new GuidTypeInfo(); - } - else if (dataType == typeof(TimeSpan)) - { - result = new TimeSpanTypeInfo(); - } - else if (dataType == typeof(DateTimeOffset)) - { - result = new DateTimeOffsetTypeInfo(); - } - else if (dataType == typeof(EmptyStruct)) - { - result = new NullTypeInfo<EmptyStruct>(); - } - else if (IsGenericMatch(dataType, typeof(KeyValuePair<,>))) - { - var args = GetGenericArguments(dataType); - result = (TraceLoggingTypeInfo<DataType>)CreateInstance( - typeof(KeyValuePairTypeInfo<,>).MakeGenericType(args[0], args[1]), - recursionCheck); - } - else if (IsGenericMatch(dataType, typeof(Nullable<>))) - { - var args = GetGenericArguments(dataType); - result = (TraceLoggingTypeInfo<DataType>)CreateInstance( - typeof(NullableTypeInfo<>).MakeGenericType(args[0]), - recursionCheck); - } - else - { - var elementType = FindEnumerableElementType(dataType); - if (elementType != null) + else if (dataType == typeof(UInt64)) { - result = (TraceLoggingTypeInfo<DataType>)CreateInstance( - typeof(EnumerableTypeInfo<,>).MakeGenericType(dataType, elementType), - GetTypeInfoInstance(elementType, recursionCheck)); + result = ScalarTypeInfo.UInt64(); + } + else if (dataType == typeof(Char)) + { + result = ScalarTypeInfo.Char(); + } + else if (dataType == typeof(Double)) + { + result = ScalarTypeInfo.Double(); + } + else if (dataType == typeof(Single)) + { + result = ScalarTypeInfo.Single(); + } + else if (dataType == typeof(DateTime)) + { + result = new DateTimeTypeInfo(); + } + else if (dataType == typeof(Decimal)) + { + result = new DecimalTypeInfo(); + } + else if (dataType == typeof(IntPtr)) + { + result = ScalarTypeInfo.IntPtr(); + } + else if (dataType == typeof(UIntPtr)) + { + result = ScalarTypeInfo.UIntPtr(); + } + else if (dataType == typeof(Guid)) + { + result = ScalarTypeInfo.Guid(); + } + else if (dataType == typeof(TimeSpan)) + { + result = new TimeSpanTypeInfo(); + } + else if (dataType == typeof(DateTimeOffset)) + { + result = new DateTimeOffsetTypeInfo(); + } + else if (dataType == typeof(EmptyStruct)) + { + result = new NullTypeInfo(); + } + else if (IsGenericMatch(dataType, typeof(Nullable<>))) + { + result = new NullableTypeInfo(dataType, recursionCheck); } else { - throw new ArgumentException(Environment.GetResourceString("EventSource_NonCompliantTypeError", dataType.Name)); + var elementType = FindEnumerableElementType(dataType); + if (elementType != null) + { + result = new EnumerableTypeInfo(dataType, TraceLoggingTypeInfo.GetInstance(elementType, recursionCheck)); + } + else + { + throw new ArgumentException(Resources.GetResourceString("EventSource_NonCompliantTypeError", dataType.Name)); + } } } - return (TraceLoggingTypeInfo<DataType>)result; + return result; } #endregion diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingDataCollector.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingDataCollector.cs index 2ac1df17fd..6a805d951d 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingDataCollector.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingDataCollector.cs @@ -60,70 +60,10 @@ namespace System.Diagnostics.Tracing return this; } - /// <summary> - /// Adds a Boolean value to the event payload. - /// </summary> - /// <param name="value">Value to be added.</param> - public void AddScalar(bool value) - { - DataCollector.ThreadInstance.AddScalar(&value, sizeof(bool)); - } - - /// <summary> - /// Adds an SByte value to the event payload. - /// </summary> - /// <param name="value">Value to be added.</param> - //[CLSCompliant(false)] - public void AddScalar(sbyte value) - { - DataCollector.ThreadInstance.AddScalar(&value, sizeof(sbyte)); - } - - /// <summary> - /// Adds a Byte value to the event payload. - /// </summary> - /// <param name="value">Value to be added.</param> - public void AddScalar(byte value) - { - DataCollector.ThreadInstance.AddScalar(&value, sizeof(byte)); - } - - /// <summary> - /// Adds an Int16 value to the event payload. - /// </summary> - /// <param name="value">Value to be added.</param> - public void AddScalar(short value) - { - DataCollector.ThreadInstance.AddScalar(&value, sizeof(short)); - } - - /// <summary> - /// Adds a UInt16 value to the event payload. - /// </summary> - /// <param name="value">Value to be added.</param> - //[CLSCompliant(false)] - public void AddScalar(ushort value) - { - DataCollector.ThreadInstance.AddScalar(&value, sizeof(ushort)); - } - - /// <summary> - /// Adds an Int32 value to the event payload. - /// </summary> - /// <param name="value">Value to be added.</param> - public void AddScalar(int value) + public void AddScalar(PropertyValue value) { - DataCollector.ThreadInstance.AddScalar(&value, sizeof(int)); - } - - /// <summary> - /// Adds a UInt32 value to the event payload. - /// </summary> - /// <param name="value">Value to be added.</param> - //[CLSCompliant(false)] - public void AddScalar(uint value) - { - DataCollector.ThreadInstance.AddScalar(&value, sizeof(uint)); + var scalar = value.ScalarValue; + DataCollector.ThreadInstance.AddScalar(&scalar, value.ScalarLength); } /// <summary> @@ -136,44 +76,6 @@ namespace System.Diagnostics.Tracing } /// <summary> - /// Adds a UInt64 value to the event payload. - /// </summary> - /// <param name="value">Value to be added.</param> - //[CLSCompliant(false)] - public void AddScalar(ulong value) - { - DataCollector.ThreadInstance.AddScalar(&value, sizeof(ulong)); - } - - /// <summary> - /// Adds an IntPtr value to the event payload. - /// </summary> - /// <param name="value">Value to be added.</param> - public void AddScalar(IntPtr value) - { - DataCollector.ThreadInstance.AddScalar(&value, IntPtr.Size); - } - - /// <summary> - /// Adds a UIntPtr value to the event payload. - /// </summary> - /// <param name="value">Value to be added.</param> - //[CLSCompliant(false)] - public void AddScalar(UIntPtr value) - { - DataCollector.ThreadInstance.AddScalar(&value, UIntPtr.Size); - } - - /// <summary> - /// Adds a Single value to the event payload. - /// </summary> - /// <param name="value">Value to be added.</param> - public void AddScalar(float value) - { - DataCollector.ThreadInstance.AddScalar(&value, sizeof(float)); - } - - /// <summary> /// Adds a Double value to the event payload. /// </summary> /// <param name="value">Value to be added.</param> @@ -183,24 +85,6 @@ namespace System.Diagnostics.Tracing } /// <summary> - /// Adds a Char value to the event payload. - /// </summary> - /// <param name="value">Value to be added.</param> - public void AddScalar(char value) - { - DataCollector.ThreadInstance.AddScalar(&value, sizeof(char)); - } - - /// <summary> - /// Adds a Guid value to the event payload. - /// </summary> - /// <param name="value">Value to be added.</param> - public void AddScalar(Guid value) - { - DataCollector.ThreadInstance.AddScalar(&value, 16); - } - - /// <summary> /// Adds a counted String value to the event payload. /// </summary> /// <param name="value"> @@ -211,185 +95,10 @@ namespace System.Diagnostics.Tracing DataCollector.ThreadInstance.AddBinary(value, value == null ? 0 : value.Length * 2); } - /// <summary> - /// Adds an array of Byte values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - public void AddBinary(byte[] value) - { - DataCollector.ThreadInstance.AddBinary(value, value == null ? 0 : value.Length); - } - - /// <summary> - /// Adds an array of Boolean values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - public void AddArray(bool[] value) - { - DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(bool)); - } - - /// <summary> - /// Adds an array of SByte values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - //[CLSCompliant(false)] - public void AddArray(sbyte[] value) - { - DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(sbyte)); - } - - /// <summary> - /// Adds an array of Int16 values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - public void AddArray(short[] value) - { - DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(short)); - } - - /// <summary> - /// Adds an array of UInt16 values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - //[CLSCompliant(false)] - public void AddArray(ushort[] value) - { - DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(ushort)); - } - - /// <summary> - /// Adds an array of Int32 values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - public void AddArray(int[] value) - { - DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(int)); - } - - /// <summary> - /// Adds an array of UInt32 values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - //[CLSCompliant(false)] - public void AddArray(uint[] value) - { - DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(uint)); - } - - /// <summary> - /// Adds an array of Int64 values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - public void AddArray(long[] value) - { - DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(long)); - } - - /// <summary> - /// Adds an array of UInt64 values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - //[CLSCompliant(false)] - public void AddArray(ulong[] value) - { - DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(ulong)); - } - - /// <summary> - /// Adds an array of IntPtr values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - public void AddArray(IntPtr[] value) - { - DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, IntPtr.Size); - } - - /// <summary> - /// Adds an array of UIntPtr values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - //[CLSCompliant(false)] - public void AddArray(UIntPtr[] value) - { - DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, UIntPtr.Size); - } - - /// <summary> - /// Adds an array of Single values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - public void AddArray(float[] value) - { - DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(float)); - } - - /// <summary> - /// Adds an array of Double values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - public void AddArray(double[] value) - { - DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(double)); - } - - /// <summary> - /// Adds an array of Char values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - public void AddArray(char[] value) - { - DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(char)); - } - - /// <summary> - /// Adds an array of Guid values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - public void AddArray(Guid[] value) - { - DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, 16); - } - - /// <summary> - /// Adds an array of Byte values to the event payload. - /// </summary> - /// <param name="value"> - /// Value to be added. A null value is treated as a zero-length array. - /// </param> - public void AddCustom(byte[] value) + public void AddArray(PropertyValue value, int elementSize) { - DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(byte)); + Array array = (Array)value.ReferenceValue; + DataCollector.ThreadInstance.AddArray(array, array == null ? 0 : array.Length, elementSize); } } } diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventSource.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventSource.cs index 9dd3d8c035..366d615a85 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventSource.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventSource.cs @@ -17,6 +17,7 @@ #if ES_BUILD_STANDALONE using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment; +using EventDescriptor = Microsoft.Diagnostics.Tracing.EventDescriptor; #endif using System; @@ -120,8 +121,7 @@ namespace System.Diagnostics.Tracing } var options = new EventSourceOptions(); - var data = new EmptyStruct(); - this.WriteImpl(eventName, ref options, ref data, null, null); + this.WriteImpl(eventName, ref options, null, null, null, SimpleEventTypes<EmptyStruct>.Instance); } /// <summary> @@ -148,8 +148,7 @@ namespace System.Diagnostics.Tracing return; } - var data = new EmptyStruct(); - this.WriteImpl(eventName, ref options, ref data, null, null); + this.WriteImpl(eventName, ref options, null, null, null, SimpleEventTypes<EmptyStruct>.Instance); } /// <summary> @@ -182,7 +181,7 @@ namespace System.Diagnostics.Tracing } var options = new EventSourceOptions(); - this.WriteImpl(eventName, ref options, ref data, null, null); + this.WriteImpl(eventName, ref options, data, null, null, SimpleEventTypes<T>.Instance); } /// <summary> @@ -219,7 +218,7 @@ namespace System.Diagnostics.Tracing return; } - this.WriteImpl(eventName, ref options, ref data, null, null); + this.WriteImpl(eventName, ref options, data, null, null, SimpleEventTypes<T>.Instance); } /// <summary> @@ -258,7 +257,7 @@ namespace System.Diagnostics.Tracing return; } - this.WriteImpl(eventName, ref options, ref data, null, null); + this.WriteImpl(eventName, ref options, data, null, null, SimpleEventTypes<T>.Instance); } /// <summary> @@ -311,9 +310,10 @@ namespace System.Diagnostics.Tracing this.WriteImpl( eventName, ref options, - ref data, + data, pActivity, - relatedActivityId == Guid.Empty ? null : pRelated); + relatedActivityId == Guid.Empty ? null : pRelated, + SimpleEventTypes<T>.Instance); } } @@ -354,7 +354,7 @@ namespace System.Diagnostics.Tracing string eventName, ref EventSourceOptions options, TraceLoggingEventTypes eventTypes, - Guid* activityID, + Guid* activityID, Guid* childActivityID, params object[] values) { @@ -412,12 +412,12 @@ namespace System.Diagnostics.Tracing /// </param> [SecuritySafeCritical] private unsafe void WriteMultiMergeInner( - string eventName, - ref EventSourceOptions options, - TraceLoggingEventTypes eventTypes, - Guid* activityID, - Guid* childActivityID, - params object[] values) + string eventName, + ref EventSourceOptions options, + TraceLoggingEventTypes eventTypes, + Guid* activityID, + Guid* childActivityID, + params object[] values) { int identity = 0; byte level = (options.valuesSet & EventSourceOptions.levelSet) != 0 @@ -455,7 +455,7 @@ namespace System.Diagnostics.Tracing descriptors[1].SetMetadata(pMetadata1, nameInfo.nameMetadata.Length, 1); descriptors[2].SetMetadata(pMetadata2, eventTypes.typeMetadata.Length, 1); -#if !ES_BUILD_PCL +#if (!ES_BUILD_PCL && !PROJECTN) System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -470,10 +470,12 @@ namespace System.Diagnostics.Tracing for (int i = 0; i < eventTypes.typeInfos.Length; i++) { - eventTypes.typeInfos[i].WriteObjectData(TraceLoggingDataCollector.Instance, values[i]); + var info = eventTypes.typeInfos[i]; + info.WriteData(TraceLoggingDataCollector.Instance, info.PropertyValueFactory(values[i])); } this.WriteEventRaw( + eventName, ref descriptor, activityID, childActivityID, @@ -584,6 +586,7 @@ namespace System.Diagnostics.Tracing } this.WriteEventRaw( + eventName, ref descriptor, activityID, childActivityID, @@ -594,17 +597,16 @@ namespace System.Diagnostics.Tracing } [SecuritySafeCritical] - private unsafe void WriteImpl<T>( + private unsafe void WriteImpl( string eventName, ref EventSourceOptions options, - ref T data, + object data, Guid* pActivityId, - Guid* pRelatedActivityId) + Guid* pRelatedActivityId, + TraceLoggingEventTypes eventTypes) { try { - var eventTypes = SimpleEventTypes<T>.Instance; - fixed (EventSourceOptions* pOptions = &options) { EventDescriptor descriptor; @@ -629,7 +631,7 @@ namespace System.Diagnostics.Tracing descriptors[1].SetMetadata(pMetadata1, nameInfo.nameMetadata.Length, 1); descriptors[2].SetMetadata(pMetadata2, eventTypes.typeMetadata.Length, 1); -#if !ES_BUILD_PCL +#if (!ES_BUILD_PCL && !PROJECTN) System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); #endif EventOpcode opcode = (EventOpcode)descriptor.Opcode; @@ -663,9 +665,11 @@ namespace System.Diagnostics.Tracing pins, pinCount); - eventTypes.typeInfo.WriteData(TraceLoggingDataCollector.Instance, ref data); - + var info = eventTypes.typeInfos[0]; + info.WriteData(TraceLoggingDataCollector.Instance, info.PropertyValueFactory(data)); + this.WriteEventRaw( + eventName, ref descriptor, pActivityId, pRelatedActivityId, @@ -675,17 +679,17 @@ namespace System.Diagnostics.Tracing // TODO enable filtering for listeners. if (m_Dispatchers != null) { - var eventData = (EventPayload)(eventTypes.typeInfo.GetData(data)); + var eventData = (EventPayload)(eventTypes.typeInfos[0].GetData(data)); WriteToAllListeners(eventName, ref descriptor, nameInfo.tags, pActivityId, eventData); } } - catch(Exception ex) + catch (Exception ex) { if (ex is EventSourceException) throw; else - ThrowEventSourceException(ex); + ThrowEventSourceException(eventName, ex); } finally { @@ -699,7 +703,7 @@ namespace System.Diagnostics.Tracing if (ex is EventSourceException) throw; else - ThrowEventSourceException(ex); + ThrowEventSourceException(eventName, ex); } } @@ -727,7 +731,7 @@ namespace System.Diagnostics.Tracing DispatchToAllListeners(-1, pActivityId, eventCallbackArgs); } -#if !ES_BUILD_PCL +#if (!ES_BUILD_PCL && !PROJECTN) [System.Runtime.ConstrainedExecution.ReliabilityContract( System.Runtime.ConstrainedExecution.Consistency.WillNotCorruptState, System.Runtime.ConstrainedExecution.Cer.Success)] @@ -761,9 +765,13 @@ namespace System.Diagnostics.Tracing if (!byte.TryParse(etwTrait, out traitNum)) { if (etwTrait == "GROUP") + { traitNum = 1; + } else - throw new ArgumentException(Environment.GetResourceString("UnknownEtwTrait", etwTrait), "traits"); + { + throw new ArgumentException(Resources.GetResourceString("UnknownEtwTrait", etwTrait), "traits"); + } } string value = m_traits[i + 1]; int lenPos = traitMetaData.Count; @@ -776,7 +784,7 @@ namespace System.Diagnostics.Tracing } } providerMetadata = Statics.MetadataForString(this.Name, 0, traitMetaData.Count, 0); - int startPos = providerMetadata.Length-traitMetaData.Count; + int startPos = providerMetadata.Length - traitMetaData.Count; foreach (var b in traitMetaData) providerMetadata[startPos++] = b; } @@ -803,16 +811,22 @@ namespace System.Diagnostics.Tracing if (value[i] != ' ') // Skip spaces between bytes. { if (!(i + 1 < value.Length)) - throw new ArgumentException(Environment.GetResourceString("EvenHexDigits"), "traits"); + { + throw new ArgumentException(Resources.GetResourceString("EvenHexDigits"), "traits"); + } metaData.Add((byte)(HexDigit(value[i]) * 16 + HexDigit(value[i + 1]))); i++; } } } else if ('A' <= firstChar || ' ' == firstChar) // Is it alphabetic or space (excludes digits and most punctuation). + { metaData.AddRange(Encoding.UTF8.GetBytes(value)); + } else - throw new ArgumentException(Environment.GetResourceString("IllegalValue", value), "traits"); + { + throw new ArgumentException(Resources.GetResourceString("IllegalValue", value), "traits"); + } return metaData.Count - startPos; } @@ -823,12 +837,19 @@ namespace System.Diagnostics.Tracing private static int HexDigit(char c) { if ('0' <= c && c <= '9') + { return (c - '0'); + } if ('a' <= c) - c = unchecked((char) (c - ('a' - 'A'))); // Convert to lower case + { + c = unchecked((char)(c - ('a' - 'A'))); // Convert to lower case + } if ('A' <= c && c <= 'F') + { return (c - 'A' + 10); - throw new ArgumentException(Environment.GetResourceString("BadHexDigit", c), "traits"); + } + + throw new ArgumentException(Resources.GetResourceString("BadHexDigit", c), "traits"); } private NameInfo UpdateDescriptor( diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventTypes.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventTypes.cs index 06b840f7b7..39327f6786 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventTypes.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventTypes.cs @@ -21,7 +21,7 @@ namespace System.Diagnostics.Tracing /// TraceLogging: Used when calling EventSource.WriteMultiMerge. /// Stores the type information to use when writing the event fields. /// </summary> - internal class TraceLoggingEventTypes + public class TraceLoggingEventTypes { internal readonly TraceLoggingTypeInfo[] typeInfos; internal readonly string name; @@ -220,7 +220,7 @@ namespace System.Diagnostics.Tracing var result = new TraceLoggingTypeInfo[paramInfos.Length]; for (int i = 0; i < paramInfos.Length; ++i) { - result[i] = Statics.GetTypeInfoInstance(paramInfos[i].ParameterType, recursionCheck); + result[i] = TraceLoggingTypeInfo.GetInstance(paramInfos[i].ParameterType, recursionCheck); } return result; @@ -239,7 +239,7 @@ namespace System.Diagnostics.Tracing var result = new TraceLoggingTypeInfo[types.Length]; for (int i = 0; i < types.Length; i++) { - result[i] = Statics.GetTypeInfoInstance(types[i], recursionCheck); + result[i] = TraceLoggingTypeInfo.GetInstance(types[i], recursionCheck); } return result; diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingMetadataCollector.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingMetadataCollector.cs index ff97db5aa2..cee8985aba 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingMetadataCollector.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingMetadataCollector.cs @@ -231,7 +231,7 @@ namespace System.Diagnostics.Tracing if (this.BeginningBufferedArray) { - throw new NotSupportedException(Environment.GetResourceString("EventSource_NotSupportedNestedArraysEnums")); + throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedNestedArraysEnums")); } this.impl.AddScalar(2); @@ -243,7 +243,7 @@ namespace System.Diagnostics.Tracing { if (this.bufferedArrayFieldCount >= 0) { - throw new NotSupportedException(Environment.GetResourceString("EventSource_NotSupportedNestedArraysEnums")); + throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedNestedArraysEnums")); } this.bufferedArrayFieldCount = 0; @@ -254,7 +254,7 @@ namespace System.Diagnostics.Tracing { if (this.bufferedArrayFieldCount != 1) { - throw new InvalidOperationException(Environment.GetResourceString("EventSource_IncorrentlyAuthoredTypeInfo")); + throw new InvalidOperationException(Resources.GetResourceString("EventSource_IncorrentlyAuthoredTypeInfo")); } this.bufferedArrayFieldCount = int.MinValue; @@ -273,7 +273,7 @@ namespace System.Diagnostics.Tracing { if (this.BeginningBufferedArray) { - throw new NotSupportedException(Environment.GetResourceString("EventSource_NotSupportedCustomSerializedData")); + throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedCustomSerializedData")); } this.impl.AddScalar(2); diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingTypeInfo.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingTypeInfo.cs index 21a4390e42..7d4b53315e 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingTypeInfo.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingTypeInfo.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Collections.Generic; #if !ES_BUILD_AGAINST_DOTNET_V35 using Contract = System.Diagnostics.Contracts.Contract; @@ -28,6 +29,7 @@ namespace System.Diagnostics.Tracing private readonly EventOpcode opcode = (EventOpcode)(-1); private readonly EventTags tags; private readonly Type dataType; + private readonly Func<object, PropertyValue> propertyValueFactory; internal TraceLoggingTypeInfo(Type dataType) { @@ -40,6 +42,7 @@ namespace System.Diagnostics.Tracing this.name = dataType.Name; this.dataType = dataType; + this.propertyValueFactory = PropertyValue.GetFactory(dataType); } internal TraceLoggingTypeInfo( @@ -70,6 +73,7 @@ namespace System.Diagnostics.Tracing this.opcode = opcode; this.tags = tags; this.dataType = dataType; + this.propertyValueFactory = PropertyValue.GetFactory(dataType); } /// <summary> @@ -123,6 +127,11 @@ namespace System.Diagnostics.Tracing get { return this.dataType; } } + internal Func<object, PropertyValue> PropertyValueFactory + { + get { return this.propertyValueFactory; } + } + /// <summary> /// When overridden by a derived class, writes the metadata (schema) for /// this type. Note that the sequence of operations in WriteMetadata should be @@ -162,9 +171,9 @@ namespace System.Diagnostics.Tracing /// Refer to TraceLoggingTypeInfo.WriteObjectData for information about this /// method. /// </param> - public abstract void WriteObjectData( + public abstract void WriteData( TraceLoggingDataCollector collector, - object value); + PropertyValue value); /// <summary> /// Fetches the event parameter data for internal serialization. @@ -175,5 +184,25 @@ namespace System.Diagnostics.Tracing { return value; } + + [ThreadStatic] // per-thread cache to avoid synchronization + private static Dictionary<Type, TraceLoggingTypeInfo> threadCache; + + public static TraceLoggingTypeInfo GetInstance(Type type, List<Type> recursionCheck) + { + var cache = threadCache ?? (threadCache = new Dictionary<Type, TraceLoggingTypeInfo>()); + + TraceLoggingTypeInfo instance; + if (!cache.TryGetValue(type, out instance)) + { + if (recursionCheck == null) + recursionCheck = new List<Type>(); + var recursionCheckCount = recursionCheck.Count; + instance = Statics.CreateDefaultTypeInfo(type, recursionCheck); + cache[type] = instance; + recursionCheck.RemoveRange(recursionCheckCount, recursionCheck.Count - recursionCheckCount); + } + return instance; + } } } diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingTypeInfo_T.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingTypeInfo_T.cs deleted file mode 100644 index 58945987ee..0000000000 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingTypeInfo_T.cs +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using Interlocked = System.Threading.Interlocked; - -#if ES_BUILD_STANDALONE -namespace Microsoft.Diagnostics.Tracing -#else -namespace System.Diagnostics.Tracing -#endif -{ - /// <summary> - /// TraceLogging: used when implementing a custom TraceLoggingTypeInfo. - /// Implementations of this type provide the behaviors that TraceLogging - /// uses to turn objects into event data. TraceLogging provides default - /// implementations of this type, but custom implementations can be used - /// when the default TraceLogging implementation is insufficient. - /// </summary> - /// <typeparam name="DataType"> - /// The type of object that is handled by this implementation. - /// </typeparam> - internal abstract class TraceLoggingTypeInfo<DataType> - : TraceLoggingTypeInfo - { - private static TraceLoggingTypeInfo<DataType> instance; - - /// <summary> - /// Initializes a new instance of the TraceLoggingTypeInfo class with - /// default settings. Uses typeof(DataType).Name for EventName and FieldName. - /// Marks Level and Opcode as unset. Sets Keywords and Traits to 0. - /// </summary> - protected TraceLoggingTypeInfo() - : base(typeof(DataType)) - { - return; - } - - /// <summary> - /// Initializes a new instance of the TraceLoggingTypeInfo class, using - /// the specified values for the EventName, Level, Opcode, Keywords, - /// FieldName, and Traits properties. - /// </summary> - /// <param name="name"> - /// The value for the Name property. Must not contain '\0' characters. - /// Must not be null. - /// </param> - /// <param name="level"> - /// The value for the Level property, or -1 to mark Level as unset. - /// </param> - /// <param name="opcode"> - /// The value for the Opcode property, or -1 to mark Opcode as unset. - /// </param> - /// <param name="keywords"> - /// The value for the Keywords property. - /// </param> - /// <param name="tags"> - /// The value for the Tags property. - /// </param> - protected TraceLoggingTypeInfo( - string name, - EventLevel level, - EventOpcode opcode, - EventKeywords keywords, - EventTags tags) - : base( - typeof(DataType), - name, - level, - opcode, - keywords, - tags) - { - return; - } - - /// <summary> - /// Gets the type info that will be used for handling instances of - /// DataType. If the instance has not already been set, this will - /// call TrySetInstance(automaticSerializer) to set one, where - /// automaticSerializer is the value returned from CreateDefault(), - /// or a do-nothing serializer if CreateDefault() fails. - /// </summary> - public static TraceLoggingTypeInfo<DataType> Instance - { - get - { - return instance ?? InitInstance(); - } - } - - /// <summary> - /// When overridden by a derived class, writes the data (fields) for an instance - /// of DataType. Note that the sequence of operations in WriteData should be - /// essentially identical to the sequence of operations in WriteMetadata. Otherwise, - /// the metadata and data will not match, which may cause trouble when decoding the - /// event. - /// </summary> - /// <param name="collector"> - /// The object that collects the data for the instance. Data is written by calling - /// methods on the collector object. Note that if the type contains sub-objects, - /// the implementation of this method may need to call the WriteData method - /// for the sub-object, e.g. by calling - /// TraceLoggingTypeInfo<SubType>.Instance.WriteData(...). - /// </param> - /// <param name="value"> - /// The value for which data is to be written. - /// </param> - public abstract void WriteData( - TraceLoggingDataCollector collector, - ref DataType value); - - /// <summary> - /// When overridden in a derived class, writes the data (fields) for an instance - /// of DataType. The default implementation of WriteObjectData calls - /// WriteData(collector, (DataType)value). Normally, you will override WriteData - /// and not WriteObjectData. However, if your implementation of WriteData has to - /// cast the value to object, it may be more efficient to reverse this calling - /// pattern, i.e. to implement WriteObjectData, and then implement WriteData as a - /// call to WriteObjectData. - /// </summary> - /// <param name="collector"> - /// The object that collects the data for the instance. Data is written by calling - /// methods on the collector object. Note that if the type contains sub-objects, - /// the implementation of this method may need to call the WriteData method - /// for the sub-object, e.g. by calling - /// TraceLoggingTypeInfo<SubType>.Instance.WriteData(...). - /// </param> - /// <param name="value"> - /// The value for which data is to be written. Note that this value may be null - /// (even for value types) if the property from which the value was read is - /// missing or null. - /// </param> - public override void WriteObjectData( - TraceLoggingDataCollector collector, - object value) - { - var val = value == null ? default(DataType) : (DataType)value; - this.WriteData(collector, ref val); - } - - internal static TraceLoggingTypeInfo<DataType> GetInstance(List<Type> recursionCheck) - { - if (instance == null) - { - var recursionCheckCount = recursionCheck.Count; - var newInstance = Statics.CreateDefaultTypeInfo<DataType>(recursionCheck); - Interlocked.CompareExchange(ref instance, newInstance, null); - recursionCheck.RemoveRange(recursionCheckCount, recursionCheck.Count - recursionCheckCount); - } - - return instance; - } - - private static TraceLoggingTypeInfo<DataType> InitInstance() - { - return GetInstance(new List<Type>()); - } - } -} diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TypeAnalysis.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TypeAnalysis.cs index 8b44ddec15..3221dbdc0d 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TypeAnalysis.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TypeAnalysis.cs @@ -57,7 +57,7 @@ namespace System.Diagnostics.Tracing } var propertyType = propertyInfo.PropertyType; - var propertyTypeInfo = Statics.GetTypeInfoInstance(propertyType, recursionCheck); + var propertyTypeInfo = TraceLoggingTypeInfo.GetInstance(propertyType, recursionCheck); var fieldAttribute = Statics.GetCustomAttribute<EventFieldAttribute>(propertyInfo); string propertyName = @@ -68,7 +68,7 @@ namespace System.Diagnostics.Tracing : propertyInfo.Name; propertyList.Add(new PropertyAnalysis( propertyName, - getterInfo, + propertyInfo, propertyTypeInfo, fieldAttribute)); } diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/Winmeta.cs b/src/mscorlib/src/System/Diagnostics/Eventing/Winmeta.cs index 9971a8ff8c..31e5a68d68 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/Winmeta.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/Winmeta.cs @@ -24,7 +24,8 @@ namespace System.Diagnostics.Tracing /// <summary> /// WindowsEventLevel. Custom values must be in the range from 16 through 255 /// </summary> - public enum EventLevel { + public enum EventLevel + { /// <summary> /// Log always /// </summary> @@ -53,10 +54,11 @@ namespace System.Diagnostics.Tracing /// <summary> /// WindowsEventTask. Custom values must be in the range from 1 through 65534 /// </summary> -#if !ES_BUILD_STANDALONE +#if (!ES_BUILD_STANDALONE && !PROJECTN) [System.Runtime.CompilerServices.FriendAccessAllowed] #endif - public enum EventTask { + public enum EventTask + { /// <summary> /// Undefined task /// </summary> @@ -65,7 +67,7 @@ namespace System.Diagnostics.Tracing /// <summary> /// EventOpcode. Custom values must be in the range from 11 through 239 /// </summary> -#if !ES_BUILD_STANDALONE +#if (!ES_BUILD_STANDALONE && !PROJECTN) [System.Runtime.CompilerServices.FriendAccessAllowed] #endif public enum EventOpcode @@ -120,12 +122,12 @@ namespace System.Diagnostics.Tracing /// <summary> /// EventChannel. Custom values must be in the range from 16 through 255. Currently only predefined values allowed. /// </summary> - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1028:EnumStorageShouldBeInt32", Justification="Backwards compatibility")] -#if !ES_BUILD_STANDALONE + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1028:EnumStorageShouldBeInt32", Justification = "Backwards compatibility")] +#if (!ES_BUILD_STANDALONE && !PROJECTN) [System.Runtime.CompilerServices.FriendAccessAllowed] #endif - public enum EventChannel : byte - { + public enum EventChannel : byte + { /// <summary> /// No channel /// </summary> @@ -146,7 +148,8 @@ namespace System.Diagnostics.Tracing /// EventOpcode /// </summary> [Flags] - public enum EventKeywords : long { + public enum EventKeywords : long + { /// <summary> /// No events. /// </summary> diff --git a/src/nativeresources/processrc.awk b/src/nativeresources/processrc.awk index 1632753956..fcfd6e4f91 100644 --- a/src/nativeresources/processrc.awk +++ b/src/nativeresources/processrc.awk @@ -40,9 +40,9 @@ BEGIN { # some of the resource IDs have trailing L gsub(/L/, "", $i); expression = expression $i; - $i=""; i++; } + # evaluate the resource ID expression cmd = "echo $(("expression"))"; cmd | getline var; @@ -50,13 +50,17 @@ BEGIN { # in case shell returned the result as a string, ensure the var has numeric type var = var + 0; + # Extract string content starting with either " or L" + idx = match($0, /L?\"/); + content = substr($0, idx); + # remove the L prefix from strings - gsub(/L"/, "\"", $0); + gsub(/L"/, "\"", content); # join strings "..." "..." into one - gsub(/" +"/, "", $0); + gsub(/" +"/, "", content); # write the resource entry to the target file - writestringentry(var, $0); + writestringentry(var, content); } } END { diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h index c139efcba8..7eaba46688 100644 --- a/src/pal/inc/pal.h +++ b/src/pal/inc/pal.h @@ -6112,6 +6112,7 @@ PALIMPORT int __cdecl vsprintf(char *, const char *, va_list); PALIMPORT int __cdecl sscanf(const char *, const char *, ...); PALIMPORT int __cdecl atoi(const char *); PALIMPORT LONG __cdecl atol(const char *); +PALIMPORT long long int __cdecl atoll(const char *); PALIMPORT ULONG __cdecl strtoul(const char *, char **, int); PALIMPORT double __cdecl atof(const char *); PALIMPORT double __cdecl strtod(const char *, char **); diff --git a/src/pal/inc/pal_mstypes.h b/src/pal/inc/pal_mstypes.h index aca1c60814..e56cf1bd6d 100644 --- a/src/pal/inc/pal_mstypes.h +++ b/src/pal/inc/pal_mstypes.h @@ -319,8 +319,7 @@ typedef signed __int64 LONG64; #ifdef BIT64 -// UNIXTODO: Implement proper _atoi64, the atol returns 32 bit result -#define _atoi64 (__int64)atol +#define _atoi64 (__int64)atoll typedef __int64 INT_PTR, *PINT_PTR; typedef unsigned __int64 UINT_PTR, *PUINT_PTR; diff --git a/src/scripts/Utilities.py b/src/scripts/Utilities.py index 0de1cafdbd..9dfefb7329 100644 --- a/src/scripts/Utilities.py +++ b/src/scripts/Utilities.py @@ -7,7 +7,7 @@ def walk_recursively_and_update(dcmp): for name in dcmp.diff_files: srcpath = dcmp.right + "/" + name destpath = dcmp.left + "/" + name - print "Updating %s" % (destpath) + print("Updating %s" % (destpath)) if os.path.isfile(srcpath): shutil.copyfile(srcpath, destpath) else : @@ -17,7 +17,7 @@ def walk_recursively_and_update(dcmp): for name in dcmp.right_only: srcpath = dcmp.right + "/" + name destpath = dcmp.left + "/" + name - print "Updating %s" % (destpath) + print("Updating %s" % (destpath)) if os.path.isfile(srcpath): shutil.copyfile(srcpath, destpath) elif os.path.isdir(srcpath): @@ -28,7 +28,7 @@ def walk_recursively_and_update(dcmp): #delete left only files for name in dcmp.left_only: path = dcmp.left + "/" + name - print "Deleting " % (path) + print("Deleting " % (path)) if os.path.isfile(path): os.remove(path) elif os.path.isdir(path): diff --git a/src/scripts/genWinEtw.py b/src/scripts/genWinEtw.py index 52bcbd4763..19f9f30e68 100644 --- a/src/scripts/genWinEtw.py +++ b/src/scripts/genWinEtw.py @@ -37,12 +37,12 @@ def generateEtwMacroHeader(sClrEtwAllMan, sExcludeFile,macroHeader,inHeader): os.makedirs(incDir) outHeader = open(macroHeader,'w') - print >>outHeader, stdprolog - - print >>outHeader, "#include \"" + os.path.basename(inHeader) + '"' - print >>outHeader, "#define NO_OF_ETW_PROVIDERS " + str(numOfProviders) - print >>outHeader, "#define MAX_BYTES_PER_ETW_PROVIDER " + str(nMaxEventBytesPerProvider) - print >>outHeader, "EXTERN_C __declspec(selectany) const BYTE etwStackSupportedEvents[NO_OF_ETW_PROVIDERS][MAX_BYTES_PER_ETW_PROVIDER] = \n{" + outHeader.write(stdprolog + "\n") + + outHeader.write("#include \"" + os.path.basename(inHeader) + '"\n') + outHeader.write("#define NO_OF_ETW_PROVIDERS " + str(numOfProviders) + "\n") + outHeader.write("#define MAX_BYTES_PER_ETW_PROVIDER " + str(nMaxEventBytesPerProvider) + "\n") + outHeader.write("EXTERN_C __declspec(selectany) const BYTE etwStackSupportedEvents[NO_OF_ETW_PROVIDERS][MAX_BYTES_PER_ETW_PROVIDER] = \n{\n") for providerNode in tree.getElementsByTagName('provider'): stackSupportedEvents = [0]*nMaxEventBytesPerProvider @@ -55,8 +55,8 @@ def generateEtwMacroHeader(sClrEtwAllMan, sExcludeFile,macroHeader,inHeader): eventTemplate = eventNode.getAttribute('template') eventTemplate = eventNode.getAttribute('template') eventValue = int(eventNode.getAttribute('value')) - eventIndex = eventValue/8 - eventBitPositionInIndex = eventValue%8 + eventIndex = eventValue // 8 + eventBitPositionInIndex = eventValue % 8 eventStackBitFromNoStackList = int(getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.nostack)) eventStackBitFromExplicitStackList = int(getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.explicitstack)) @@ -80,8 +80,8 @@ def generateEtwMacroHeader(sClrEtwAllMan, sExcludeFile,macroHeader,inHeader): del line[-1] line.append("},") - print >>outHeader,''.join(line) - print >>outHeader, "};" + outHeader.write(''.join(line) + "\n") + outHeader.write("};\n") outHeader.close() diff --git a/src/scripts/genXplatEventing.py b/src/scripts/genXplatEventing.py index 0f4033e18f..1d01b60a6c 100644 --- a/src/scripts/genXplatEventing.py +++ b/src/scripts/genXplatEventing.py @@ -10,7 +10,6 @@ import os import xml.dom.minidom as DOM -from sets import Set stdprolog=""" // @@ -179,8 +178,8 @@ def bucketizeAbstractTemplates(template,fnPrototypes,var_Dependecies): return templateProp -ignoredXmlTemplateAttribes = Set(["map","outType"]) -usedXmlTemplateAttribes = Set(["name","inType","count", "length"]) +ignoredXmlTemplateAttribes = frozenset(["map","outType"]) +usedXmlTemplateAttribes = frozenset(["name","inType","count", "length"]) def parseTemplateNodes(templateNodes): @@ -608,14 +607,14 @@ def generateEtmDummyHeader(sClrEtwAllMan,clretwdummy): if not os.path.exists(incDir): os.makedirs(incDir) Clretwdummy = open(clretwdummy,'w') - print >>Clretwdummy, stdprolog + Clretwdummy.write(stdprolog + "\n") for providerNode in tree.getElementsByTagName('provider'): templateNodes = providerNode.getElementsByTagName('template') allTemplates = parseTemplateNodes(templateNodes) eventNodes = providerNode.getElementsByTagName('event') #pal: create etmdummy.h - print >>Clretwdummy,generateclrEtwDummy(eventNodes,allTemplates) + Clretwdummy.write(generateclrEtwDummy(eventNodes, allTemplates) + "\n") Clretwdummy.close() @@ -632,20 +631,20 @@ def generatePlformIndependentFiles(sClrEtwAllMan,incDir,etmDummyFile, testDir): Clrallevents = open(clrallevents,'w') Clrxplatevents = open(clrxplatevents,'w') - print >>Clrallevents, stdprolog - print >>Clrxplatevents, stdprolog + Clrallevents.write(stdprolog + "\n") + Clrxplatevents.write(stdprolog + "\n") - print >>Clrallevents, "\n#include \"clrxplatevents.h\"\n" + Clrallevents.write("\n#include \"clrxplatevents.h\"\n\n") for providerNode in tree.getElementsByTagName('provider'): templateNodes = providerNode.getElementsByTagName('template') allTemplates = parseTemplateNodes(templateNodes) eventNodes = providerNode.getElementsByTagName('event') #vm header: - print >>Clrallevents,generateClrallEvents(eventNodes,allTemplates) + Clrallevents.write(generateClrallEvents(eventNodes, allTemplates) + "\n") #pal: create clrallevents.h - print >>Clrxplatevents, generateClrXplatEvents(eventNodes,allTemplates) + Clrxplatevents.write(generateClrXplatEvents(eventNodes, allTemplates) + "\n") Clrxplatevents.close() @@ -653,9 +652,9 @@ def generatePlformIndependentFiles(sClrEtwAllMan,incDir,etmDummyFile, testDir): class EventExclusions: def __init__(self): - self.nostack = Set() - self.explicitstack = Set() - self.noclrinstance = Set() + self.nostack = set() + self.explicitstack = set() + self.noclrinstance = set() def parseExclusionList(exclusionListFile): ExclusionFile = open(exclusionListFile,'r') diff --git a/src/scripts/genXplatLttng.py b/src/scripts/genXplatLttng.py index 1a1652e22b..fbabfb85ae 100644 --- a/src/scripts/genXplatLttng.py +++ b/src/scripts/genXplatLttng.py @@ -428,8 +428,8 @@ def generateLttngFiles(etwmanifest,intermediate): #Top level Cmake topCmake = open(eventprovider_directory + "/CMakeLists.txt", 'w') - print >>topCmake, stdprolog_cmake - print >>topCmake, """cmake_minimum_required(VERSION 2.8.12.2) + topCmake.write(stdprolog_cmake + "\n") + topCmake.write("""cmake_minimum_required(VERSION 2.8.12.2) project(eventprovider) @@ -441,7 +441,7 @@ def generateLttngFiles(etwmanifest,intermediate): add_library(eventprovider STATIC -""" +""") for providerNode in tree.getElementsByTagName('provider'): providerName = providerNode.getAttribute('name') @@ -451,21 +451,22 @@ def generateLttngFiles(etwmanifest,intermediate): providerName_File = providerName.replace('-','') providerName_File = providerName_File.lower() - print >>topCmake,' "'+ lttngevntprovPre + providerName_File + ".cpp" + '"' + topCmake.write(' "'+ lttngevntprovPre + providerName_File + ".cpp" + '"\n') - print >>topCmake, """) + topCmake.write(""") add_subdirectory(tracepointprovider) # Install the static eventprovider library - install (TARGETS eventprovider DESTINATION lib)""" + install (TARGETS eventprovider DESTINATION lib) + """) topCmake.close() #TracepointProvider Cmake tracepointprovider_Cmake = open(tracepointprovider_directory + "/CMakeLists.txt", 'w') - print >>tracepointprovider_Cmake, stdprolog_cmake - print >>tracepointprovider_Cmake, """cmake_minimum_required(VERSION 2.8.12.2) + tracepointprovider_Cmake.write(stdprolog_cmake + "\n") + tracepointprovider_Cmake.write("""cmake_minimum_required(VERSION 2.8.12.2) project(coreclrtraceptprovider) @@ -477,7 +478,8 @@ def generateLttngFiles(etwmanifest,intermediate): add_compile_options(-fPIC) add_library(coreclrtraceptprovider - SHARED""" + SHARED + """) for providerNode in tree.getElementsByTagName('provider'): providerName = providerNode.getAttribute('name') @@ -487,16 +489,17 @@ def generateLttngFiles(etwmanifest,intermediate): providerName_File = providerName.replace('-','') providerName_File = providerName_File.lower() - print >>tracepointprovider_Cmake,' "'+ lttngevntprovTpPre + providerName_File +".cpp" + '"' + tracepointprovider_Cmake.write(' "'+ lttngevntprovTpPre + providerName_File +".cpp" + '"\n') - print >>tracepointprovider_Cmake, """ ) + tracepointprovider_Cmake.write(""" ) target_link_libraries(coreclrtraceptprovider -llttng-ust ) #Install the static coreclrtraceptprovider library - install (TARGETS coreclrtraceptprovider DESTINATION .)""" + install (TARGETS coreclrtraceptprovider DESTINATION .) + """) tracepointprovider_Cmake.close() # Generate Lttng specific instrumentation @@ -520,40 +523,43 @@ def generateLttngFiles(etwmanifest,intermediate): lTTngImpl = open(lttngevntprov, 'w') lTTngTpImpl = open(lttngevntprovTp, 'w') - print >>lTTngHdr, stdprolog - print >>lTTngImpl, stdprolog - print >>lTTngTpImpl, stdprolog + lTTngHdr.write(stdprolog + "\n") + lTTngImpl.write(stdprolog + "\n") + lTTngTpImpl.write(stdprolog + "\n") - print >>lTTngTpImpl,"\n#define TRACEPOINT_CREATE_PROBES\n" + lTTngTpImpl.write("\n#define TRACEPOINT_CREATE_PROBES\n") - print >>lTTngTpImpl,"#include \"./"+lttngevntheadershortname + "\"" + lTTngTpImpl.write("#include \"./"+lttngevntheadershortname + "\"\n") - print >>lTTngHdr, """ + lTTngHdr.write(""" #include "palrt.h" #include "pal.h" #undef TRACEPOINT_PROVIDER -""" +""") - print >>lTTngHdr, "#define TRACEPOINT_PROVIDER " + providerName - print >>lTTngHdr,""" -#undef TRACEPOINT_INCLUDE""" + lTTngHdr.write("#define TRACEPOINT_PROVIDER " + providerName + "\n") + lTTngHdr.write(""" - print >>lTTngHdr,"#define TRACEPOINT_INCLUDE \"./" + lttngevntheadershortname + "\"\n" +#undef TRACEPOINT_INCLUDE +""") + + lTTngHdr.write("#define TRACEPOINT_INCLUDE \"./" + lttngevntheadershortname + "\"\n\n") - print >>lTTngHdr, "#if !defined(LTTNG_CORECLR_H" + providerName + ") || defined(TRACEPOINT_HEADER_MULTI_READ)\n" - print >>lTTngHdr, "#define LTTNG_CORECLR_H" + providerName + lTTngHdr.write("#if !defined(LTTNG_CORECLR_H" + providerName + ") || defined(TRACEPOINT_HEADER_MULTI_READ)\n\n") + lTTngHdr.write("#define LTTNG_CORECLR_H" + providerName + "\n") - print >>lTTngHdr, "\n#include <lttng/tracepoint.h>\n" + lTTngHdr.write("\n#include <lttng/tracepoint.h>\n\n") - print >>lTTngImpl, """ + lTTngImpl.write(""" #define TRACEPOINT_DEFINE -#define TRACEPOINT_PROBE_DYNAMIC_LINKAGE""" - print >>lTTngImpl,"#include \"" + lttngevntheadershortname + "\"\n" +#define TRACEPOINT_PROBE_DYNAMIC_LINKAGE +""") + lTTngImpl.write("#include \"" + lttngevntheadershortname + "\"\n\n") @@ -562,10 +568,10 @@ def generateLttngFiles(etwmanifest,intermediate): allTemplates = parseTemplateNodes(templateNodes) #generate the header - print >>lTTngHdr,generateLttngHeader(providerName,allTemplates,eventNodes) + lTTngHdr.write(generateLttngHeader(providerName,allTemplates,eventNodes) + "\n") #create the implementation of eventing functions : lttngeventprov*.cp - print >>lTTngImpl,generateLttngTpProvider(providerName,eventNodes,allTemplates) + lTTngImpl.write(generateLttngTpProvider(providerName,eventNodes,allTemplates) + "\n") lTTngHdr.close() lTTngImpl.close() diff --git a/src/vm/exceptionhandling.cpp b/src/vm/exceptionhandling.cpp index a4d90d7073..4441f3b039 100644 --- a/src/vm/exceptionhandling.cpp +++ b/src/vm/exceptionhandling.cpp @@ -4776,7 +4776,7 @@ DWORD64 GetModRMOperandValue(BYTE rex, BYTE* ip, PCONTEXT pContext, bool is8Bit, BYTE rm = (modrm & 0x07); reg |= (rex_r << 3); - rm |= (rex_b << 3); + BYTE rmIndex = rm | (rex_b << 3); // 8 bit idiv without the REX prefix uses registers AH, CH, DH, BH for rm 4..8 // which is an exception from the regular register indexes. @@ -4859,7 +4859,7 @@ DWORD64 GetModRMOperandValue(BYTE rex, BYTE* ip, PCONTEXT pContext, bool is8Bit, } else { - result = GetRegisterValueByIndex(pContext, rm); + result = GetRegisterValueByIndex(pContext, rmIndex); if (mod == 1) { @@ -4881,10 +4881,10 @@ DWORD64 GetModRMOperandValue(BYTE rex, BYTE* ip, PCONTEXT pContext, bool is8Bit, { // 8 bit idiv without the REX prefix uses registers AH, CH, DH or BH for rm 4..8. // So we shift the register index to get the real register index. - rm -= 4; + rmIndex -= 4; } - result = (DWORD64)GetRegisterAddressByIndex(pContext, rm); + result = (DWORD64)GetRegisterAddressByIndex(pContext, rmIndex); if (isAhChDhBh) { diff --git a/src/vm/gcenv.ee.cpp b/src/vm/gcenv.ee.cpp index ab1d66f82b..64455a355c 100644 --- a/src/vm/gcenv.ee.cpp +++ b/src/vm/gcenv.ee.cpp @@ -492,6 +492,17 @@ static void ScanStackRoots(Thread * pThread, promote_func* fn, ScanContext* sc) pThread->SetHasPromotedBytes(); + Frame* pTopFrame = pThread->GetFrame(); + Object ** topStack = (Object **)pTopFrame; + if ((pTopFrame != ((Frame*)-1)) + && (pTopFrame->GetVTablePtr() == InlinedCallFrame::GetMethodFrameVPtr())) { + // It is an InlinedCallFrame. Get SP from it. + InlinedCallFrame* pInlinedFrame = (InlinedCallFrame*)pTopFrame; + topStack = (Object **)pInlinedFrame->GetCallSiteSP(); + } + + sc->stack_limit = (uintptr_t)topStack; + #ifdef FEATURE_CONSERVATIVE_GC if (g_pConfig->GetGCConservative()) { @@ -500,14 +511,6 @@ static void ScanStackRoots(Thread * pThread, promote_func* fn, ScanContext* sc) // Since we report every thing as pinned, we don't need to run following code for relocation phase. if (sc->promotion) { - Frame* pTopFrame = pThread->GetFrame(); - Object ** topStack = (Object **)pTopFrame; - if ((pTopFrame != ((Frame*)-1)) - && (pTopFrame->GetVTablePtr() == InlinedCallFrame::GetMethodFrameVPtr())) { - // It is an InlinedCallFrame. Get SP from it. - InlinedCallFrame* pInlinedFrame = (InlinedCallFrame*)pTopFrame; - topStack = (Object **)pInlinedFrame->GetCallSiteSP(); - } Object ** bottomStack = (Object **) pThread->GetCachedStackBase(); Object ** walk; for (walk = topStack; walk < bottomStack; walk ++) diff --git a/src/vm/siginfo.cpp b/src/vm/siginfo.cpp index 0567b539b3..24c89a35b8 100644 --- a/src/vm/siginfo.cpp +++ b/src/vm/siginfo.cpp @@ -4937,12 +4937,24 @@ void PromoteCarefully(promote_func fn, assert(flags & GC_CALL_INTERIOR); #if !defined(DACCESS_COMPILE) + + // + // Sanity check the stack scan limit + // + assert(sc->stack_limit != 0); + // Note that the base is at a higher address than the limit, since the stack // grows downwards. - if (sc->thread_under_crawl->IsAddressInStack(*ppObj)) + // To check whether the object is in the stack or not, we also need to check the sc->stack_limit. + // The reason is that on Unix, the stack size can be unlimited. In such case, the system can + // shrink the current reserved stack space. That causes the real limit of the stack to move up and + // the range can be reused for other purposes. But the sc->stack_limit is stable during the scan. + // Even on Windows, we care just about the stack above the stack_limit. + if ((sc->thread_under_crawl->IsAddressInStack(*ppObj)) && (PTR_TO_TADDR(*ppObj) >= sc->stack_limit)) { return; } + #endif // !defined(DACCESS_COMPILE) (*fn) (ppObj, sc, flags); |