internal unsafe CategorySample(byte[] data, CategoryEntry entry, PerformanceCounterLib library) { this.entry = entry; this.library = library; int categoryIndex = entry.NameIndex; NativeMethods.PERF_DATA_BLOCK dataBlock = new NativeMethods.PERF_DATA_BLOCK(); fixed (byte* dataPtr = data) { IntPtr dataRef = new IntPtr((void*) dataPtr); Marshal.PtrToStructure(dataRef, dataBlock); this.SystemFrequency = dataBlock.PerfFreq; this.TimeStamp = dataBlock.PerfTime; this.TimeStamp100nSec = dataBlock.PerfTime100nSec; dataRef = (IntPtr)((long)dataRef + dataBlock.HeaderLength); int numPerfObjects = dataBlock.NumObjectTypes; if (numPerfObjects == 0) { this.CounterTable = new Hashtable(); this.InstanceNameTable = new Hashtable(StringComparer.OrdinalIgnoreCase); return; } //Need to find the right category, GetPerformanceData might return //several of them. NativeMethods.PERF_OBJECT_TYPE perfObject = null; bool foundCategory = false; for (int index = 0; index < numPerfObjects; index++) { perfObject = new NativeMethods.PERF_OBJECT_TYPE(); Marshal.PtrToStructure(dataRef, perfObject); if (perfObject.ObjectNameTitleIndex == categoryIndex) { foundCategory = true; break; } dataRef = (IntPtr)((long)dataRef + perfObject.TotalByteLength); } if (!foundCategory) throw new InvalidOperationException(SR.GetString(SR.CantReadCategoryIndex, categoryIndex.ToString(CultureInfo.CurrentCulture))); this.CounterFrequency = perfObject.PerfFreq; this.CounterTimeStamp = perfObject.PerfTime; int counterNumber = perfObject.NumCounters; int instanceNumber = perfObject.NumInstances; if (instanceNumber == -1) IsMultiInstance = false; else IsMultiInstance = true; // Move pointer forward to end of PERF_OBJECT_TYPE dataRef = (IntPtr)((long)dataRef + perfObject.HeaderLength); CounterDefinitionSample[] samples = new CounterDefinitionSample[counterNumber]; this.CounterTable = new Hashtable(counterNumber); for (int index = 0; index < samples.Length; ++ index) { NativeMethods.PERF_COUNTER_DEFINITION perfCounter = new NativeMethods.PERF_COUNTER_DEFINITION(); Marshal.PtrToStructure(dataRef, perfCounter); samples[index] = new CounterDefinitionSample(perfCounter, this, instanceNumber); dataRef = (IntPtr)((long)dataRef + perfCounter.ByteLength); int currentSampleType = samples[index].CounterType; if (!PerformanceCounterLib.IsBaseCounter(currentSampleType)) { // We'll put only non-base counters in the table. if (currentSampleType != NativeMethods.PERF_COUNTER_NODATA) this.CounterTable[samples[index].NameIndex] = samples[index]; } else { // it's a base counter, try to hook it up to the main counter. Debug.Assert(index > 0, "Index > 0 because base counters should never be at index 0"); if (index > 0) samples[index-1].BaseCounterDefinitionSample = samples[index]; } } // now set up the InstanceNameTable. if (!IsMultiInstance) { this.InstanceNameTable = new Hashtable(1, StringComparer.OrdinalIgnoreCase); this.InstanceNameTable[PerformanceCounterLib.SingleInstanceName] = 0; for (int index = 0; index < samples.Length; ++ index) { samples[index].SetInstanceValue(0, dataRef); } } else { string[] parentInstanceNames = null; this.InstanceNameTable = new Hashtable(instanceNumber, StringComparer.OrdinalIgnoreCase); for (int i = 0; i < instanceNumber; i++) { NativeMethods.PERF_INSTANCE_DEFINITION perfInstance = new NativeMethods.PERF_INSTANCE_DEFINITION(); Marshal.PtrToStructure(dataRef, perfInstance); if (perfInstance.ParentObjectTitleIndex > 0 && parentInstanceNames == null) parentInstanceNames = GetInstanceNamesFromIndex(perfInstance.ParentObjectTitleIndex); string instanceName; if (parentInstanceNames != null && perfInstance.ParentObjectInstance >= 0 && perfInstance.ParentObjectInstance < parentInstanceNames.Length - 1) instanceName = parentInstanceNames[perfInstance.ParentObjectInstance] + "/" + Marshal.PtrToStringUni((IntPtr)((long)dataRef + perfInstance.NameOffset)); else instanceName = Marshal.PtrToStringUni((IntPtr)((long)dataRef + perfInstance.NameOffset)); //In some cases instance names are not unique (Process), same as perfmon //generate a unique name. string newInstanceName = instanceName; int newInstanceNumber = 1; while (true) { if (!this.InstanceNameTable.ContainsKey(newInstanceName)) { this.InstanceNameTable[newInstanceName] = i; break; } else { newInstanceName = instanceName + "#" + newInstanceNumber.ToString(CultureInfo.InvariantCulture); ++ newInstanceNumber; } } dataRef = (IntPtr)((long)dataRef + perfInstance.ByteLength); for (int index = 0; index < samples.Length; ++ index) samples[index].SetInstanceValue(i, dataRef); dataRef = (IntPtr)((long)dataRef + Marshal.ReadInt32(dataRef)); } } } }
// // FindCategory - // // * when the function returns true the returnCategoryPointerReference is set to the CategoryEntry // that matches 'categoryNameHashCode' and 'categoryName' // // * when the function returns false the returnCategoryPointerReference is set to the last CategoryEntry // in the linked list // private unsafe bool FindCategory(CategoryEntry** returnCategoryPointerReference) { CategoryEntry* firstCategoryPointer = (CategoryEntry*)(ResolveOffset(InitialOffset, CategoryEntrySize)); CategoryEntry* currentCategoryPointer = firstCategoryPointer; CategoryEntry* previousCategoryPointer = firstCategoryPointer; for(;;) { if (currentCategoryPointer->IsConsistent == 0) Verify(currentCategoryPointer); if (currentCategoryPointer->CategoryNameHashCode == categoryNameHashCode) { if (StringEquals(categoryName, currentCategoryPointer->CategoryNameOffset)) { *returnCategoryPointerReference = currentCategoryPointer; return true; } } previousCategoryPointer = currentCategoryPointer; if (currentCategoryPointer->NextCategoryOffset != 0) currentCategoryPointer = (CategoryEntry*)(ResolveOffset(currentCategoryPointer->NextCategoryOffset, CategoryEntrySize)); else { *returnCategoryPointerReference = previousCategoryPointer; return false; } } }
private unsafe bool FindInstance(int instanceNameHashCode, string instanceName, CategoryEntry* categoryPointer, InstanceEntry** returnInstancePointerReference, bool activateUnusedInstances, PerformanceCounterInstanceLifetime lifetime, out bool foundFreeInstance) { InstanceEntry* currentInstancePointer = (InstanceEntry*)(ResolveOffset(categoryPointer->FirstInstanceOffset, InstanceEntrySize)); InstanceEntry* previousInstancePointer = currentInstancePointer; foundFreeInstance = false; // Look at the first instance to determine if this is single or multi instance. if (currentInstancePointer->InstanceNameHashCode == SingleInstanceHashCode) { if (StringEquals(SingleInstanceName, currentInstancePointer->InstanceNameOffset)){ if (instanceName != SingleInstanceName) throw new InvalidOperationException(SR.GetString(SR.SingleInstanceOnly, categoryName)); } else { if (instanceName == SingleInstanceName) throw new InvalidOperationException(SR.GetString(SR.MultiInstanceOnly, categoryName)); } } else { if (instanceName == SingleInstanceName) throw new InvalidOperationException(SR.GetString(SR.MultiInstanceOnly, categoryName)); } // // 1st pass find exact matching! // // We don't need to aggressively claim unused instances. For performance, we would proactively // verify lifetime of instances if activateUnusedInstances is specified and certain time // has elapsed since last sweep or we are running out of shared memory. bool verifyLifeTime = activateUnusedInstances; if (activateUnusedInstances) { int totalSize = InstanceEntrySize + ProcessLifetimeEntrySize + InstanceNameSlotSize + (CounterEntrySize * categoryData.CounterNames.Count); int freeMemoryOffset = *((int *) baseAddress); int alignmentAdjustment; int newOffset = CalculateMemoryNoBoundsCheck(freeMemoryOffset, totalSize, out alignmentAdjustment); if (!(newOffset > FileView.FileMappingSize || newOffset < 0)) { long tickDelta = (DateTime.Now.Ticks - Volatile.Read(ref LastInstanceLifetimeSweepTick)); if (tickDelta < InstanceLifetimeSweepWindow) verifyLifeTime = false; } } new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); try { for(;;) { bool verifiedLifetimeOfThisInstance = false; if (verifyLifeTime && (currentInstancePointer->RefCount != 0)) { verifiedLifetimeOfThisInstance = true; VerifyLifetime(currentInstancePointer); } if (currentInstancePointer->InstanceNameHashCode == instanceNameHashCode) { if (StringEquals(instanceName, currentInstancePointer->InstanceNameOffset)){ // we found a matching instance. *returnInstancePointerReference = currentInstancePointer; CounterEntry* firstCounter = (CounterEntry*) ResolveOffset(currentInstancePointer->FirstCounterOffset, CounterEntrySize); ProcessLifetimeEntry* lifetimeEntry; if (categoryData.UseUniqueSharedMemory) lifetimeEntry = (ProcessLifetimeEntry*) ResolveOffset(firstCounter->LifetimeOffset, ProcessLifetimeEntrySize); else lifetimeEntry = null; // ensure that we have verified the lifetime of the matched instance if (!verifiedLifetimeOfThisInstance && currentInstancePointer->RefCount != 0) VerifyLifetime(currentInstancePointer); if (currentInstancePointer->RefCount != 0) { if (lifetimeEntry != null && lifetimeEntry->ProcessId != 0) { if (lifetime != PerformanceCounterInstanceLifetime.Process) throw new InvalidOperationException(SR.GetString(SR.CantConvertProcessToGlobal)); // make sure only one process is using this instance. if (ProcessData.ProcessId != lifetimeEntry->ProcessId) throw new InvalidOperationException(SR.GetString(SR.InstanceAlreadyExists, instanceName)); // compare start time of the process, account for ACL issues in querying process information if ((lifetimeEntry->StartupTime != -1) && (ProcessData.StartupTime != -1)) { if (ProcessData.StartupTime != lifetimeEntry->StartupTime) throw new InvalidOperationException(SR.GetString(SR.InstanceAlreadyExists, instanceName)); } } else { if (lifetime == PerformanceCounterInstanceLifetime.Process) throw new InvalidOperationException(SR.GetString(SR.CantConvertGlobalToProcess)); } return true; } if (activateUnusedInstances) { Mutex mutex = null; RuntimeHelpers.PrepareConstrainedRegions(); try { SharedUtils.EnterMutexWithoutGlobal(categoryData.MutexName, ref mutex); ClearCounterValues(currentInstancePointer); if (lifetimeEntry != null) PopulateLifetimeEntry(lifetimeEntry, lifetime); currentInstancePointer->RefCount = 1; return true; } finally { if (mutex != null) { mutex.ReleaseMutex(); mutex.Close(); } } } else return false; } } if (currentInstancePointer->RefCount == 0) { foundFreeInstance = true; } previousInstancePointer = currentInstancePointer; if (currentInstancePointer->NextInstanceOffset != 0) currentInstancePointer = (InstanceEntry*)(ResolveOffset(currentInstancePointer->NextInstanceOffset, InstanceEntrySize)); else { *returnInstancePointerReference = previousInstancePointer; return false; } } } finally { SecurityPermission.RevertAssert(); if (verifyLifeTime) Volatile.Write(ref LastInstanceLifetimeSweepTick, DateTime.Now.Ticks); } }
private unsafe int CreateCategory(CategoryEntry* lastCategoryPointer, int instanceNameHashCode, string instanceName, PerformanceCounterInstanceLifetime lifetime) { int categoryNameLength; int instanceNameLength; int alignmentAdjustment; int freeMemoryOffset; int newOffset = 0; int totalSize; categoryNameLength = (categoryName.Length + 1) * 2; totalSize = CategoryEntrySize + InstanceEntrySize + (CounterEntrySize * categoryData.CounterNames.Count) + categoryNameLength; for (int i=0; i<categoryData.CounterNames.Count; i++) { totalSize += (((string)categoryData.CounterNames[i]).Length + 1) * 2; } if (categoryData.UseUniqueSharedMemory) { instanceNameLength = InstanceNameSlotSize; totalSize += ProcessLifetimeEntrySize + instanceNameLength; // If we're in a separate shared memory, we need to do a two stage update of the free memory pointer. // First we calculate our alignment adjustment and where the new free offset is. Then we // write the new structs and data. The last two operations are to link the new structs into the // existing ones and update the next free offset. Our process could get killed in between those two, // leaving the memory in an inconsistent state. We use the "IsConsistent" flag to help determine // when that has happened. freeMemoryOffset = *((int *) baseAddress); newOffset = CalculateMemory(freeMemoryOffset, totalSize, out alignmentAdjustment); if (freeMemoryOffset == InitialOffset) lastCategoryPointer->IsConsistent = 0; } else { instanceNameLength = (instanceName.Length +1) * 2; totalSize += instanceNameLength; freeMemoryOffset = CalculateAndAllocateMemory(totalSize, out alignmentAdjustment); } long nextPtr = ResolveOffset(freeMemoryOffset, totalSize + alignmentAdjustment); CategoryEntry* newCategoryEntryPointer; InstanceEntry* newInstanceEntryPointer; // We need to decide where to put the padding returned in alignmentAdjustment. There are several things that // need to be aligned. First, we need to align each struct on a 4 byte boundary so we can use interlocked // operations on the int Spinlock field. Second, we need to align the CounterEntry on an 8 byte boundary so that // on 64 bit platforms we can use interlocked operations on the Value field. alignmentAdjustment guarantees 8 byte // alignemnt, so we use that for both. If we're creating the very first category, however, we can't move that // CategoryEntry. In this case we put the alignmentAdjustment before the InstanceEntry. if (freeMemoryOffset == InitialOffset) { newCategoryEntryPointer = (CategoryEntry*) nextPtr; nextPtr += CategoryEntrySize + alignmentAdjustment; newInstanceEntryPointer = (InstanceEntry*) nextPtr; } else { nextPtr += alignmentAdjustment; newCategoryEntryPointer = (CategoryEntry*) nextPtr; nextPtr += CategoryEntrySize; newInstanceEntryPointer = (InstanceEntry*) nextPtr; } nextPtr += InstanceEntrySize; // create the first CounterEntry and reserve space for all of the rest. We won't // finish creating them until the end CounterEntry* newCounterEntryPointer = (CounterEntry*) nextPtr; nextPtr += CounterEntrySize * categoryData.CounterNames.Count; if (categoryData.UseUniqueSharedMemory) { ProcessLifetimeEntry* newLifetimeEntry = (ProcessLifetimeEntry*) nextPtr; nextPtr += ProcessLifetimeEntrySize; newCounterEntryPointer->LifetimeOffset = (int)((long)newLifetimeEntry - baseAddress); PopulateLifetimeEntry(newLifetimeEntry, lifetime); } newCategoryEntryPointer->CategoryNameHashCode = categoryNameHashCode; newCategoryEntryPointer->NextCategoryOffset = 0; newCategoryEntryPointer->FirstInstanceOffset = (int)((long)newInstanceEntryPointer - baseAddress); newCategoryEntryPointer->CategoryNameOffset = (int) (nextPtr - baseAddress); SafeMarshalCopy(categoryName, (IntPtr)nextPtr); nextPtr += categoryNameLength; newInstanceEntryPointer->InstanceNameHashCode = instanceNameHashCode; newInstanceEntryPointer->NextInstanceOffset = 0; newInstanceEntryPointer->FirstCounterOffset = (int)((long)newCounterEntryPointer - baseAddress); newInstanceEntryPointer->RefCount = 1; newInstanceEntryPointer->InstanceNameOffset = (int) (nextPtr - baseAddress); SafeMarshalCopy(instanceName, (IntPtr)nextPtr); nextPtr += instanceNameLength; string counterName = (string) categoryData.CounterNames[0]; newCounterEntryPointer->CounterNameHashCode = GetWstrHashCode(counterName); SetValue(newCounterEntryPointer, 0); newCounterEntryPointer->CounterNameOffset = (int) (nextPtr - baseAddress); SafeMarshalCopy(counterName, (IntPtr)nextPtr); nextPtr += (counterName.Length + 1) * 2; CounterEntry* previousCounterEntryPointer; for (int i=1; i<categoryData.CounterNames.Count; i++) { previousCounterEntryPointer = newCounterEntryPointer; counterName = (string) categoryData.CounterNames[i]; newCounterEntryPointer++; newCounterEntryPointer->CounterNameHashCode = GetWstrHashCode(counterName); SetValue(newCounterEntryPointer, 0); newCounterEntryPointer->CounterNameOffset = (int) (nextPtr - baseAddress); SafeMarshalCopy(counterName, (IntPtr)nextPtr); nextPtr += (counterName.Length + 1) * 2; previousCounterEntryPointer->NextCounterOffset = (int)((long)newCounterEntryPointer - baseAddress); } Debug.Assert(nextPtr - baseAddress == freeMemoryOffset + totalSize + alignmentAdjustment, "We should have used all of the space we requested at this point"); int offset = (int) ((long) newCategoryEntryPointer - baseAddress); lastCategoryPointer->IsConsistent = 0; // If not the first category node, link it. if (offset != InitialOffset) lastCategoryPointer->NextCategoryOffset = offset; if (categoryData.UseUniqueSharedMemory) { *((int*) baseAddress) = newOffset; lastCategoryPointer->IsConsistent = 1; } return offset; }
private unsafe int CreateInstance(CategoryEntry* categoryPointer, int instanceNameHashCode, string instanceName, PerformanceCounterInstanceLifetime lifetime) { int instanceNameLength; int totalSize = InstanceEntrySize + (CounterEntrySize * categoryData.CounterNames.Count); int alignmentAdjustment; int freeMemoryOffset; int newOffset = 0; if (categoryData.UseUniqueSharedMemory) { instanceNameLength = InstanceNameSlotSize; totalSize += ProcessLifetimeEntrySize + instanceNameLength; // If we're in a separate shared memory, we need to do a two stage update of the free memory pointer. // First we calculate our alignment adjustment and where the new free offset is. Then we // write the new structs and data. The last two operations are to link the new structs into the // existing ones and update the next free offset. Our process could get killed in between those two, // leaving the memory in an inconsistent state. We use the "IsConsistent" flag to help determine // when that has happened. freeMemoryOffset = *((int *) baseAddress); newOffset = CalculateMemory(freeMemoryOffset, totalSize, out alignmentAdjustment); } else { instanceNameLength = (instanceName.Length +1) * 2; totalSize += instanceNameLength; // add in the counter names for the global shared mem. for (int i=0; i<categoryData.CounterNames.Count; i++) { totalSize += (((string)categoryData.CounterNames[i]).Length + 1) * 2; } freeMemoryOffset = CalculateAndAllocateMemory(totalSize, out alignmentAdjustment); } freeMemoryOffset += alignmentAdjustment; long nextPtr = ResolveOffset(freeMemoryOffset, totalSize); // don't add alignmentAdjustment since it's already // been added to freeMemoryOffset InstanceEntry* newInstanceEntryPointer = (InstanceEntry*) nextPtr; nextPtr += InstanceEntrySize; // create the first CounterEntry and reserve space for all of the rest. We won't // finish creating them until the end CounterEntry* newCounterEntryPointer = (CounterEntry*) nextPtr; nextPtr += CounterEntrySize * categoryData.CounterNames.Count; if (categoryData.UseUniqueSharedMemory) { ProcessLifetimeEntry* newLifetimeEntry = (ProcessLifetimeEntry*) nextPtr; nextPtr += ProcessLifetimeEntrySize; newCounterEntryPointer->LifetimeOffset = (int)((long)newLifetimeEntry - baseAddress); PopulateLifetimeEntry(newLifetimeEntry, lifetime); } // set up the InstanceEntry newInstanceEntryPointer->InstanceNameHashCode = instanceNameHashCode; newInstanceEntryPointer->NextInstanceOffset = 0; newInstanceEntryPointer->FirstCounterOffset = (int)((long)newCounterEntryPointer - baseAddress); newInstanceEntryPointer->RefCount = 1; newInstanceEntryPointer->InstanceNameOffset = (int) (nextPtr - baseAddress); SafeMarshalCopy(instanceName, (IntPtr)nextPtr); nextPtr += instanceNameLength; if (categoryData.UseUniqueSharedMemory) { // in the unique shared mem we'll assume that the CounterEntries of the first instance // are all created. Then we can just refer to the old counter name rather than copying in a new one. InstanceEntry* firstInstanceInCategoryPointer = (InstanceEntry*) ResolveOffset(categoryPointer->FirstInstanceOffset, InstanceEntrySize); CounterEntry* firstCounterInCategoryPointer = (CounterEntry*) ResolveOffset(firstInstanceInCategoryPointer->FirstCounterOffset, CounterEntrySize); newCounterEntryPointer->CounterNameHashCode = firstCounterInCategoryPointer->CounterNameHashCode; SetValue(newCounterEntryPointer, 0); newCounterEntryPointer->CounterNameOffset = firstCounterInCategoryPointer->CounterNameOffset; // now create the rest of the CounterEntrys CounterEntry* previousCounterEntryPointer; for (int i=1; i<categoryData.CounterNames.Count; i++) { previousCounterEntryPointer = newCounterEntryPointer; newCounterEntryPointer++; Debug.Assert(firstCounterInCategoryPointer->NextCounterOffset != 0, "The unique shared memory should have all of its counters created by the time we hit CreateInstance"); firstCounterInCategoryPointer = (CounterEntry*) ResolveOffset(firstCounterInCategoryPointer->NextCounterOffset, CounterEntrySize); newCounterEntryPointer->CounterNameHashCode = firstCounterInCategoryPointer->CounterNameHashCode; SetValue(newCounterEntryPointer, 0); newCounterEntryPointer->CounterNameOffset = firstCounterInCategoryPointer->CounterNameOffset; previousCounterEntryPointer->NextCounterOffset = (int)((long)newCounterEntryPointer - baseAddress); } } else { // now create the rest of the CounterEntrys CounterEntry* previousCounterEntryPointer = null; for (int i=0; i<categoryData.CounterNames.Count; i++) { string counterName = (string) categoryData.CounterNames[i]; newCounterEntryPointer->CounterNameHashCode = GetWstrHashCode(counterName); newCounterEntryPointer->CounterNameOffset = (int) (nextPtr - baseAddress); SafeMarshalCopy(counterName, (IntPtr)nextPtr); nextPtr += (counterName.Length + 1) * 2; SetValue(newCounterEntryPointer, 0); if (i != 0) previousCounterEntryPointer->NextCounterOffset = (int)((long)newCounterEntryPointer - baseAddress); previousCounterEntryPointer = newCounterEntryPointer; newCounterEntryPointer++; } } Debug.Assert(nextPtr - baseAddress == freeMemoryOffset + totalSize, "We should have used all of the space we requested at this point"); int offset = (int) ((long) newInstanceEntryPointer - baseAddress); categoryPointer->IsConsistent = 0; // prepend the new instance rather than append, helps with perf of hooking up subsequent counters newInstanceEntryPointer->NextInstanceOffset = categoryPointer->FirstInstanceOffset; categoryPointer->FirstInstanceOffset = offset; if (categoryData.UseUniqueSharedMemory) { *((int*) baseAddress) = newOffset; categoryPointer->IsConsistent = 1; } return freeMemoryOffset; }
private unsafe void Verify(CategoryEntry* currentCategoryPointer) { if (!categoryData.UseUniqueSharedMemory) return; Mutex mutex = null; RuntimeHelpers.PrepareConstrainedRegions(); try { SharedUtils.EnterMutexWithoutGlobal(categoryData.MutexName, ref mutex); VerifyCategory(currentCategoryPointer); } finally { if (mutex != null) { mutex.ReleaseMutex(); mutex.Close(); } } }
private unsafe void VerifyCategory(CategoryEntry* currentCategoryPointer) { int freeOffset = *((int*)baseAddress); ResolveOffset(freeOffset, 0); // verify next free offset // begin by verifying the head node's offset int currentOffset = ResolveAddress((long)currentCategoryPointer, CategoryEntrySize); if (currentOffset >= freeOffset) { // zero out the bad head node entry currentCategoryPointer->SpinLock = 0; currentCategoryPointer->CategoryNameHashCode = 0; currentCategoryPointer->CategoryNameOffset = 0; currentCategoryPointer->FirstInstanceOffset = 0; currentCategoryPointer->NextCategoryOffset = 0; currentCategoryPointer->IsConsistent = 0; return; } if (currentCategoryPointer->NextCategoryOffset > freeOffset) currentCategoryPointer->NextCategoryOffset = 0; else if (currentCategoryPointer->NextCategoryOffset != 0) VerifyCategory((CategoryEntry*) ResolveOffset(currentCategoryPointer->NextCategoryOffset, CategoryEntrySize)); if (currentCategoryPointer->FirstInstanceOffset != 0) { // In V3, we started prepending the new instances rather than appending (as in V2) for performance. // Check whether the recently added instance at the head of the list is committed. If not, rewire // the head of the list to point to the next instance if (currentCategoryPointer->FirstInstanceOffset > freeOffset) { InstanceEntry* currentInstancePointer = (InstanceEntry*) ResolveOffset(currentCategoryPointer->FirstInstanceOffset, InstanceEntrySize); currentCategoryPointer->FirstInstanceOffset = currentInstancePointer->NextInstanceOffset; if (currentCategoryPointer->FirstInstanceOffset > freeOffset) currentCategoryPointer->FirstInstanceOffset = 0; } // if (currentCategoryPointer->FirstInstanceOffset != 0) { Debug.Assert(currentCategoryPointer->FirstInstanceOffset <= freeOffset, "The head of the list is inconsistent - possible mismatch of V2 & V3 instances?"); VerifyInstance((InstanceEntry*) ResolveOffset(currentCategoryPointer->FirstInstanceOffset, InstanceEntrySize)); } } currentCategoryPointer->IsConsistent = 1; }
private unsafe bool FindInstance(int instanceNameHashCode, string instanceName, CategoryEntry* categoryPointer, InstanceEntry** returnInstancePointerReference, bool activateUnusedInstances, PerformanceCounterInstanceLifetime lifetime, out bool foundFreeInstance) { bool flag3; InstanceEntry* currentInstancePointer = (InstanceEntry*) this.ResolveOffset(categoryPointer.FirstInstanceOffset, InstanceEntrySize); InstanceEntry* entryPtr2 = currentInstancePointer; foundFreeInstance = false; if (currentInstancePointer->InstanceNameHashCode == SingleInstanceHashCode) { if (!this.StringEquals("systemdiagnosticssharedsingleinstance", currentInstancePointer->InstanceNameOffset)) { if (instanceName == "systemdiagnosticssharedsingleinstance") { throw new InvalidOperationException(SR.GetString("MultiInstanceOnly", new object[] { this.categoryName })); } } else if (instanceName != "systemdiagnosticssharedsingleinstance") { throw new InvalidOperationException(SR.GetString("SingleInstanceOnly", new object[] { this.categoryName })); } } else if (instanceName == "systemdiagnosticssharedsingleinstance") { throw new InvalidOperationException(SR.GetString("MultiInstanceOnly", new object[] { this.categoryName })); } bool flag = activateUnusedInstances; if (activateUnusedInstances) { int num3; int totalSize = ((InstanceEntrySize + ProcessLifetimeEntrySize) + 0x100) + (CounterEntrySize * this.categoryData.CounterNames.Count); int oldOffset = *((int*) this.baseAddress); int num4 = this.CalculateMemoryNoBoundsCheck(oldOffset, totalSize, out num3); if ((num4 <= this.FileView.FileMappingSize) && (num4 >= 0)) { long num5 = DateTime.Now.Ticks - LastInstanceLifetimeSweepTick; if (num5 < InstanceLifetimeSweepWindow) { flag = false; } } } new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); try { bool flag2; Label_0156: flag2 = false; if (flag && (currentInstancePointer->RefCount != 0)) { flag2 = true; this.VerifyLifetime(currentInstancePointer); } if ((currentInstancePointer->InstanceNameHashCode == instanceNameHashCode) && this.StringEquals(instanceName, currentInstancePointer->InstanceNameOffset)) { ProcessLifetimeEntry* entryPtr4; *((IntPtr*) returnInstancePointerReference) = currentInstancePointer; CounterEntry* entryPtr3 = (CounterEntry*) this.ResolveOffset(currentInstancePointer->FirstCounterOffset, CounterEntrySize); if (this.categoryData.UseUniqueSharedMemory) { entryPtr4 = (ProcessLifetimeEntry*) this.ResolveOffset(entryPtr3->LifetimeOffset, ProcessLifetimeEntrySize); } else { entryPtr4 = null; } if (!flag2 && (currentInstancePointer->RefCount != 0)) { this.VerifyLifetime(currentInstancePointer); } if (currentInstancePointer->RefCount != 0) { if ((entryPtr4 != null) && (entryPtr4->ProcessId != 0)) { if (lifetime != PerformanceCounterInstanceLifetime.Process) { throw new InvalidOperationException(SR.GetString("CantConvertProcessToGlobal")); } if (ProcessData.ProcessId != entryPtr4->ProcessId) { throw new InvalidOperationException(SR.GetString("InstanceAlreadyExists", new object[] { instanceName })); } if (((entryPtr4->StartupTime != -1L) && (ProcessData.StartupTime != -1L)) && (ProcessData.StartupTime != entryPtr4->StartupTime)) { throw new InvalidOperationException(SR.GetString("InstanceAlreadyExists", new object[] { instanceName })); } } else if (lifetime == PerformanceCounterInstanceLifetime.Process) { throw new InvalidOperationException(SR.GetString("CantConvertGlobalToProcess")); } return true; } if (activateUnusedInstances) { Mutex mutex = null; RuntimeHelpers.PrepareConstrainedRegions(); try { SharedUtils.EnterMutexWithoutGlobal(this.categoryData.MutexName, ref mutex); this.ClearCounterValues(currentInstancePointer); if (entryPtr4 != null) { PopulateLifetimeEntry(entryPtr4, lifetime); } currentInstancePointer->RefCount = 1; return true; } finally { if (mutex != null) { mutex.ReleaseMutex(); mutex.Close(); } } } return false; } if (currentInstancePointer->RefCount == 0) { foundFreeInstance = true; } entryPtr2 = currentInstancePointer; if (currentInstancePointer->NextInstanceOffset != 0) { currentInstancePointer = (InstanceEntry*) this.ResolveOffset(currentInstancePointer->NextInstanceOffset, InstanceEntrySize); goto Label_0156; } *((IntPtr*) returnInstancePointerReference) = entryPtr2; flag3 = false; } finally { CodeAccessPermission.RevertAssert(); if (flag) { LastInstanceLifetimeSweepTick = DateTime.Now.Ticks; } } return flag3; }
private unsafe bool TryReuseInstance(int instanceNameHashCode, string instanceName, CategoryEntry* categoryPointer, InstanceEntry** returnInstancePointerReference, PerformanceCounterInstanceLifetime lifetime, InstanceEntry* lockInstancePointer) { // // 2nd pass find a free instance slot // InstanceEntry* currentInstancePointer = (InstanceEntry*)(ResolveOffset(categoryPointer->FirstInstanceOffset, InstanceEntrySize)); InstanceEntry* previousInstancePointer = currentInstancePointer; for (;;) { if (currentInstancePointer->RefCount == 0) { bool hasFit; long instanceNamePtr; // we need cache this to avoid race conditions. if (categoryData.UseUniqueSharedMemory) { instanceNamePtr = ResolveOffset(currentInstancePointer->InstanceNameOffset, InstanceNameSlotSize); // In the separate shared memory case we should always have enough space for instances. The // name slot size is fixed. Debug.Assert(((instanceName.Length + 1) * 2) <= InstanceNameSlotSize, "The instance name length should always fit in our slot size"); hasFit = true; } else { // we don't know the string length yet. instanceNamePtr = ResolveOffset(currentInstancePointer->InstanceNameOffset, 0); // In the global shared memory, we require names to be exactly the same length in order // to reuse them. This way we don't end up leaking any space and we don't need to // depend on the layout of the memory to calculate the space we have. int length = GetStringLength((char*) instanceNamePtr); hasFit = (length == instanceName.Length); } bool noSpinLock = (lockInstancePointer == currentInstancePointer) || categoryData.UseUniqueSharedMemory; // Instance name fit if (hasFit) { // don't bother locking again if we're using a separate shared memory. bool sectionEntered; if (noSpinLock) sectionEntered = true; else WaitAndEnterCriticalSection(&(currentInstancePointer->SpinLock), out sectionEntered); if (sectionEntered) { try { // Make copy with zero-term SafeMarshalCopy(instanceName, (IntPtr)instanceNamePtr); currentInstancePointer->InstanceNameHashCode = instanceNameHashCode; // return *returnInstancePointerReference = currentInstancePointer; // clear the counter values. ClearCounterValues(*returnInstancePointerReference); if (categoryData.UseUniqueSharedMemory) { CounterEntry* counterPointer = (CounterEntry*)ResolveOffset(currentInstancePointer->FirstCounterOffset, CounterEntrySize); ProcessLifetimeEntry* lifetimeEntry = (ProcessLifetimeEntry*) ResolveOffset(counterPointer->LifetimeOffset, ProcessLifetimeEntrySize); PopulateLifetimeEntry(lifetimeEntry, lifetime); } (*returnInstancePointerReference)->RefCount = 1; return true; } finally { if (!noSpinLock) ExitCriticalSection(&(currentInstancePointer->SpinLock)); } } } } previousInstancePointer = currentInstancePointer; if (currentInstancePointer->NextInstanceOffset != 0) currentInstancePointer = (InstanceEntry*)(ResolveOffset(currentInstancePointer->NextInstanceOffset, InstanceEntrySize)); else { *returnInstancePointerReference = previousInstancePointer; return false; } } }
private unsafe bool FindCategory(CategoryEntry** returnCategoryPointerReference) { CategoryEntry* entryPtr = (CategoryEntry*) this.ResolveOffset(this.InitialOffset, CategoryEntrySize); CategoryEntry* currentCategoryPointer = entryPtr; CategoryEntry* entryPtr3 = entryPtr; Label_0017: if (currentCategoryPointer->IsConsistent == 0) { this.Verify(currentCategoryPointer); } if ((currentCategoryPointer->CategoryNameHashCode == this.categoryNameHashCode) && this.StringEquals(this.categoryName, currentCategoryPointer->CategoryNameOffset)) { *((IntPtr*) returnCategoryPointerReference) = currentCategoryPointer; return true; } entryPtr3 = currentCategoryPointer; if (currentCategoryPointer->NextCategoryOffset != 0) { currentCategoryPointer = (CategoryEntry*) this.ResolveOffset(currentCategoryPointer->NextCategoryOffset, CategoryEntrySize); goto Label_0017; } *((IntPtr*) returnCategoryPointerReference) = entryPtr3; return false; }
private unsafe int CreateInstance(CategoryEntry* categoryPointer, int instanceNameHashCode, string instanceName, PerformanceCounterInstanceLifetime lifetime) { int num; int num3; int num4; int totalSize = InstanceEntrySize + (CounterEntrySize * this.categoryData.CounterNames.Count); int num5 = 0; if (this.categoryData.UseUniqueSharedMemory) { num = 0x100; totalSize += ProcessLifetimeEntrySize + num; num4 = *((int*) this.baseAddress); num5 = this.CalculateMemory(num4, totalSize, out num3); } else { num = (instanceName.Length + 1) * 2; totalSize += num; for (int i = 0; i < this.categoryData.CounterNames.Count; i++) { totalSize += (((string) this.categoryData.CounterNames[i]).Length + 1) * 2; } num4 = this.CalculateAndAllocateMemory(totalSize, out num3); } num4 += num3; long num7 = this.ResolveOffset(num4, totalSize); InstanceEntry* entryPtr = (InstanceEntry*) num7; num7 += InstanceEntrySize; CounterEntry* counterEntry = (CounterEntry*) num7; num7 += CounterEntrySize * this.categoryData.CounterNames.Count; if (this.categoryData.UseUniqueSharedMemory) { ProcessLifetimeEntry* lifetimeEntry = (ProcessLifetimeEntry*) num7; num7 += ProcessLifetimeEntrySize; counterEntry->LifetimeOffset = (int) (((ulong) lifetimeEntry) - this.baseAddress); PopulateLifetimeEntry(lifetimeEntry, lifetime); } entryPtr->InstanceNameHashCode = instanceNameHashCode; entryPtr->NextInstanceOffset = 0; entryPtr->FirstCounterOffset = (int) (((ulong) counterEntry) - this.baseAddress); entryPtr->RefCount = 1; entryPtr->InstanceNameOffset = (int) (num7 - this.baseAddress); SafeMarshalCopy(instanceName, (IntPtr) num7); num7 += num; if (this.categoryData.UseUniqueSharedMemory) { InstanceEntry* entryPtr4 = (InstanceEntry*) this.ResolveOffset(categoryPointer.FirstInstanceOffset, InstanceEntrySize); CounterEntry* entryPtr5 = (CounterEntry*) this.ResolveOffset(entryPtr4->FirstCounterOffset, CounterEntrySize); counterEntry->CounterNameHashCode = entryPtr5->CounterNameHashCode; SetValue(counterEntry, 0L); counterEntry->CounterNameOffset = entryPtr5->CounterNameOffset; for (int j = 1; j < this.categoryData.CounterNames.Count; j++) { CounterEntry* entryPtr6 = counterEntry; counterEntry++; entryPtr5 = (CounterEntry*) this.ResolveOffset(entryPtr5->NextCounterOffset, CounterEntrySize); counterEntry->CounterNameHashCode = entryPtr5->CounterNameHashCode; SetValue(counterEntry, 0L); counterEntry->CounterNameOffset = entryPtr5->CounterNameOffset; entryPtr6->NextCounterOffset = (int) (((ulong) counterEntry) - this.baseAddress); } } else { CounterEntry* entryPtr7 = null; for (int k = 0; k < this.categoryData.CounterNames.Count; k++) { string wstr = (string) this.categoryData.CounterNames[k]; counterEntry->CounterNameHashCode = GetWstrHashCode(wstr); counterEntry->CounterNameOffset = (int) (num7 - this.baseAddress); SafeMarshalCopy(wstr, (IntPtr) num7); num7 += (wstr.Length + 1) * 2; SetValue(counterEntry, 0L); if (k != 0) { entryPtr7->NextCounterOffset = (int) (((ulong) counterEntry) - this.baseAddress); } entryPtr7 = counterEntry; counterEntry++; } } int num10 = (int) (((ulong) entryPtr) - this.baseAddress); categoryPointer.IsConsistent = 0; entryPtr->NextInstanceOffset = categoryPointer.FirstInstanceOffset; categoryPointer.FirstInstanceOffset = num10; if (this.categoryData.UseUniqueSharedMemory) { this.baseAddress[0] = num5; categoryPointer.IsConsistent = 1; } return num4; }
private unsafe int CreateCategory(CategoryEntry* lastCategoryPointer, int instanceNameHashCode, string instanceName, PerformanceCounterInstanceLifetime lifetime) { int num2; int num3; int num4; CategoryEntry* entryPtr; InstanceEntry* entryPtr2; int num5 = 0; int num = (this.categoryName.Length + 1) * 2; int totalSize = ((CategoryEntrySize + InstanceEntrySize) + (CounterEntrySize * this.categoryData.CounterNames.Count)) + num; for (int i = 0; i < this.categoryData.CounterNames.Count; i++) { totalSize += (((string) this.categoryData.CounterNames[i]).Length + 1) * 2; } if (this.categoryData.UseUniqueSharedMemory) { num2 = 0x100; totalSize += ProcessLifetimeEntrySize + num2; num4 = *((int*) this.baseAddress); num5 = this.CalculateMemory(num4, totalSize, out num3); if (num4 == this.InitialOffset) { lastCategoryPointer.IsConsistent = 0; } } else { num2 = (instanceName.Length + 1) * 2; totalSize += num2; num4 = this.CalculateAndAllocateMemory(totalSize, out num3); } long num8 = this.ResolveOffset(num4, totalSize + num3); if (num4 == this.InitialOffset) { entryPtr = (CategoryEntry*) num8; num8 += CategoryEntrySize + num3; entryPtr2 = (InstanceEntry*) num8; } else { num8 += num3; entryPtr = (CategoryEntry*) num8; num8 += CategoryEntrySize; entryPtr2 = (InstanceEntry*) num8; } num8 += InstanceEntrySize; CounterEntry* counterEntry = (CounterEntry*) num8; num8 += CounterEntrySize * this.categoryData.CounterNames.Count; if (this.categoryData.UseUniqueSharedMemory) { ProcessLifetimeEntry* lifetimeEntry = (ProcessLifetimeEntry*) num8; num8 += ProcessLifetimeEntrySize; counterEntry->LifetimeOffset = (int) (((ulong) lifetimeEntry) - this.baseAddress); PopulateLifetimeEntry(lifetimeEntry, lifetime); } entryPtr->CategoryNameHashCode = this.categoryNameHashCode; entryPtr->NextCategoryOffset = 0; entryPtr->FirstInstanceOffset = (int) (((ulong) entryPtr2) - this.baseAddress); entryPtr->CategoryNameOffset = (int) (num8 - this.baseAddress); SafeMarshalCopy(this.categoryName, (IntPtr) num8); num8 += num; entryPtr2->InstanceNameHashCode = instanceNameHashCode; entryPtr2->NextInstanceOffset = 0; entryPtr2->FirstCounterOffset = (int) (((ulong) counterEntry) - this.baseAddress); entryPtr2->RefCount = 1; entryPtr2->InstanceNameOffset = (int) (num8 - this.baseAddress); SafeMarshalCopy(instanceName, (IntPtr) num8); num8 += num2; string wstr = (string) this.categoryData.CounterNames[0]; counterEntry->CounterNameHashCode = GetWstrHashCode(wstr); SetValue(counterEntry, 0L); counterEntry->CounterNameOffset = (int) (num8 - this.baseAddress); SafeMarshalCopy(wstr, (IntPtr) num8); num8 += (wstr.Length + 1) * 2; for (int j = 1; j < this.categoryData.CounterNames.Count; j++) { CounterEntry* entryPtr5 = counterEntry; wstr = (string) this.categoryData.CounterNames[j]; counterEntry++; counterEntry->CounterNameHashCode = GetWstrHashCode(wstr); SetValue(counterEntry, 0L); counterEntry->CounterNameOffset = (int) (num8 - this.baseAddress); SafeMarshalCopy(wstr, (IntPtr) num8); num8 += (wstr.Length + 1) * 2; entryPtr5->NextCounterOffset = (int) (((ulong) counterEntry) - this.baseAddress); } int num10 = (int) (((ulong) entryPtr) - this.baseAddress); lastCategoryPointer.IsConsistent = 0; if (num10 != this.InitialOffset) { lastCategoryPointer.NextCategoryOffset = num10; } if (this.categoryData.UseUniqueSharedMemory) { this.baseAddress[0] = num5; lastCategoryPointer.IsConsistent = 1; } return num10; }
private unsafe void VerifyCategory(CategoryEntry* currentCategoryPointer) { int offset = *((int*) this.baseAddress); this.ResolveOffset(offset, 0); if (this.ResolveAddress((long) ((ulong) currentCategoryPointer), CategoryEntrySize) >= offset) { currentCategoryPointer.SpinLock = 0; currentCategoryPointer.CategoryNameHashCode = 0; currentCategoryPointer.CategoryNameOffset = 0; currentCategoryPointer.FirstInstanceOffset = 0; currentCategoryPointer.NextCategoryOffset = 0; currentCategoryPointer.IsConsistent = 0; } else { if (currentCategoryPointer.NextCategoryOffset > offset) { currentCategoryPointer.NextCategoryOffset = 0; } else if (currentCategoryPointer.NextCategoryOffset != 0) { this.VerifyCategory((CategoryEntry*) this.ResolveOffset(currentCategoryPointer.NextCategoryOffset, CategoryEntrySize)); } if (currentCategoryPointer.FirstInstanceOffset != 0) { if (currentCategoryPointer.FirstInstanceOffset > offset) { InstanceEntry* entryPtr = (InstanceEntry*) this.ResolveOffset(currentCategoryPointer.FirstInstanceOffset, InstanceEntrySize); currentCategoryPointer.FirstInstanceOffset = entryPtr->NextInstanceOffset; if (currentCategoryPointer.FirstInstanceOffset > offset) { currentCategoryPointer.FirstInstanceOffset = 0; } } if (currentCategoryPointer.FirstInstanceOffset != 0) { this.VerifyInstance((InstanceEntry*) this.ResolveOffset(currentCategoryPointer.FirstInstanceOffset, InstanceEntrySize)); } } currentCategoryPointer.IsConsistent = 1; } }
private unsafe bool TryReuseInstance(int instanceNameHashCode, string instanceName, CategoryEntry* categoryPointer, InstanceEntry** returnInstancePointerReference, PerformanceCounterInstanceLifetime lifetime, InstanceEntry* lockInstancePointer) { InstanceEntry* entryPtr = (InstanceEntry*) this.ResolveOffset(categoryPointer.FirstInstanceOffset, InstanceEntrySize); InstanceEntry* entryPtr2 = entryPtr; Label_0015: if (entryPtr->RefCount == 0) { bool flag; long num; if (this.categoryData.UseUniqueSharedMemory) { num = this.ResolveOffset(entryPtr->InstanceNameOffset, 0x100); flag = true; } else { num = this.ResolveOffset(entryPtr->InstanceNameOffset, 0); flag = this.GetStringLength((char*) num) == instanceName.Length; } bool flag2 = (lockInstancePointer == entryPtr) || this.categoryData.UseUniqueSharedMemory; if (flag) { bool flag3; if (flag2) { flag3 = true; } else { WaitAndEnterCriticalSection(&entryPtr->SpinLock, out flag3); } if (flag3) { try { SafeMarshalCopy(instanceName, (IntPtr) num); entryPtr->InstanceNameHashCode = instanceNameHashCode; *((IntPtr*) returnInstancePointerReference) = entryPtr; this.ClearCounterValues(returnInstancePointerReference[0]); if (this.categoryData.UseUniqueSharedMemory) { CounterEntry* entryPtr3 = (CounterEntry*) this.ResolveOffset(entryPtr->FirstCounterOffset, CounterEntrySize); ProcessLifetimeEntry* lifetimeEntry = (ProcessLifetimeEntry*) this.ResolveOffset(entryPtr3->LifetimeOffset, ProcessLifetimeEntrySize); PopulateLifetimeEntry(lifetimeEntry, lifetime); } *(((IntPtr*) returnInstancePointerReference)).RefCount = 1; return true; } finally { if (!flag2) { ExitCriticalSection(&entryPtr->SpinLock); } } } } } entryPtr2 = entryPtr; if (entryPtr->NextInstanceOffset != 0) { entryPtr = (InstanceEntry*) this.ResolveOffset(entryPtr->NextInstanceOffset, InstanceEntrySize); goto Label_0015; } *((IntPtr*) returnInstancePointerReference) = entryPtr2; return false; }